The Samba-Bugzilla – Attachment 16933 Details for
Bug 14725
[SECURITY] Andrew's Kerberos Concerns (November 9 2021)
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Combined patchset for 4.13 v12 (CVE-2020-25717 CVE-2020-25721 CVE-2020-25718 CVE-2020-25719 CVE-2020-25722)
security-2021-11-v4.13-v12-bug14725.patches.txt (text/plain), 1.39 MB, created by
Stefan Metzmacher
on 2021-11-03 16:02:30 UTC
(
hide
)
Description:
Combined patchset for 4.13 v12 (CVE-2020-25717 CVE-2020-25721 CVE-2020-25718 CVE-2020-25719 CVE-2020-25722)
Filename:
MIME Type:
Creator:
Stefan Metzmacher
Created:
2021-11-03 16:02:30 UTC
Size:
1.39 MB
patch
obsolete
>From db08e222e4a3931446b83bb89d1c7519feeb8795 Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Tue, 8 Dec 2020 22:00:55 +1300 >Subject: [PATCH 001/262] CVE-2020-25718 ldb/attrib_handler casefold: simplify > space dropping > >As seen in CVE-2021-20277, ldb_handler_fold() has been making mistakes >when collapsing spaces down to a single space. > >This patch fixes the way it handles internal spaces (CVE-2021-20277 >was about leading spaces), and involves a rewrite of the parsing loop. > >The bug has a detailed description of the problem. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14656 > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >Autobuild-User(master): Andrew Bartlett <abartlet@samba.org> >Autobuild-Date(master): Wed Apr 7 03:16:39 UTC 2021 on sn-devel-184 > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit 24ddc1ca9cad95673bdd8023d99867707b37085f) >--- > lib/ldb/common/attrib_handlers.c | 53 +++++++++++++++----------------- > lib/ldb/tests/ldb_match_test.c | 2 ++ > 2 files changed, 27 insertions(+), 28 deletions(-) > >diff --git a/lib/ldb/common/attrib_handlers.c b/lib/ldb/common/attrib_handlers.c >index c6ef5ad477b0..f0fd4f50d8df 100644 >--- a/lib/ldb/common/attrib_handlers.c >+++ b/lib/ldb/common/attrib_handlers.c >@@ -54,8 +54,8 @@ int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx, > int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, > const struct ldb_val *in, struct ldb_val *out) > { >- char *s, *t; >- size_t l; >+ char *s, *t, *start; >+ bool in_space; > > if (!in || !out || !(in->data)) { > return -1; >@@ -67,36 +67,33 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, > return -1; > } > >- s = (char *)(out->data); >- >- /* remove trailing spaces if any */ >- l = strlen(s); >- while (l > 0 && s[l - 1] == ' ') l--; >- s[l] = '\0'; >- >- /* remove leading spaces if any */ >- if (*s == ' ') { >- for (t = s; *s == ' '; s++, l--) ; >- >- /* remove leading spaces by moving down the string */ >- memmove(t, s, l); >- >- s = t; >+ start = (char *)(out->data); >+ in_space = true; >+ t = start; >+ for (s = start; *s != '\0'; s++) { >+ if (*s == ' ') { >+ if (in_space) { >+ /* >+ * We already have one (or this is the start) >+ * and we don't want to add more >+ */ >+ continue; >+ } >+ in_space = true; >+ } else { >+ in_space = false; >+ } >+ *t = *s; >+ t++; > } > >- /* check middle spaces */ >- while ((t = strchr(s, ' ')) != NULL) { >- for (s = t; *s == ' '; s++) ; >- >- if ((s - t) > 1) { >- l = strlen(s); >- >- /* remove all spaces but one by moving down the string */ >- memmove(t + 1, s, l); >- } >+ if (in_space && t != start) { >+ /* the loop will have left a single trailing space */ >+ t--; > } >+ *t = '\0'; > >- out->length = strlen((char *)out->data); >+ out->length = t - start; > return 0; > } > >diff --git a/lib/ldb/tests/ldb_match_test.c b/lib/ldb/tests/ldb_match_test.c >index fbf4106fa786..eb5d9fcee200 100644 >--- a/lib/ldb/tests/ldb_match_test.c >+++ b/lib/ldb/tests/ldb_match_test.c >@@ -183,6 +183,8 @@ static void test_wildcard_match(void **state) > struct wildcard_test tests[] = { > TEST_ENTRY(" 1 0", "1*0*", true, true), > TEST_ENTRY(" 1 0", "1 *0", true, true), >+ TEST_ENTRY(" 1 0", "*1 0", true, true), >+ TEST_ENTRY("1 0", "*1 0", true, true), > TEST_ENTRY("The value.......end", "*end", true, true), > TEST_ENTRY("The value.......end", "*fend", false, true), > TEST_ENTRY("The value.......end", "*eel", false, true), >-- >2.25.1 > > >From 0ecd6fb254fa78d37d7aae9c70f5b58373887901 Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Wed, 3 Mar 2021 19:17:36 +1300 >Subject: [PATCH 002/262] CVE-2020-25718 ldb_match: trailing chunk must match > end of string >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >A wildcard search is divided into chunks by the asterisks. While most >chunks match the first suitable string, the last chunk matches the >last possible string (unless there is a trailing asterisk, in which >case this distinction is moot). > >We always knew this in our hearts, but we tried to do it in a funny >complicated way that stepped through the string, comparing here and >there, leading to CVE-2019-3824 and missed matches (bug 14044). > >With this patch, we just jump to the end of the string and compare it. >As well as being correct, this should also improve performance, as the >previous algorithm involved a quadratic loop of erroneous memmem()s. > >See https://tools.ietf.org/html/rfc4517 > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14044 > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Björn Jacke <bjacke@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit cc098f1cad04b2cfec4ddd6b2511cd5a600f31c6) >--- > lib/ldb/common/ldb_match.c | 80 +++++++++++++++++--------------------- > 1 file changed, 35 insertions(+), 45 deletions(-) > >diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c >index 829afa77e716..da595615bd94 100644 >--- a/lib/ldb/common/ldb_match.c >+++ b/lib/ldb/common/ldb_match.c >@@ -295,8 +295,9 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, > uint8_t *p; > > chunk = tree->u.substring.chunks[c]; >- if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch; >- >+ if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) { >+ goto mismatch; >+ } > /* > * Empty strings are returned as length 0. Ensure > * we can cope with this. >@@ -304,52 +305,41 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, > if (cnk.length == 0) { > goto mismatch; > } >- /* >- * Values might be binary blobs. Don't use string >- * search, but memory search instead. >- */ >- p = memmem((const void *)val.data,val.length, >- (const void *)cnk.data, cnk.length); >- if (p == NULL) goto mismatch; >- >- /* >- * At this point we know cnk.length <= val.length as >- * otherwise there could be no match >- */ >+ if (cnk.length > val.length) { >+ goto mismatch; >+ } > >- if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) { >- uint8_t *g; >- uint8_t *end = val.data + val.length; >- do { /* greedy */ >- >- /* >- * haystack is a valid pointer in val >- * because the memmem() can only >- * succeed if the needle (cnk.length) >- * is <= haystacklen >- * >- * p will be a pointer at least >- * cnk.length from the end of haystack >- */ >- uint8_t *haystack >- = p + cnk.length; >- size_t haystacklen >- = end - (haystack); >- >- g = memmem(haystack, >- haystacklen, >- (const uint8_t *)cnk.data, >- cnk.length); >- if (g) { >- p = g; >- } >- } while(g); >+ if ( (tree->u.substring.chunks[c + 1]) == NULL && >+ (! tree->u.substring.end_with_wildcard) ) { >+ /* >+ * The last bit, after all the asterisks, must match >+ * exactly the last bit of the string. >+ */ >+ int cmp; >+ p = val.data + val.length - cnk.length; >+ cmp = memcmp(p, >+ cnk.data, >+ cnk.length); >+ if (cmp != 0) { >+ goto mismatch; >+ } >+ } else { >+ /* >+ * Values might be binary blobs. Don't use string >+ * search, but memory search instead. >+ */ >+ p = memmem((const void *)val.data, val.length, >+ (const void *)cnk.data, cnk.length); >+ if (p == NULL) { >+ goto mismatch; >+ } >+ /* move val to the end of the match */ >+ p += cnk.length; >+ val.length -= (p - val.data); >+ val.data = p; > } >- val.length = val.length - (p - (uint8_t *)(val.data)) - cnk.length; >- val.data = (uint8_t *)(p + cnk.length); > c++; >- talloc_free(cnk.data); >- cnk.data = NULL; >+ TALLOC_FREE(cnk.data); > } > > /* last chunk may not have reached end of string */ >-- >2.25.1 > > >From 402a6e13df80f60ebf226ec5fe5b733654e1c858 Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Sat, 6 Mar 2021 16:05:15 +1300 >Subject: [PATCH 003/262] CVE-2020-25718 ldb: fix ldb_comparison_fold > off-by-one overrun > >We run one character over in comparing all the bytes in two ldb_vals. > >In almost all circumstances both ldb_vals would have an allocated '\0' >in the overrun position, but it is best not to rely on that. > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit 2b2f4f519454beb6f2a46705675a62274019fc09) >--- > lib/ldb/common/attrib_handlers.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > >diff --git a/lib/ldb/common/attrib_handlers.c b/lib/ldb/common/attrib_handlers.c >index f0fd4f50d8df..6a885065f773 100644 >--- a/lib/ldb/common/attrib_handlers.c >+++ b/lib/ldb/common/attrib_handlers.c >@@ -334,8 +334,8 @@ int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx, > if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2)) > break; > if (*s1 == ' ') { >- while (n1 && s1[0] == s1[1]) { s1++; n1--; } >- while (n2 && s2[0] == s2[1]) { s2++; n2--; } >+ while (n1 > 1 && s1[0] == s1[1]) { s1++; n1--; } >+ while (n2 > 1 && s2[0] == s2[1]) { s2++; n2--; } > } > s1++; s2++; > n1--; n2--; >-- >2.25.1 > > >From 33fa75b7337ddf2f715e48957ada9de466354664 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 19 Jan 2021 16:53:55 +0100 >Subject: [PATCH 004/262] CVE-2020-25718 pyldb: catch potential overflow error > in py_timestring >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >Pair-Programmed-With: Björn Baumbach <bb@sernet.de> > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Signed-off-by: Björn Baumbach <bb@sernet.de> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit 71e8b24b8a031de26b21539e36a60f459257d2fd) >--- > lib/ldb/common/ldb_msg.c | 1 + > lib/ldb/pyldb.c | 7 +++++++ > lib/ldb/tests/python/api.py | 19 +++++++++++++++++++ > 3 files changed, 27 insertions(+) > >diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c >index 7131f013f71b..57dfc5a04c2b 100644 >--- a/lib/ldb/common/ldb_msg.c >+++ b/lib/ldb/common/ldb_msg.c >@@ -1272,6 +1272,7 @@ char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t) > > if (r != 17) { > talloc_free(ts); >+ errno = EOVERFLOW; > return NULL; > } > >diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c >index d093daedf5c7..257351b2bc45 100644 >--- a/lib/ldb/pyldb.c >+++ b/lib/ldb/pyldb.c >@@ -4227,6 +4227,13 @@ static PyObject *py_timestring(PyObject *module, PyObject *args) > if (!PyArg_ParseTuple(args, "l", &t_val)) > return NULL; > tresult = ldb_timestring(NULL, (time_t) t_val); >+ if (tresult == NULL) { >+ /* >+ * Most likely EOVERFLOW from gmtime() >+ */ >+ PyErr_SetFromErrno(PyExc_OSError); >+ return NULL; >+ } > ret = PyUnicode_FromString(tresult); > talloc_free(tresult); > return ret; >diff --git a/lib/ldb/tests/python/api.py b/lib/ldb/tests/python/api.py >index 675b5859af8f..8d154aac6adf 100755 >--- a/lib/ldb/tests/python/api.py >+++ b/lib/ldb/tests/python/api.py >@@ -5,10 +5,12 @@ > import os > from unittest import TestCase > import sys >+sys.path.insert(0, "bin/python") > import gc > import time > import ldb > import shutil >+import errno > > PY3 = sys.version_info > (3, 0) > >@@ -42,10 +44,27 @@ class NoContextTests(TestCase): > self.assertEqual("19700101000000.0Z", ldb.timestring(0)) > self.assertEqual("20071119191012.0Z", ldb.timestring(1195499412)) > >+ self.assertEqual("00000101000000.0Z", ldb.timestring(-62167219200)) >+ self.assertEqual("99991231235959.0Z", ldb.timestring(253402300799)) >+ >+ # should result with OSError EOVERFLOW from gmtime() >+ with self.assertRaises(OSError) as err: >+ ldb.timestring(-62167219201) >+ self.assertEqual(err.exception.errno, errno.EOVERFLOW) >+ with self.assertRaises(OSError) as err: >+ ldb.timestring(253402300800) >+ self.assertEqual(err.exception.errno, errno.EOVERFLOW) >+ with self.assertRaises(OSError) as err: >+ ldb.timestring(0x7fffffffffffffff) >+ self.assertEqual(err.exception.errno, errno.EOVERFLOW) >+ > def test_string_to_time(self): > self.assertEqual(0, ldb.string_to_time("19700101000000.0Z")) > self.assertEqual(1195499412, ldb.string_to_time("20071119191012.0Z")) > >+ self.assertEqual(-62167219200, ldb.string_to_time("00000101000000.0Z")) >+ self.assertEqual(253402300799, ldb.string_to_time("99991231235959.0Z")) >+ > def test_binary_encode(self): > encoded = ldb.binary_encode(b'test\\x') > decoded = ldb.binary_decode(encoded) >-- >2.25.1 > > >From e25ac37496e574b237f2f6dc98f384439b2674a5 Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Wed, 3 Mar 2021 19:54:37 +1300 >Subject: [PATCH 005/262] CVE-2020-25718 ldb_match: remove redundant check >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >We already ensure the no-trailing-asterisk case ends at the end of the >string. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14044 > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Björn Jacke <bjacke@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit fa93339978040eab52b2722c1716028b48d8d084) >--- > lib/ldb/common/ldb_match.c | 2 -- > 1 file changed, 2 deletions(-) > >diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c >index da595615bd94..2f4d41f34416 100644 >--- a/lib/ldb/common/ldb_match.c >+++ b/lib/ldb/common/ldb_match.c >@@ -342,8 +342,6 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, > TALLOC_FREE(cnk.data); > } > >- /* last chunk may not have reached end of string */ >- if ( (! tree->u.substring.end_with_wildcard) && (val.length != 0) ) goto mismatch; > talloc_free(save_p); > *matched = true; > return LDB_SUCCESS; >-- >2.25.1 > > >From edeb9812aacc6d7fda93586c66641bfff079183e Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Fri, 28 May 2021 14:15:43 +1200 >Subject: [PATCH 006/262] CVE-2020-25718 pyldb: Fix Message.items() for a > message containing elements > >Previously, message elements were being freed before the call to >Py_BuildValue(), resulting in an exception being raised. Additionally, >only the first element of the returned list was ever assigned to. > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit 3e4ec0a90a222c1cff4a91912afc703ca4cbbb0e) >--- > lib/ldb/pyldb.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > >diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c >index 257351b2bc45..df7c5c54eaaa 100644 >--- a/lib/ldb/pyldb.c >+++ b/lib/ldb/pyldb.c >@@ -3535,13 +3535,13 @@ static PyObject *py_ldb_msg_items(PyLdbMessageObject *self, > PyObject *value = NULL; > PyObject *py_el = PyLdbMessageElement_FromMessageElement(&msg->elements[i], msg->elements); > int res = 0; >- Py_CLEAR(py_el); > value = Py_BuildValue("(sO)", msg->elements[i].name, py_el); >+ Py_CLEAR(py_el); > if (value == NULL ) { > Py_CLEAR(l); > return NULL; > } >- res = PyList_SetItem(l, 0, value); >+ res = PyList_SetItem(l, j, value); > if (res == -1) { > Py_CLEAR(l); > return NULL; >-- >2.25.1 > > >From 31f00576003516483c014c6275691cfee3d24abb Mon Sep 17 00:00:00 2001 >From: Andreas Schneider <asn@samba.org> >Date: Mon, 1 Feb 2021 14:21:21 +0100 >Subject: [PATCH 007/262] CVE-2020-25718 lib:ldb: Add missing break in switch > statement > >error: unannotated fall-through between switch labels [-Werror,-Wimplicit-fallthrough] > >Signed-off-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit 1ffacac547a8ce29c6696dda73991a8db7e34dfd) >--- > lib/ldb/ldb_map/ldb_map_inbound.c | 1 + > 1 file changed, 1 insertion(+) > >diff --git a/lib/ldb/ldb_map/ldb_map_inbound.c b/lib/ldb/ldb_map/ldb_map_inbound.c >index 861c4c1622d5..324295737da1 100644 >--- a/lib/ldb/ldb_map/ldb_map_inbound.c >+++ b/lib/ldb/ldb_map/ldb_map_inbound.c >@@ -262,6 +262,7 @@ static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *a > LDB_ERR_OPERATIONS_ERROR); > } > >+ break; > default: > /* ignore referrals */ > break; >-- >2.25.1 > > >From 999ee2e027948c0ee1ba7d62dc8e78517e9f11a8 Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Sat, 19 Dec 2020 11:43:56 +1300 >Subject: [PATCH 008/262] CVE-2020-25718 ldb.h: remove undefined async_ctx > function signatures > >These functions do not exist. > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Jeremy Allison <jra@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit 1a05b58edaf96e7da707f9ad0a237551dbe13eb5) >--- > lib/ldb/include/ldb.h | 12 ------------ > 1 file changed, 12 deletions(-) > >diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h >index 7f53e6420e1c..f5f02c9a344c 100644 >--- a/lib/ldb/include/ldb.h >+++ b/lib/ldb/include/ldb.h >@@ -1093,18 +1093,6 @@ int ldb_global_init(void); > */ > struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx); > >-typedef void (*ldb_async_timeout_fn) (void *); >-typedef bool (*ldb_async_callback_fn) (void *); >-typedef int (*ldb_async_ctx_add_op_fn)(void *, time_t, void *, ldb_async_timeout_fn, ldb_async_callback_fn); >-typedef int (*ldb_async_ctx_wait_op_fn)(void *); >- >-void ldb_async_ctx_set_private_data(struct ldb_context *ldb, >- void *private_data); >-void ldb_async_ctx_set_add_op(struct ldb_context *ldb, >- ldb_async_ctx_add_op_fn add_op); >-void ldb_async_ctx_set_wait_op(struct ldb_context *ldb, >- ldb_async_ctx_wait_op_fn wait_op); >- > /** > Connect to a database. > >-- >2.25.1 > > >From 4e44d6811fd7a678f159e09735ab7edebbd09020 Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Sat, 6 Mar 2021 09:57:44 +1300 >Subject: [PATCH 009/262] CVE-2020-25718 ldb: correct comments in > attrib_handers val_to_int64 > >c.f. the identical static function in lib/ldb-samba/ldif_handlers.c > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Jeremy Allison <jra@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit 46e6f6ef8436df7e083f34556c25f66f65ea1ce5) >--- > lib/ldb/common/attrib_handlers.c | 4 +--- > 1 file changed, 1 insertion(+), 3 deletions(-) > >diff --git a/lib/ldb/common/attrib_handlers.c b/lib/ldb/common/attrib_handlers.c >index 6a885065f773..febf2f414ca0 100644 >--- a/lib/ldb/common/attrib_handlers.c >+++ b/lib/ldb/common/attrib_handlers.c >@@ -97,7 +97,7 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, > return 0; > } > >-/* length limited conversion of a ldb_val to a int32_t */ >+/* length limited conversion of a ldb_val to an int64_t */ > static int val_to_int64(const struct ldb_val *in, int64_t *v) > { > char *end; >@@ -110,8 +110,6 @@ static int val_to_int64(const struct ldb_val *in, int64_t *v) > strncpy(buf, (char *)in->data, in->length); > buf[in->length] = 0; > >- /* We've to use "strtoll" here to have the intended overflows. >- * Otherwise we may get "LONG_MAX" and the conversion is wrong. */ > *v = (int64_t) strtoll(buf, &end, 0); > if (*end != 0) { > return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; >-- >2.25.1 > > >From 3c649f59300e72bcde3c7a7fc8662b2ba8c726f6 Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Fri, 29 Jan 2021 13:49:02 +1300 >Subject: [PATCH 010/262] CVE-2020-25718 ldb: improve comments for > ldb_module_connect_backend() > >There is no flags argument. >There are more URI forms. > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Jeremy Allison <jra@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit 48068a58df0313cd904f27e2c918ee10275ae373) >--- > lib/ldb/common/ldb_modules.c | 14 +++++++++----- > 1 file changed, 9 insertions(+), 5 deletions(-) > >diff --git a/lib/ldb/common/ldb_modules.c b/lib/ldb/common/ldb_modules.c >index cc067abdfe04..4366f05e066c 100644 >--- a/lib/ldb/common/ldb_modules.c >+++ b/lib/ldb/common/ldb_modules.c >@@ -173,11 +173,15 @@ int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn, bool > > /* > Return the ldb module form of a database. >- The URL can either be one of the following forms >- ldb://path >- ldapi://path >- >- flags is made up of LDB_FLG_* >+ The URL looks something like this: >+ tdb://PATH >+ ldb://PATH >+ mdb://PATH >+ ldapi://PATH >+ PATH (unadorned PATH defaults to tdb://) >+ >+ for a complete list of backends (including possibly unmaintained ones) grep >+ for calls to ldb_register_backend(). > > the options are passed uninterpreted to the backend, and are > backend specific. >-- >2.25.1 > > >From 4d89cadb0958702976d8d562ccf325ce5ce986e4 Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?Bj=C3=B6rn=20Baumbach?= <bb@sernet.de> >Date: Mon, 18 Jan 2021 16:48:21 +0100 >Subject: [PATCH 011/262] CVE-2020-25718 pyldb: fix a typo >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >Signed-off-by: Björn Baumbach <bb@sernet.de> >Reviewed-by: Rowland penny <rpenny@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit 6fcde09f093db5d26c582a3c28531265f06b9fde) >--- > lib/ldb/pyldb.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c >index df7c5c54eaaa..3f4b0c7a45cf 100644 >--- a/lib/ldb/pyldb.c >+++ b/lib/ldb/pyldb.c >@@ -4314,7 +4314,7 @@ static PyMethodDef py_ldb_global_methods[] = { > "S.string_to_time(string) -> int\n\n" > "Parse a LDAP time string into a UNIX timestamp." }, > { "valid_attr_name", py_valid_attr_name, METH_VARARGS, >- "S.valid_attr_name(name) -> bool\n\nn" >+ "S.valid_attr_name(name) -> bool\n\n" > "Check whether the supplied name is a valid attribute name." }, > { "binary_encode", py_binary_encode, METH_VARARGS, > "S.binary_encode(string) -> string\n\n" >-- >2.25.1 > > >From edd489cb140aff17a7d735aa4b214e4b405f11dc Mon Sep 17 00:00:00 2001 >From: Andreas Schneider <asn@samba.org> >Date: Thu, 17 Dec 2020 11:56:08 +0100 >Subject: [PATCH 012/262] CVE-2020-25718 lib:ldb: Use C99 initializers for > builtin_popt_options[] > >Signed-off-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit a593065c7f22e17434f33d0132cc6a7073acf414) >--- > lib/ldb/tools/cmdline.c | 250 ++++++++++++++++++++++++++++++++++++---- > 1 file changed, 225 insertions(+), 25 deletions(-) > >diff --git a/lib/ldb/tools/cmdline.c b/lib/ldb/tools/cmdline.c >index c32470864d4f..affce47ac84d 100644 >--- a/lib/ldb/tools/cmdline.c >+++ b/lib/ldb/tools/cmdline.c >@@ -34,31 +34,231 @@ enum ldb_cmdline_options { CMDLINE_RELAX=1 }; > > static struct poptOption builtin_popt_options[] = { > POPT_AUTOHELP >- { "url", 'H', POPT_ARG_STRING, &options.url, 0, "database URL", "URL" }, >- { "basedn", 'b', POPT_ARG_STRING, &options.basedn, 0, "base DN", "DN" }, >- { "editor", 'e', POPT_ARG_STRING, &options.editor, 0, "external editor", "PROGRAM" }, >- { "scope", 's', POPT_ARG_STRING, NULL, 's', "search scope", "SCOPE" }, >- { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "increase verbosity", NULL }, >- { "trace", 0, POPT_ARG_NONE, &options.tracing, 0, "enable tracing", NULL }, >- { "interactive", 'i', POPT_ARG_NONE, &options.interactive, 0, "input from stdin", NULL }, >- { "recursive", 'r', POPT_ARG_NONE, &options.recursive, 0, "recursive delete", NULL }, >- { "modules-path", 0, POPT_ARG_STRING, &options.modules_path, 0, "modules path", "PATH" }, >- { "num-searches", 0, POPT_ARG_INT, &options.num_searches, 0, "number of test searches", NULL }, >- { "num-records", 0, POPT_ARG_INT, &options.num_records, 0, "number of test records", NULL }, >- { "all", 'a', POPT_ARG_NONE, &options.all_records, 0, "(|(objectClass=*)(distinguishedName=*))", NULL }, >- { "nosync", 0, POPT_ARG_NONE, &options.nosync, 0, "non-synchronous transactions", NULL }, >- { "sorted", 'S', POPT_ARG_NONE, &options.sorted, 0, "sort attributes", NULL }, >- { NULL, 'o', POPT_ARG_STRING, NULL, 'o', "ldb_connect option", "OPTION" }, >- { "controls", 0, POPT_ARG_STRING, NULL, 'c', "controls", NULL }, >- { "show-binary", 0, POPT_ARG_NONE, &options.show_binary, 0, "display binary LDIF", NULL }, >- { "paged", 0, POPT_ARG_NONE, NULL, 'P', "use a paged search", NULL }, >- { "show-deleted", 0, POPT_ARG_NONE, NULL, 'D', "show deleted objects", NULL }, >- { "show-recycled", 0, POPT_ARG_NONE, NULL, 'R', "show recycled objects", NULL }, >- { "show-deactivated-link", 0, POPT_ARG_NONE, NULL, 'd', "show deactivated links", NULL }, >- { "reveal", 0, POPT_ARG_NONE, NULL, 'r', "reveal ldb internals", NULL }, >- { "relax", 0, POPT_ARG_NONE, NULL, CMDLINE_RELAX, "pass relax control", NULL }, >- { "cross-ncs", 0, POPT_ARG_NONE, NULL, 'N', "search across NC boundaries", NULL }, >- { "extended-dn", 0, POPT_ARG_NONE, NULL, 'E', "show extended DNs", NULL }, >+ { >+ .longName = "url", >+ .shortName = 'H', >+ .argInfo = POPT_ARG_STRING, >+ .arg = &options.url, >+ .val = 0, >+ .descrip = "database URL", >+ .argDescrip = "URL" >+ }, >+ { >+ .longName = "basedn", >+ .shortName = 'b', >+ .argInfo = POPT_ARG_STRING, >+ .arg = &options.basedn, >+ .val = 0, >+ .descrip = "base DN", >+ .argDescrip = "DN" >+ }, >+ { >+ .longName = "editor", >+ .shortName = 'e', >+ .argInfo = POPT_ARG_STRING, >+ .arg = &options.editor, >+ .val = 0, >+ .descrip = "external editor", >+ .argDescrip = "PROGRAM" >+ }, >+ { >+ .longName = "scope", >+ .shortName = 's', >+ .argInfo = POPT_ARG_STRING, >+ .arg = NULL, >+ .val = 's', >+ .descrip = "search scope", >+ .argDescrip = "SCOPE" >+ }, >+ { >+ .longName = "verbose", >+ .shortName = 'v', >+ .argInfo = POPT_ARG_NONE, >+ .arg = NULL, >+ .val = 'v', >+ .descrip = "increase verbosity", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "trace", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = &options.tracing, >+ .val = 0, >+ .descrip = "enable tracing", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "interactive", >+ .shortName = 'i', >+ .argInfo = POPT_ARG_NONE, >+ .arg = &options.interactive, >+ .val = 0, >+ .descrip = "input from stdin", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "recursive", >+ .shortName = 'r', >+ .argInfo = POPT_ARG_NONE, >+ .arg = &options.recursive, >+ .val = 0, >+ .descrip = "recursive delete", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "modules-path", >+ .shortName = 0, >+ .argInfo = POPT_ARG_STRING, >+ .arg = &options.modules_path, >+ .val = 0, >+ .descrip = "modules path", >+ .argDescrip = "PATH" >+ }, >+ { >+ .longName = "num-searches", >+ .shortName = 0, >+ .argInfo = POPT_ARG_INT, >+ .arg = &options.num_searches, >+ .val = 0, >+ .descrip = "number of test searches", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "num-records", >+ .shortName = 0, >+ .argInfo = POPT_ARG_INT, >+ .arg = &options.num_records, >+ .val = 0, >+ .descrip = "number of test records", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "all", >+ .shortName = 'a', >+ .argInfo = POPT_ARG_NONE, >+ .arg = &options.all_records, >+ .val = 0, >+ .descrip = "(|(objectClass=*)(distinguishedName=*))", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "nosync", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = &options.nosync, >+ .val = 0, >+ .descrip = "non-synchronous transactions", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "sorted", >+ .shortName = 'S', >+ .argInfo = POPT_ARG_NONE, >+ .arg = &options.sorted, >+ .val = 0, >+ .descrip = "sort attributes", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = NULL, >+ .shortName = 'o', >+ .argInfo = POPT_ARG_STRING, >+ .arg = NULL, >+ .val = 'o', >+ .descrip = "ldb_connect option", >+ .argDescrip = "OPTION" >+ }, >+ { >+ .longName = "controls", >+ .shortName = 0, >+ .argInfo = POPT_ARG_STRING, >+ .arg = NULL, >+ .val = 'c', >+ .descrip = "controls", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "show-binary", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = &options.show_binary, >+ .val = 0, >+ .descrip = "display binary LDIF", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "paged", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = NULL, >+ .val = 'P', >+ .descrip = "use a paged search", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "show-deleted", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = NULL, >+ .val = 'D', >+ .descrip = "show deleted objects", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "show-recycled", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = NULL, >+ .val = 'R', >+ .descrip = "show recycled objects", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "show-deactivated-link", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = NULL, >+ .val = 'd', >+ .descrip = "show deactivated links", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "reveal", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = NULL, >+ .val = 'r', >+ .descrip = "reveal ldb internals", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "relax", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = NULL, >+ .val = CMDLINE_RELAX, >+ .descrip = "pass relax control", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "cross-ncs", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = NULL, >+ .val = 'N', >+ .descrip = "search across NC boundaries", >+ .argDescrip = NULL >+ }, >+ { >+ .longName = "extended-dn", >+ .shortName = 0, >+ .argInfo = POPT_ARG_NONE, >+ .arg = NULL, >+ .val = 'E', >+ .descrip = "show extended DNs", >+ .argDescrip = NULL >+ }, > {0} > }; > >-- >2.25.1 > > >From 1d22b24a50f970dffc014e50119b021d96895de0 Mon Sep 17 00:00:00 2001 >From: Andreas Schneider <asn@samba.org> >Date: Thu, 17 Dec 2020 19:16:13 +0100 >Subject: [PATCH 013/262] CVE-2020-25718 lib:ldb-samba: Improve > calculate_popt_array_length() > >Note that memcmp() doesn't work well with padding bytes. So avoid it! > >(gdb) ptype/o struct poptOption >/* offset | size */ type = struct poptOption { >/* 0 | 8 */ const char *longName; >/* 8 | 1 */ char shortName; >/* XXX 3-byte hole */ >/* 12 | 4 */ unsigned int argInfo; >/* 16 | 8 */ void *arg; >/* 24 | 4 */ int val; >/* XXX 4-byte hole */ >/* 32 | 8 */ const char *descrip; >/* 40 | 8 */ const char *argDescrip; > > /* total size (bytes): 48 */ > >Signed-off-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit c2c7c1f50a8acb3169e19ba4329aa78839b66def) >--- > lib/ldb-samba/samba_extensions.c | 27 ++++++++++++++++++++++----- > lib/ldb/tools/cmdline.c | 2 +- > 2 files changed, 23 insertions(+), 6 deletions(-) > >diff --git a/lib/ldb-samba/samba_extensions.c b/lib/ldb-samba/samba_extensions.c >index 65a4079ec97e..60aa1a332b5a 100644 >--- a/lib/ldb-samba/samba_extensions.c >+++ b/lib/ldb-samba/samba_extensions.c >@@ -34,15 +34,32 @@ > #include "popt.h" > > >+static bool is_popt_table_end(const struct poptOption *o) >+{ >+ if (o->longName == NULL && >+ o->shortName =='\0' && >+ o->arg == NULL) { >+ return true; >+ } >+ >+ return false; >+} > > /* > work out the length of a popt array > */ >-static unsigned calculate_popt_array_length(struct poptOption *opts) >+static size_t calculate_popt_array_length(struct poptOption *opts) > { >- unsigned i; >- struct poptOption zero_opt = { 0 }; >- for (i=0; memcmp(&zero_opt, &opts[i], sizeof(zero_opt)) != 0; i++) ; >+ size_t i = 0; >+ >+ for (i = 0; i < UINT32_MAX; i++) { >+ struct poptOption *o = &(opts[i]); >+ >+ if (is_popt_table_end(o)) { >+ break; >+ } >+ } >+ > return i; > } > >@@ -61,7 +78,7 @@ static int extensions_hook(struct ldb_context *ldb, enum ldb_module_hook_type t) > { > switch (t) { > case LDB_MODULE_HOOK_CMDLINE_OPTIONS: { >- unsigned len1, len2; >+ size_t len1, len2; > struct poptOption **popt_options = ldb_module_popt_options(ldb); > struct poptOption *new_array; > >diff --git a/lib/ldb/tools/cmdline.c b/lib/ldb/tools/cmdline.c >index affce47ac84d..ff25fe05ec7c 100644 >--- a/lib/ldb/tools/cmdline.c >+++ b/lib/ldb/tools/cmdline.c >@@ -259,7 +259,7 @@ static struct poptOption builtin_popt_options[] = { > .descrip = "show extended DNs", > .argDescrip = NULL > }, >- {0} >+ POPT_TABLEEND > }; > > void ldb_cmdline_help(struct ldb_context *ldb, const char *cmdname, FILE *f) >-- >2.25.1 > > >From 0f75e198a63995ef27fae87039e6134a2e6ae6d2 Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Fri, 24 Jul 2020 12:41:29 +1200 >Subject: [PATCH 014/262] CVE-2020-25718 ldb_controls: control_to_string avoids > crash > >Otherwise a malformed control with unexpected NULL data will segfault >ldb_control_to_string(), though this is not very likely to affect >anyone in practice as converting controls to strings is rarely >necessary. If it happens at all in Samba it is in Python code. > >Found by Honggfuzz using fuzz_ldb_parse_control. > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Andreas Schneider <asn@samba.org> > >Autobuild-User(master): Douglas Bagnall <dbagnall@samba.org> >Autobuild-Date(master): Wed Jul 29 04:43:23 UTC 2020 on sn-devel-184 > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit 2aace18f170644da9c293342a6df5e5b2ae8da25) >--- > lib/ldb/common/ldb_controls.c | 22 ++++++++++++++++++++++ > 1 file changed, 22 insertions(+) > >diff --git a/lib/ldb/common/ldb_controls.c b/lib/ldb/common/ldb_controls.c >index d67c0afd8452..266aa90b2245 100644 >--- a/lib/ldb/common/ldb_controls.c >+++ b/lib/ldb/common/ldb_controls.c >@@ -286,6 +286,9 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr > if (strcmp(control->oid, LDB_CONTROL_PAGED_RESULTS_OID) == 0) { > struct ldb_paged_control *rep_control = talloc_get_type(control->data, struct ldb_paged_control); > char *cookie; >+ if (rep_control == NULL) { >+ return NULL; >+ } > > cookie = ldb_base64_encode(mem_ctx, rep_control->cookie, rep_control->cookie_len); > if (cookie == NULL) { >@@ -312,6 +315,10 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr > > char *cookie; > >+ if (rep_control == NULL) { >+ return NULL; >+ } >+ > cookie = ldb_base64_encode(mem_ctx, > (char *)rep_control->contextId, > rep_control->ctxid_len); >@@ -334,6 +341,9 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr > struct ldb_sort_resp_control *rep_control = talloc_get_type(control->data, > struct ldb_sort_resp_control); > >+ if (rep_control == NULL) { >+ return NULL; >+ } > res = talloc_asprintf(mem_ctx, "%s:%d:%d:%s", > LDB_CONTROL_SORT_RESP_NAME, > control->critical, >@@ -347,6 +357,9 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr > struct ldb_asq_control *rep_control = talloc_get_type(control->data, > struct ldb_asq_control); > >+ if (rep_control == NULL) { >+ return NULL; >+ } > res = talloc_asprintf(mem_ctx, "%s:%d:%d", > LDB_CONTROL_SORT_RESP_NAME, > control->critical, >@@ -360,6 +373,9 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr > struct ldb_dirsync_control *rep_control = talloc_get_type(control->data, > struct ldb_dirsync_control); > >+ if (rep_control == NULL) { >+ return NULL; >+ } > cookie = ldb_base64_encode(mem_ctx, rep_control->cookie, > rep_control->cookie_len); > if (cookie == NULL) { >@@ -380,6 +396,9 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr > struct ldb_dirsync_control *rep_control = talloc_get_type(control->data, > struct ldb_dirsync_control); > >+ if (rep_control == NULL) { >+ return NULL; >+ } > cookie = ldb_base64_encode(mem_ctx, rep_control->cookie, > rep_control->cookie_len); > if (cookie == NULL) { >@@ -399,6 +418,9 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr > if (strcmp(control->oid, LDB_CONTROL_VERIFY_NAME_OID) == 0) { > struct ldb_verify_name_control *rep_control = talloc_get_type(control->data, struct ldb_verify_name_control); > >+ if (rep_control == NULL) { >+ return NULL; >+ } > if (rep_control->gc != NULL) { > res = talloc_asprintf(mem_ctx, "%s:%d:%d:%s", > LDB_CONTROL_VERIFY_NAME_NAME, >-- >2.25.1 > > >From 4330d2e3a14d977e9ec286d888b0c03cb3db8f67 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Mon, 4 Jan 2021 13:12:30 +0100 >Subject: [PATCH 015/262] CVE-2020-25718 lib: Add "hex_byte()" to replace.h > >This is required in quite a few places, and replace.h has things like >ZERO_STRUCT already, so this is not completely outplaced. > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit c8d9ce3f7c8c486ab21e320a0adcb71311dcb453) >--- > lib/replace/replace.h | 16 ++++++++++++++++ > 1 file changed, 16 insertions(+) > >diff --git a/lib/replace/replace.h b/lib/replace/replace.h >index 6c78311f2d32..aaca9e67d3bd 100644 >--- a/lib/replace/replace.h >+++ b/lib/replace/replace.h >@@ -977,6 +977,22 @@ bool nss_wrapper_hosts_enabled(void); > bool socket_wrapper_enabled(void); > bool uid_wrapper_enabled(void); > >+static inline bool _hexcharval(char c, uint8_t *val) >+{ >+ if ((c >= '0') && (c <= '9')) { *val = c - '0'; return true; } >+ if ((c >= 'a') && (c <= 'f')) { *val = c - 'a' + 10; return true; } >+ if ((c >= 'A') && (c <= 'F')) { *val = c - 'A' + 10; return true; } >+ return false; >+} >+ >+static inline bool hex_byte(const char *in, uint8_t *out) >+{ >+ uint8_t hi=0, lo=0; >+ bool ok = _hexcharval(in[0], &hi) && _hexcharval(in[1], &lo); >+ *out = (hi<<4)+lo; >+ return ok; >+} >+ > /* Needed for Solaris atomic_add_XX functions. */ > #if defined(HAVE_SYS_ATOMIC_H) > #include <sys/atomic.h> >-- >2.25.1 > > >From 416fc5bf9d3ea02b4bb75fe9f7906231e6789af7 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Mon, 4 Jan 2021 13:55:01 +0100 >Subject: [PATCH 016/262] CVE-2020-25718 ldb: Use hex_byte() in > ldb_binary_decode() > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit b6a57c49c00a778f954aaf10db6ebe6dca8f5ae2) >--- > lib/ldb/common/ldb_parse.c | 27 ++++----------------------- > 1 file changed, 4 insertions(+), 23 deletions(-) > >diff --git a/lib/ldb/common/ldb_parse.c b/lib/ldb/common/ldb_parse.c >index 7e15206b1687..f0045ad2093b 100644 >--- a/lib/ldb/common/ldb_parse.c >+++ b/lib/ldb/common/ldb_parse.c >@@ -53,26 +53,6 @@ > */ > #define LDB_MAX_PARSE_TREE_DEPTH 128 > >-static int ldb_parse_hex2char(const char *x) >-{ >- if (isxdigit(x[0]) && isxdigit(x[1])) { >- const char h1 = x[0], h2 = x[1]; >- int c = 0; >- >- if (h1 >= 'a') c = h1 - (int)'a' + 10; >- else if (h1 >= 'A') c = h1 - (int)'A' + 10; >- else if (h1 >= '0') c = h1 - (int)'0'; >- c = c << 4; >- if (h2 >= 'a') c += h2 - (int)'a' + 10; >- else if (h2 >= 'A') c += h2 - (int)'A' + 10; >- else if (h2 >= '0') c += h2 - (int)'0'; >- >- return c; >- } >- >- return -1; >-} >- > /* > a filter is defined by: > <filter> ::= '(' <filtercomp> ')' >@@ -101,10 +81,11 @@ struct ldb_val ldb_binary_decode(TALLOC_CTX *mem_ctx, const char *str) > > for (i=j=0;i<slen;i++) { > if (str[i] == '\\') { >- int c; >+ uint8_t c; >+ bool ok; > >- c = ldb_parse_hex2char(&str[i+1]); >- if (c == -1) { >+ ok = hex_byte(&str[i+1], &c); >+ if (!ok) { > talloc_free(ret.data); > memset(&ret, 0, sizeof(ret)); > return ret; >-- >2.25.1 > > >From 5c2e907a1f122903a21588239b618eaf465e7b5f Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?Bj=C3=B6rn=20Jacke?= <bj@sernet.de> >Date: Mon, 19 Oct 2020 02:39:46 +0200 >Subject: [PATCH 017/262] CVE-2020-25718 ldb_kv_index: fix empty initializer > compile warning > >Signed-off-by: Bjoern Jacke <bjacke@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >(cherry picked from commit c862ad64aea31d1d5ec66385bb50d9b97e609071) >--- > lib/ldb/ldb_key_value/ldb_kv_index.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c >index 9be7c5adcbee..1cc042aa84fb 100644 >--- a/lib/ldb/ldb_key_value/ldb_kv_index.c >+++ b/lib/ldb/ldb_key_value/ldb_kv_index.c >@@ -2267,7 +2267,7 @@ static int ldb_kv_index_filter(struct ldb_kv_private *ldb_kv, > struct ldb_message *filtered_msg; > unsigned int i; > unsigned int num_keys = 0; >- uint8_t previous_guid_key[LDB_KV_GUID_KEY_SIZE] = {}; >+ uint8_t previous_guid_key[LDB_KV_GUID_KEY_SIZE] = {0}; > struct ldb_val *keys = NULL; > > /* >-- >2.25.1 > > >From 235f579d4db4722cbd9ebb93159397b44495c671 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 2 Nov 2021 15:19:31 +0100 >Subject: [PATCH 018/262] CVE-2020-25718 ldb: version 2.2.3 > >Backport all C code changes from ldb-2.4.1 >to be available for Samba 4.13.x > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >--- > lib/ldb/ABI/ldb-2.2.3.sigs | 283 ++++++++++++++++++++++++++++++ > lib/ldb/ABI/pyldb-util-2.2.3.sigs | 3 + > lib/ldb/wscript | 3 +- > 3 files changed, 288 insertions(+), 1 deletion(-) > create mode 100644 lib/ldb/ABI/ldb-2.2.3.sigs > create mode 100644 lib/ldb/ABI/pyldb-util-2.2.3.sigs > >diff --git a/lib/ldb/ABI/ldb-2.2.3.sigs b/lib/ldb/ABI/ldb-2.2.3.sigs >new file mode 100644 >index 000000000000..5049dc64ce1a >--- /dev/null >+++ b/lib/ldb/ABI/ldb-2.2.3.sigs >@@ -0,0 +1,283 @@ >+ldb_add: int (struct ldb_context *, const struct ldb_message *) >+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *) >+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...) >+ldb_attr_casefold: char *(TALLOC_CTX *, const char *) >+ldb_attr_dn: int (const char *) >+ldb_attr_in_list: int (const char * const *, const char *) >+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *) >+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *) >+ldb_base64_decode: int (char *) >+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int) >+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *) >+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val) >+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *) >+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) >+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t) >+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t) >+ldb_check_critical_controls: int (struct ldb_control **) >+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *) >+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *) >+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **) >+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *) >+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *) >+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...) >+ldb_debug_add: void (struct ldb_context *, const char *, ...) >+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level) >+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...) >+ldb_delete: int (struct ldb_context *, struct ldb_dn *) >+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *) >+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...) >+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *) >+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...) >+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val) >+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *) >+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *) >+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *) >+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *) >+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *) >+ldb_dn_check_special: bool (struct ldb_dn *, const char *) >+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *) >+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *) >+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *) >+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val) >+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *) >+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *) >+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *) >+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *) >+ldb_dn_get_casefold: const char *(struct ldb_dn *) >+ldb_dn_get_comp_num: int (struct ldb_dn *) >+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int) >+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int) >+ldb_dn_get_extended_comp_num: int (struct ldb_dn *) >+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *) >+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int) >+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *) >+ldb_dn_get_linearized: const char *(struct ldb_dn *) >+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *) >+ldb_dn_get_rdn_name: const char *(struct ldb_dn *) >+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *) >+ldb_dn_has_extended: bool (struct ldb_dn *) >+ldb_dn_is_null: bool (struct ldb_dn *) >+ldb_dn_is_special: bool (struct ldb_dn *) >+ldb_dn_is_valid: bool (struct ldb_dn *) >+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) >+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) >+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) >+ldb_dn_minimise: bool (struct ldb_dn *) >+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *) >+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...) >+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int) >+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int) >+ldb_dn_remove_extended_components: void (struct ldb_dn *) >+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *) >+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val) >+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *) >+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *) >+ldb_dn_validate: bool (struct ldb_dn *) >+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *) >+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int) >+ldb_errstring: const char *(struct ldb_context *) >+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **) >+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *) >+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *) >+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *) >+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *) >+ldb_get_create_perms: unsigned int (struct ldb_context *) >+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *) >+ldb_get_event_context: struct tevent_context *(struct ldb_context *) >+ldb_get_flags: unsigned int (struct ldb_context *) >+ldb_get_opaque: void *(struct ldb_context *, const char *) >+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *) >+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *) >+ldb_global_init: int (void) >+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *) >+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *) >+ldb_handle_use_global_event_context: void (struct ldb_handle *) >+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *) >+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *) >+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *) >+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *) >+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *) >+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **) >+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *) >+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *) >+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *) >+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *) >+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **) >+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *) >+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *) >+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *) >+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *) >+ldb_load_modules: int (struct ldb_context *, const char **) >+ldb_map_add: int (struct ldb_module *, struct ldb_request *) >+ldb_map_delete: int (struct ldb_module *, struct ldb_request *) >+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *) >+ldb_map_modify: int (struct ldb_module *, struct ldb_request *) >+ldb_map_rename: int (struct ldb_module *, struct ldb_request *) >+ldb_map_search: int (struct ldb_module *, struct ldb_request *) >+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *) >+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope) >+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *) >+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *) >+ldb_mod_register_control: int (struct ldb_module *, const char *) >+ldb_modify: int (struct ldb_context *, const struct ldb_message *) >+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *) >+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *) >+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **) >+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int) >+ldb_module_flags: uint32_t (struct ldb_context *) >+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *) >+ldb_module_get_name: const char *(struct ldb_module *) >+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *) >+ldb_module_get_private: void *(struct ldb_module *) >+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *) >+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **) >+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *) >+ldb_module_next: struct ldb_module *(struct ldb_module *) >+ldb_module_popt_options: struct poptOption **(struct ldb_context *) >+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **) >+ldb_module_send_referral: int (struct ldb_request *, char *) >+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *) >+ldb_module_set_private: void (struct ldb_module *, void *) >+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type) >+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *) >+ldb_modules_load: int (const char *, const char *) >+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int) >+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **) >+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...) >+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *) >+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *) >+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *) >+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *) >+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **) >+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *) >+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *) >+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *) >+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *) >+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *) >+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *) >+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **) >+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *) >+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *) >+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *) >+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int) >+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *) >+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double) >+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int) >+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t) >+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *) >+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int) >+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t) >+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t) >+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t) >+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *) >+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *) >+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *) >+ldb_msg_new: struct ldb_message *(TALLOC_CTX *) >+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **) >+ldb_msg_remove_attr: void (struct ldb_message *, const char *) >+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *) >+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *) >+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *) >+ldb_msg_sort_elements: void (struct ldb_message *) >+ldb_next_del_trans: int (struct ldb_module *) >+ldb_next_end_trans: int (struct ldb_module *) >+ldb_next_init: int (struct ldb_module *) >+ldb_next_prepare_commit: int (struct ldb_module *) >+ldb_next_read_lock: int (struct ldb_module *) >+ldb_next_read_unlock: int (struct ldb_module *) >+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *) >+ldb_next_request: int (struct ldb_module *, struct ldb_request *) >+ldb_next_start_trans: int (struct ldb_module *) >+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *) >+ldb_options_copy: const char **(TALLOC_CTX *, const char **) >+ldb_options_find: const char *(struct ldb_context *, const char **, const char *) >+ldb_options_get: const char **(struct ldb_context *) >+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t) >+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *) >+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **) >+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *) >+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *) >+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *) >+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *) >+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t) >+ldb_register_backend: int (const char *, ldb_connect_fn, bool) >+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *) >+ldb_register_hook: int (ldb_hook_fn) >+ldb_register_module: int (const struct ldb_module_ops *) >+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *) >+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *) >+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *) >+ldb_req_get_custom_flags: uint32_t (struct ldb_request *) >+ldb_req_is_untrusted: bool (struct ldb_request *) >+ldb_req_location: const char *(struct ldb_request *) >+ldb_req_mark_trusted: void (struct ldb_request *) >+ldb_req_mark_untrusted: void (struct ldb_request *) >+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t) >+ldb_req_set_location: void (struct ldb_request *, const char *) >+ldb_request: int (struct ldb_context *, struct ldb_request *) >+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *) >+ldb_request_done: int (struct ldb_request *, int) >+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *) >+ldb_request_get_status: int (struct ldb_request *) >+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *) >+ldb_request_set_state: void (struct ldb_request *, int) >+ldb_reset_err_string: void (struct ldb_context *) >+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***) >+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *) >+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *) >+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *) >+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *) >+ldb_schema_attribute_remove: void (struct ldb_context *, const char *) >+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int) >+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *) >+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *) >+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool) >+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...) >+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *) >+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *) >+ldb_set_create_perms: void (struct ldb_context *, unsigned int) >+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *) >+ldb_set_debug_stderr: int (struct ldb_context *) >+ldb_set_default_dns: void (struct ldb_context *) >+ldb_set_errstring: void (struct ldb_context *, const char *) >+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *) >+ldb_set_flags: void (struct ldb_context *, unsigned int) >+ldb_set_modules_dir: void (struct ldb_context *, const char *) >+ldb_set_opaque: int (struct ldb_context *, const char *, void *) >+ldb_set_require_private_event_context: void (struct ldb_context *) >+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int) >+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *) >+ldb_set_utf8_default: void (struct ldb_context *) >+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t)) >+ldb_setup_wellknown_attributes: int (struct ldb_context *) >+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *) >+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *) >+ldb_strerror: const char *(int) >+ldb_string_to_time: time_t (const char *) >+ldb_string_utc_to_time: time_t (const char *) >+ldb_timestring: char *(TALLOC_CTX *, time_t) >+ldb_timestring_utc: char *(TALLOC_CTX *, time_t) >+ldb_transaction_cancel: int (struct ldb_context *) >+ldb_transaction_cancel_noerr: int (struct ldb_context *) >+ldb_transaction_commit: int (struct ldb_context *) >+ldb_transaction_prepare_commit: int (struct ldb_context *) >+ldb_transaction_start: int (struct ldb_context *) >+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *) >+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int) >+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *) >+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *) >+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *) >+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *) >+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *) >+ldb_val_string_cmp: int (const struct ldb_val *, const char *) >+ldb_val_to_time: int (const struct ldb_val *, time_t *) >+ldb_valid_attr_name: int (const char *) >+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list) >+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type) >diff --git a/lib/ldb/ABI/pyldb-util-2.2.3.sigs b/lib/ldb/ABI/pyldb-util-2.2.3.sigs >new file mode 100644 >index 000000000000..164a806b2ffc >--- /dev/null >+++ b/lib/ldb/ABI/pyldb-util-2.2.3.sigs >@@ -0,0 +1,3 @@ >+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *) >+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **) >+pyldb_check_type: bool (PyObject *, const char *) >diff --git a/lib/ldb/wscript b/lib/ldb/wscript >index b2bb923379fc..57dfdd6fe6b2 100644 >--- a/lib/ldb/wscript >+++ b/lib/ldb/wscript >@@ -1,7 +1,8 @@ > #!/usr/bin/env python > > APPNAME = 'ldb' >-VERSION = '2.2.2' >+# For Samba 4.13.x >+VERSION = '2.2.3' > > import sys, os > >-- >2.25.1 > > >From ea3042363a98ffdecfa4688ba18be4bd92ae58b7 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 15 Sep 2020 16:01:04 +0200 >Subject: [PATCH 019/262] CVE-2020-25717 winbind.idl: rename wbint_TransID.type > to wbint_TransID.type_hint > >This makes it clear that it's a hint from the parent to the >child. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 1576421dbdd2cfe9a47516224cb54bf15ba51132) >--- > librpc/idl/winbind.idl | 2 +- > source3/winbindd/wb_sids2xids.c | 5 ++--- > source3/winbindd/winbindd_dual_srv.c | 2 +- > 3 files changed, 4 insertions(+), 5 deletions(-) > >diff --git a/librpc/idl/winbind.idl b/librpc/idl/winbind.idl >index 258dd284ad59..a2bc81a9333d 100644 >--- a/librpc/idl/winbind.idl >+++ b/librpc/idl/winbind.idl >@@ -40,7 +40,7 @@ interface winbind > ); > > typedef struct { >- id_type type; >+ id_type type_hint; > uint32 domain_index; > uint32 rid; > unixid xid; >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index e6698f947895..ff2135b4b50b 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -222,7 +222,7 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > > sid_copy(&dom_sid, sid); > sid_split_rid(&dom_sid, &t->rid); >- t->type = lsa_SidType_to_id_type(n->sid_type); >+ t->type_hint = lsa_SidType_to_id_type(n->sid_type); > domain_index = init_lsa_ref_domain_list( > state, &state->idmap_doms, domain_name, &dom_sid); > if (domain_index == -1) { >@@ -232,7 +232,7 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > t->domain_index = domain_index; > > t->xid.id = UINT32_MAX; >- t->xid.type = t->type; >+ t->xid.type = ID_TYPE_NOT_SPECIFIED; > } > > TALLOC_FREE(names); >@@ -337,7 +337,6 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > > for (i=0; i<dst->num_ids; i++) { > if (dst->ids[i].domain_index == state->dom_index) { >- dst->ids[i].type = src->ids[src_idx].type; > dst->ids[i].xid = src->ids[src_idx].xid; > src_idx += 1; > } >diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c >index 610195d9fb45..138863cb0db8 100644 >--- a/source3/winbindd/winbindd_dual_srv.c >+++ b/source3/winbindd/winbindd_dual_srv.c >@@ -200,7 +200,7 @@ NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p, > > sid_compose(m->sid, d->sid, ids[i].rid); > m->status = ID_UNKNOWN; >- m->xid = (struct unixid) { .type = ids[i].type }; >+ m->xid = (struct unixid) { .type = ids[i].type_hint }; > } > > status = dom->methods->sids_to_unixids(dom, id_map_ptrs); >-- >2.25.1 > > >From f39a5a70d4ecaca0ab5e455da48bd275f153e1cc Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 15 Sep 2020 16:46:44 +0200 >Subject: [PATCH 020/262] CVE-2020-25717 s3:passdb: use ID_TYPE_* instead of > WBC_ID_TYPE_* > >Currently these enums have the same values, but that will >change in future. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 58e9b62222ad62c81cdf11d704859a227cb2902b) >--- > source3/passdb/lookup_sid.c | 8 ++++---- > 1 file changed, 4 insertions(+), 4 deletions(-) > >diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c >index 4b3aa7e435dc..eb706c20e1bf 100644 >--- a/source3/passdb/lookup_sid.c >+++ b/source3/passdb/lookup_sid.c >@@ -1418,14 +1418,14 @@ done: > */ > for (i=0; i<num_sids; i++) { > switch(ids[i].type) { >- case WBC_ID_TYPE_GID: >- case WBC_ID_TYPE_UID: >- case WBC_ID_TYPE_BOTH: >+ case ID_TYPE_GID: >+ case ID_TYPE_UID: >+ case ID_TYPE_BOTH: > if (ids[i].id == (uint32_t)-1) { > ids[i].type = ID_TYPE_NOT_SPECIFIED; > } > break; >- case WBC_ID_TYPE_NOT_SPECIFIED: >+ case ID_TYPE_NOT_SPECIFIED: > break; > } > } >-- >2.25.1 > > >From 40172ec73815ffa69ea04813118769534ec96f79 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Thu, 21 Mar 2019 12:29:00 +0100 >Subject: [PATCH 021/262] CVE-2020-25717 test_idmap_tdb_common: correctly > initialize the idmap domain with an init function > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit f5eec89011cf7b577375d83247524587f170b592) >--- > source3/torture/test_idmap_tdb_common.c | 50 ++++++++++++++++--------- > 1 file changed, 33 insertions(+), 17 deletions(-) > >diff --git a/source3/torture/test_idmap_tdb_common.c b/source3/torture/test_idmap_tdb_common.c >index 5ecb978990dd..f881babcc52e 100644 >--- a/source3/torture/test_idmap_tdb_common.c >+++ b/source3/torture/test_idmap_tdb_common.c >@@ -110,12 +110,21 @@ static bool open_db(struct idmap_tdb_common_context *ctx) > return true; > } > >-static struct idmap_tdb_common_context *createcontext(TALLOC_CTX *memctx) >+static NTSTATUS idmap_test_tdb_db_init(struct idmap_domain *dom) > { > struct idmap_tdb_common_context *ret; > >- ret = talloc_zero(memctx, struct idmap_tdb_common_context); >+ DBG_DEBUG("called for domain '%s'\n", dom->name); >+ >+ ret = talloc_zero(dom, struct idmap_tdb_common_context); >+ if (ret == NULL) { >+ return NT_STATUS_NO_MEMORY; >+ } > ret->rw_ops = talloc_zero(ret, struct idmap_rw_ops); >+ if (ret->rw_ops == NULL) { >+ TALLOC_FREE(ret); >+ return NT_STATUS_NO_MEMORY; >+ } > > ret->max_id = HIGH_ID; > ret->hwmkey_uid = HWM_USER; >@@ -125,25 +134,33 @@ static struct idmap_tdb_common_context *createcontext(TALLOC_CTX *memctx) > ret->rw_ops->set_mapping = idmap_tdb_common_set_mapping; > > if (!open_db(ret)) { >- return NULL; >+ TALLOC_FREE(ret); >+ return NT_STATUS_INTERNAL_ERROR; > }; > >- return ret; >+ dom->private_data = ret; >+ >+ return NT_STATUS_OK; > } > > static struct idmap_domain *createdomain(TALLOC_CTX *memctx) > { > struct idmap_domain *dom; >+ struct idmap_methods *m; > > dom = talloc_zero(memctx, struct idmap_domain); > dom->name = "*"; > dom->low_id = LOW_ID; > dom->high_id = HIGH_ID; > dom->read_only = false; >- dom->methods = talloc_zero(dom, struct idmap_methods); >- dom->methods->sids_to_unixids = idmap_tdb_common_sids_to_unixids; >- dom->methods->unixids_to_sids = idmap_tdb_common_unixids_to_sids; >- dom->methods->allocate_id = idmap_tdb_common_get_new_id; >+ m = talloc_zero(dom, struct idmap_methods); >+ *m = (struct idmap_methods) { >+ .init = idmap_test_tdb_db_init, >+ .sids_to_unixids = idmap_tdb_common_sids_to_unixids, >+ .unixids_to_sids = idmap_tdb_common_unixids_to_sids, >+ .allocate_id = idmap_tdb_common_get_new_id, >+ }; >+ dom->methods = m; > > return dom; > } >@@ -965,20 +982,20 @@ out: > bool run_idmap_tdb_common_test(int dummy) > { > bool result; >- struct idmap_tdb_common_context *ctx; > struct idmap_domain *dom; >- >- TALLOC_CTX *memctx = talloc_new(NULL); > TALLOC_CTX *stack = talloc_stackframe(); >+ TALLOC_CTX *memctx = talloc_new(stack); >+ NTSTATUS status; > >- ctx = createcontext(memctx); >- if(!ctx) { >+ dom = createdomain(memctx); >+ if (dom == NULL) { > return false; > } > >- dom = createdomain(memctx); >- >- dom->private_data = ctx; >+ status = dom->methods->init(dom); >+ if (!NT_STATUS_IS_OK(status)) { >+ return false; >+ } > > /* test a single allocation from pool (no mapping) */ > result = test_getnewid1(memctx, dom); >@@ -1022,7 +1039,6 @@ bool run_idmap_tdb_common_test(int dummy) > result = test_getnewid2(memctx, dom); > CHECKRESULT(result); > >- talloc_free(memctx); > talloc_free(stack); > > return true; >-- >2.25.1 > > >From 886a440a577c877a7811c46c035950955f5a3210 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Thu, 21 Mar 2019 12:30:37 +0100 >Subject: [PATCH 022/262] CVE-2020-25717 winbindd/idmap: apply const to struct > idmap_methods pointers > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 95b0dac0af5bc7ee85c6c8099dda135c36c9684b) >--- > source3/include/idmap.h | 2 +- > source3/winbindd/idmap.c | 6 +++--- > source3/winbindd/idmap_ad.c | 2 +- > source3/winbindd/idmap_autorid.c | 2 +- > source3/winbindd/idmap_hash/idmap_hash.c | 2 +- > source3/winbindd/idmap_ldap.c | 2 +- > source3/winbindd/idmap_nss.c | 3 +-- > source3/winbindd/idmap_passdb.c | 7 +------ > source3/winbindd/idmap_proto.h | 2 +- > source3/winbindd/idmap_rfc2307.c | 2 +- > source3/winbindd/idmap_rid.c | 2 +- > source3/winbindd/idmap_script.c | 2 +- > source3/winbindd/idmap_tdb.c | 2 +- > source3/winbindd/idmap_tdb2.c | 2 +- > 14 files changed, 16 insertions(+), 22 deletions(-) > >diff --git a/source3/include/idmap.h b/source3/include/idmap.h >index 8d80643e6e91..dce60f1f76d9 100644 >--- a/source3/include/idmap.h >+++ b/source3/include/idmap.h >@@ -42,7 +42,7 @@ struct idmap_domain { > * so don't rely on this being filled out everywhere! > */ > struct dom_sid dom_sid; >- struct idmap_methods *methods; >+ const struct idmap_methods *methods; > NTSTATUS (*query_user)(struct idmap_domain *domain, > struct wbint_userinfo *info); > uint32_t low_id; >diff --git a/source3/winbindd/idmap.c b/source3/winbindd/idmap.c >index bfac7f86432d..eee28992929a 100644 >--- a/source3/winbindd/idmap.c >+++ b/source3/winbindd/idmap.c >@@ -40,7 +40,7 @@ static_decl_idmap; > > struct idmap_backend { > const char *name; >- struct idmap_methods *methods; >+ const struct idmap_methods *methods; > struct idmap_backend *prev, *next; > }; > static struct idmap_backend *backends = NULL; >@@ -285,7 +285,7 @@ static bool idmap_found_domain_backend(const char *domname, > return false; > } > >-static struct idmap_methods *get_methods(const char *name) >+static const struct idmap_methods *get_methods(const char *name) > { > struct idmap_backend *b; > >@@ -309,7 +309,7 @@ bool idmap_is_offline(void) > **********************************************************************/ > > NTSTATUS smb_register_idmap(int version, const char *name, >- struct idmap_methods *methods) >+ const struct idmap_methods *methods) > { > struct idmap_backend *entry; > >diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c >index 3bfeeee2d74b..5cd258d49c4f 100644 >--- a/source3/winbindd/idmap_ad.c >+++ b/source3/winbindd/idmap_ad.c >@@ -1003,7 +1003,7 @@ static NTSTATUS idmap_ad_sids_to_unixids_retry(struct idmap_domain *dom, > return status; > } > >-static struct idmap_methods ad_methods = { >+static const struct idmap_methods ad_methods = { > .init = idmap_ad_initialize, > .unixids_to_sids = idmap_ad_unixids_to_sids_retry, > .sids_to_unixids = idmap_ad_sids_to_unixids_retry, >diff --git a/source3/winbindd/idmap_autorid.c b/source3/winbindd/idmap_autorid.c >index 1d0f0fafb82d..636852119b26 100644 >--- a/source3/winbindd/idmap_autorid.c >+++ b/source3/winbindd/idmap_autorid.c >@@ -919,7 +919,7 @@ done: > return status; > } > >-static struct idmap_methods autorid_methods = { >+static const struct idmap_methods autorid_methods = { > .init = idmap_autorid_initialize, > .unixids_to_sids = idmap_autorid_unixids_to_sids, > .sids_to_unixids = idmap_autorid_sids_to_unixids, >diff --git a/source3/winbindd/idmap_hash/idmap_hash.c b/source3/winbindd/idmap_hash/idmap_hash.c >index 1747b7c56c11..267ff3e5edc6 100644 >--- a/source3/winbindd/idmap_hash/idmap_hash.c >+++ b/source3/winbindd/idmap_hash/idmap_hash.c >@@ -331,7 +331,7 @@ static NTSTATUS nss_hash_close(void) > Dispatch Tables for IDMap and NssInfo Methods > ********************************************************************/ > >-static struct idmap_methods hash_idmap_methods = { >+static const struct idmap_methods hash_idmap_methods = { > .init = idmap_hash_initialize, > .unixids_to_sids = unixids_to_sids, > .sids_to_unixids = sids_to_unixids, >diff --git a/source3/winbindd/idmap_ldap.c b/source3/winbindd/idmap_ldap.c >index 86cb6f1bc511..82f425ec9d07 100644 >--- a/source3/winbindd/idmap_ldap.c >+++ b/source3/winbindd/idmap_ldap.c >@@ -1093,7 +1093,7 @@ done: > Close the idmap ldap instance > **********************************/ > >-static struct idmap_methods idmap_ldap_methods = { >+static const struct idmap_methods idmap_ldap_methods = { > > .init = idmap_ldap_db_init, > .unixids_to_sids = idmap_ldap_unixids_to_sids, >diff --git a/source3/winbindd/idmap_nss.c b/source3/winbindd/idmap_nss.c >index 16f5a74bc0f3..da50e2b4aa75 100644 >--- a/source3/winbindd/idmap_nss.c >+++ b/source3/winbindd/idmap_nss.c >@@ -199,8 +199,7 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma > Close the idmap tdb instance > **********************************/ > >-static struct idmap_methods nss_methods = { >- >+static const struct idmap_methods nss_methods = { > .init = idmap_nss_int_init, > .unixids_to_sids = idmap_nss_unixids_to_sids, > .sids_to_unixids = idmap_nss_sids_to_unixids, >diff --git a/source3/winbindd/idmap_passdb.c b/source3/winbindd/idmap_passdb.c >index 75fc732cca05..758f31a2c9d3 100644 >--- a/source3/winbindd/idmap_passdb.c >+++ b/source3/winbindd/idmap_passdb.c >@@ -75,12 +75,7 @@ static NTSTATUS idmap_pdb_sids_to_unixids(struct idmap_domain *dom, struct id_ma > return NT_STATUS_OK; > } > >-/********************************** >- Close the idmap tdb instance >-**********************************/ >- >-static struct idmap_methods passdb_methods = { >- >+static const struct idmap_methods passdb_methods = { > .init = idmap_pdb_init, > .unixids_to_sids = idmap_pdb_unixids_to_sids, > .sids_to_unixids = idmap_pdb_sids_to_unixids, >diff --git a/source3/winbindd/idmap_proto.h b/source3/winbindd/idmap_proto.h >index a36d6c2f5bbc..adc04430a67f 100644 >--- a/source3/winbindd/idmap_proto.h >+++ b/source3/winbindd/idmap_proto.h >@@ -29,7 +29,7 @@ > > bool idmap_is_offline(void); > NTSTATUS smb_register_idmap(int version, const char *name, >- struct idmap_methods *methods); >+ const struct idmap_methods *methods); > void idmap_close(void); > NTSTATUS idmap_allocate_uid(struct unixid *id); > NTSTATUS idmap_allocate_gid(struct unixid *id); >diff --git a/source3/winbindd/idmap_rfc2307.c b/source3/winbindd/idmap_rfc2307.c >index 2fffaec6cca7..b8e478907e93 100644 >--- a/source3/winbindd/idmap_rfc2307.c >+++ b/source3/winbindd/idmap_rfc2307.c >@@ -838,7 +838,7 @@ err: > return status; > } > >-static struct idmap_methods rfc2307_methods = { >+static const struct idmap_methods rfc2307_methods = { > .init = idmap_rfc2307_initialize, > .unixids_to_sids = idmap_rfc2307_unixids_to_sids, > .sids_to_unixids = idmap_rfc2307_sids_to_unixids, >diff --git a/source3/winbindd/idmap_rid.c b/source3/winbindd/idmap_rid.c >index e5bb1fa856ce..33f049695f48 100644 >--- a/source3/winbindd/idmap_rid.c >+++ b/source3/winbindd/idmap_rid.c >@@ -168,7 +168,7 @@ static NTSTATUS idmap_rid_sids_to_unixids(struct idmap_domain *dom, struct id_ma > return NT_STATUS_OK; > } > >-static struct idmap_methods rid_methods = { >+static const struct idmap_methods rid_methods = { > .init = idmap_rid_initialize, > .unixids_to_sids = idmap_rid_unixids_to_sids, > .sids_to_unixids = idmap_rid_sids_to_unixids, >diff --git a/source3/winbindd/idmap_script.c b/source3/winbindd/idmap_script.c >index f382f896b351..a56ad7b93fbe 100644 >--- a/source3/winbindd/idmap_script.c >+++ b/source3/winbindd/idmap_script.c >@@ -665,7 +665,7 @@ failed: > return ret; > } > >-static struct idmap_methods db_methods = { >+static const struct idmap_methods db_methods = { > .init = idmap_script_db_init, > .unixids_to_sids = idmap_script_unixids_to_sids, > .sids_to_unixids = idmap_script_sids_to_unixids, >diff --git a/source3/winbindd/idmap_tdb.c b/source3/winbindd/idmap_tdb.c >index c3215c4dd9b0..1ec2be0d789a 100644 >--- a/source3/winbindd/idmap_tdb.c >+++ b/source3/winbindd/idmap_tdb.c >@@ -426,7 +426,7 @@ failed: > return ret; > } > >-static struct idmap_methods db_methods = { >+static const struct idmap_methods db_methods = { > .init = idmap_tdb_db_init, > .unixids_to_sids = idmap_tdb_common_unixids_to_sids, > .sids_to_unixids = idmap_tdb_common_sids_to_unixids, >diff --git a/source3/winbindd/idmap_tdb2.c b/source3/winbindd/idmap_tdb2.c >index eceab9c07840..f2731f9a04a3 100644 >--- a/source3/winbindd/idmap_tdb2.c >+++ b/source3/winbindd/idmap_tdb2.c >@@ -598,7 +598,7 @@ failed: > } > > >-static struct idmap_methods db_methods = { >+static const struct idmap_methods db_methods = { > .init = idmap_tdb2_db_init, > .unixids_to_sids = idmap_tdb_common_unixids_to_sids, > .sids_to_unixids = idmap_tdb_common_sids_to_unixids, >-- >2.25.1 > > >From 797a4379645663a6b9706802ad84b3004f8950b2 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Thu, 21 Mar 2019 12:30:37 +0100 >Subject: [PATCH 023/262] CVE-2020-25717 winbindd/idmap: apply const to struct > nss_info_methods pointers > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 7518a0ca32cade2b8b9eac0e2b5416ae685ffcff) >--- > source3/include/nss_info.h | 6 +++--- > source3/winbindd/idmap_ad_nss.c | 6 +++--- > source3/winbindd/idmap_hash/idmap_hash.c | 2 +- > source3/winbindd/nss_info.c | 7 ++++--- > 4 files changed, 11 insertions(+), 10 deletions(-) > >diff --git a/source3/include/nss_info.h b/source3/include/nss_info.h >index 448f8847be90..94df56ee7db0 100644 >--- a/source3/include/nss_info.h >+++ b/source3/include/nss_info.h >@@ -38,7 +38,7 @@ struct nss_function_entry { > struct nss_function_entry *prev, *next; > > const char *name; >- struct nss_info_methods *methods; >+ const struct nss_info_methods *methods; > }; > > /* List of configured domains. Each domain points >@@ -50,7 +50,7 @@ struct nss_domain_entry { > const char *domain; > > NTSTATUS init_status; >- struct nss_function_entry *backend; >+ const struct nss_function_entry *backend; > > /* hold state on a per domain basis */ > >@@ -75,7 +75,7 @@ struct nss_info_methods { > > NTSTATUS smb_register_idmap_nss(int version, > const char *name, >- struct nss_info_methods *methods); >+ const struct nss_info_methods *methods); > > NTSTATUS nss_map_to_alias( TALLOC_CTX *mem_ctx, const char *domain, > const char *name, char **alias ); >diff --git a/source3/winbindd/idmap_ad_nss.c b/source3/winbindd/idmap_ad_nss.c >index 0fd2b51e1569..96fee84997f2 100644 >--- a/source3/winbindd/idmap_ad_nss.c >+++ b/source3/winbindd/idmap_ad_nss.c >@@ -370,19 +370,19 @@ done: > /* The SFU and RFC2307 NSS plugins share everything but the init > function which sets the intended schema model to use */ > >-static struct nss_info_methods nss_rfc2307_methods = { >+static const struct nss_info_methods nss_rfc2307_methods = { > .init = nss_rfc2307_init, > .map_to_alias = nss_ad_map_to_alias, > .map_from_alias = nss_ad_map_from_alias, > }; > >-static struct nss_info_methods nss_sfu_methods = { >+static const struct nss_info_methods nss_sfu_methods = { > .init = nss_sfu_init, > .map_to_alias = nss_ad_map_to_alias, > .map_from_alias = nss_ad_map_from_alias, > }; > >-static struct nss_info_methods nss_sfu20_methods = { >+static const struct nss_info_methods nss_sfu20_methods = { > .init = nss_sfu20_init, > .map_to_alias = nss_ad_map_to_alias, > .map_from_alias = nss_ad_map_from_alias, >diff --git a/source3/winbindd/idmap_hash/idmap_hash.c b/source3/winbindd/idmap_hash/idmap_hash.c >index 267ff3e5edc6..be0ba45a0443 100644 >--- a/source3/winbindd/idmap_hash/idmap_hash.c >+++ b/source3/winbindd/idmap_hash/idmap_hash.c >@@ -337,7 +337,7 @@ static const struct idmap_methods hash_idmap_methods = { > .sids_to_unixids = sids_to_unixids, > }; > >-static struct nss_info_methods hash_nss_methods = { >+static const struct nss_info_methods hash_nss_methods = { > .init = nss_hash_init, > .map_to_alias = nss_hash_map_to_alias, > .map_from_alias = nss_hash_map_from_alias, >diff --git a/source3/winbindd/nss_info.c b/source3/winbindd/nss_info.c >index 1a8325ce7dc6..9c502e84ef06 100644 >--- a/source3/winbindd/nss_info.c >+++ b/source3/winbindd/nss_info.c >@@ -46,7 +46,8 @@ static struct nss_function_entry *nss_get_backend(const char *name ) > Allow a module to register itself as a backend. > **********************************************************************/ > >- NTSTATUS smb_register_idmap_nss(int version, const char *name, struct nss_info_methods *methods) >+ NTSTATUS smb_register_idmap_nss(int version, const char *name, >+ const struct nss_info_methods *methods) > { > struct nss_function_entry *entry; > >@@ -319,7 +320,7 @@ static struct nss_domain_entry *find_nss_domain( const char *domain ) > const char *name, char **alias ) > { > struct nss_domain_entry *p; >- struct nss_info_methods *m; >+ const struct nss_info_methods *m; > > if ( (p = find_nss_domain( domain )) == NULL ) { > DEBUG(4,("nss_map_to_alias: Failed to find nss domain pointer for %s\n", >@@ -340,7 +341,7 @@ static struct nss_domain_entry *find_nss_domain( const char *domain ) > const char *alias, char **name ) > { > struct nss_domain_entry *p; >- struct nss_info_methods *m; >+ const struct nss_info_methods *m; > > if ( (p = find_nss_domain( domain )) == NULL ) { > DEBUG(4,("nss_map_from_alias: Failed to find nss domain pointer for %s\n", >-- >2.25.1 > > >From 10bfe400b4b243e3a4612390db6a7595cdb1d5a2 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 13:52:17 +0200 >Subject: [PATCH 024/262] CVE-2020-25717 wb_queryuser: avoid idmap_child() and > use idmap_child_handle() instead > >This is the only aspect we need here. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 7dbe5b4897448aa71b5a8a2175850b4010316b88) >--- > source3/winbindd/wb_queryuser.c | 21 +++++++++------------ > 1 file changed, 9 insertions(+), 12 deletions(-) > >diff --git a/source3/winbindd/wb_queryuser.c b/source3/winbindd/wb_queryuser.c >index 2eb61406fc5a..2e36643454b7 100644 >--- a/source3/winbindd/wb_queryuser.c >+++ b/source3/winbindd/wb_queryuser.c >@@ -77,7 +77,7 @@ static void wb_queryuser_got_uid(struct tevent_req *subreq) > req, struct wb_queryuser_state); > struct wbint_userinfo *info = state->info; > struct netr_SamInfo3 *info3; >- struct winbindd_child *child; >+ struct dcerpc_binding_handle *child_binding_handle = NULL; > struct unixid xid; > NTSTATUS status; > >@@ -138,10 +138,9 @@ static void wb_queryuser_got_uid(struct tevent_req *subreq) > return; > } > >- child = idmap_child(); >- >+ child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_GetNssInfo_send( >- state, state->ev, child->binding_handle, info); >+ state, state->ev, child_binding_handle, info); > if (tevent_req_nomem(subreq, req)) { > return; > } >@@ -156,7 +155,7 @@ static void wb_queryuser_got_domain(struct tevent_req *subreq) > req, struct wb_queryuser_state); > struct wbint_userinfo *info = state->info; > enum lsa_SidType type; >- struct winbindd_child *child; >+ struct dcerpc_binding_handle *child_binding_handle = NULL; > NTSTATUS status; > > status = wb_lookupsid_recv(subreq, state, &type, >@@ -186,10 +185,9 @@ static void wb_queryuser_got_domain(struct tevent_req *subreq) > return; > } > >- child = idmap_child(); >- >+ child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_GetNssInfo_send( >- state, state->ev, child->binding_handle, info); >+ state, state->ev, child_binding_handle, info); > if (tevent_req_nomem(subreq, req)) { > return; > } >@@ -270,7 +268,7 @@ static void wb_queryuser_got_dc(struct tevent_req *subreq) > req, struct wb_queryuser_state); > struct wbint_userinfo *info = state->info; > struct netr_DsRGetDCNameInfo *dcinfo; >- struct winbindd_child *child; >+ struct dcerpc_binding_handle *child_binding_handle = NULL; > NTSTATUS status; > > status = wb_dsgetdcname_recv(subreq, state, &dcinfo); >@@ -286,10 +284,9 @@ static void wb_queryuser_got_dc(struct tevent_req *subreq) > return; > } > >- child = idmap_child(); >- >+ child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_GetNssInfo_send( >- state, state->ev, child->binding_handle, info); >+ state, state->ev, child_binding_handle, info); > if (tevent_req_nomem(subreq, req)) { > return; > } >-- >2.25.1 > > >From cd7421b022e08ecd0bf9fae9190e7797a1efe13d Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 12:35:09 +0200 >Subject: [PATCH 025/262] CVE-2020-25717 wb_xids2sids: avoid idmap_child() and > use idmap_child_handle() instead > >This is the only aspect we need here. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 5cc21a9d319e00397ad98900d81ffb9d1d70514f) >--- > source3/winbindd/wb_xids2sids.c | 12 ++++++------ > 1 file changed, 6 insertions(+), 6 deletions(-) > >diff --git a/source3/winbindd/wb_xids2sids.c b/source3/winbindd/wb_xids2sids.c >index 929a3b8e4251..f88c9be58a85 100644 >--- a/source3/winbindd/wb_xids2sids.c >+++ b/source3/winbindd/wb_xids2sids.c >@@ -270,7 +270,7 @@ static struct tevent_req *wb_xids2sids_dom_send( > { > struct tevent_req *req, *subreq; > struct wb_xids2sids_dom_state *state; >- struct winbindd_child *child; >+ struct dcerpc_binding_handle *child_binding_handle = NULL; > size_t i; > > req = tevent_req_create(mem_ctx, &state, >@@ -317,9 +317,9 @@ static struct tevent_req *wb_xids2sids_dom_send( > return tevent_req_post(req, ev); > } > >- child = idmap_child(); >+ child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_UnixIDs2Sids_send( >- state, ev, child->binding_handle, dom_map->name, dom_map->sid, >+ state, ev, child_binding_handle, dom_map->name, dom_map->sid, > state->num_dom_xids, state->dom_xids, state->dom_sids); > if (tevent_req_nomem(subreq, req)) { > return tevent_req_post(req, ev); >@@ -396,7 +396,7 @@ static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq) > subreq, struct tevent_req); > struct wb_xids2sids_dom_state *state = tevent_req_data( > req, struct wb_xids2sids_dom_state); >- struct winbindd_child *child = idmap_child(); >+ struct dcerpc_binding_handle *child_binding_handle = NULL; > struct netr_DsRGetDCNameInfo *dcinfo; > NTSTATUS status; > >@@ -413,9 +413,9 @@ static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq) > return; > } > >- child = idmap_child(); >+ child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_UnixIDs2Sids_send( >- state, state->ev, child->binding_handle, state->dom_map->name, >+ state, state->ev, child_binding_handle, state->dom_map->name, > state->dom_map->sid, state->num_dom_xids, > state->dom_xids, state->dom_sids); > if (tevent_req_nomem(subreq, req)) { >-- >2.25.1 > > >From 92bd4b2011fe1a3a18613987f7e60a45c239d786 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Thu, 10 Sep 2020 15:49:34 +0200 >Subject: [PATCH 026/262] CVE-2020-25717 wb_sids2xids: avoid idmap_child() and > use idmap_child_handle() instead > >This is the only aspect we need here. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 1694de1ae6ce63377d0afc47e84e55e4745905d7) >--- > source3/winbindd/wb_sids2xids.c | 16 +++++++--------- > 1 file changed, 7 insertions(+), 9 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index ff2135b4b50b..b47856520eac 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -238,8 +238,6 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > TALLOC_FREE(names); > TALLOC_FREE(domains); > >- child_binding_handle = idmap_child_handle(); >- > state->dom_ids = wb_sids2xids_extract_for_domain_index( > state, &state->ids, state->dom_index); > if (tevent_req_nomem(state->dom_ids, req)) { >@@ -252,6 +250,7 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > .max_size = 1 > }; > >+ child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_Sids2UnixIDs_send( > state, state->ev, child_binding_handle, &state->idmap_dom, > state->dom_ids); >@@ -290,8 +289,7 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > struct wb_sids2xids_state *state = tevent_req_data( > req, struct wb_sids2xids_state); > NTSTATUS status, result; >- struct winbindd_child *child; >- >+ struct dcerpc_binding_handle *child_binding_handle = NULL; > struct wbint_TransIDArray *src, *dst; > uint32_t i, src_idx; > >@@ -352,8 +350,6 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > return; > } > >- child = idmap_child(); >- > state->dom_ids = wb_sids2xids_extract_for_domain_index( > state, &state->ids, state->dom_index); > if (tevent_req_nomem(state->dom_ids, req)) { >@@ -366,8 +362,9 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > .max_size = 1 > }; > >+ child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_Sids2UnixIDs_send( >- state, state->ev, child->binding_handle, &state->idmap_dom, >+ state, state->ev, child_binding_handle, &state->idmap_dom, > state->dom_ids); > if (tevent_req_nomem(subreq, req)) { > return; >@@ -381,7 +378,7 @@ static void wb_sids2xids_gotdc(struct tevent_req *subreq) > subreq, struct tevent_req); > struct wb_sids2xids_state *state = tevent_req_data( > req, struct wb_sids2xids_state); >- struct winbindd_child *child = idmap_child(); >+ struct dcerpc_binding_handle *child_binding_handle = NULL; > struct netr_DsRGetDCNameInfo *dcinfo; > NTSTATUS status; > >@@ -404,8 +401,9 @@ static void wb_sids2xids_gotdc(struct tevent_req *subreq) > } > } > >+ child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_Sids2UnixIDs_send( >- state, state->ev, child->binding_handle, &state->idmap_dom, >+ state, state->ev, child_binding_handle, &state->idmap_dom, > state->dom_ids); > if (tevent_req_nomem(subreq, req)) { > return; >-- >2.25.1 > > >From ad75a5ee7b612db01d149185999541f9bd366804 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 14:06:04 +0200 >Subject: [PATCH 027/262] CVE-2020-25717 winbindd: add and use > idmap_child_pid() > >We should avoid calling idmap_child() as much as possible. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 2103543629004a3a22e7bf60305bb15bf3b316be) >--- > source3/winbindd/winbindd_cm.c | 12 ++++++------ > source3/winbindd/winbindd_dual.c | 6 +++--- > source3/winbindd/winbindd_idmap.c | 5 +++++ > source3/winbindd/winbindd_proto.h | 1 + > 4 files changed, 15 insertions(+), 9 deletions(-) > >diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c >index 5fb22d7e9c8a..bb819bbba19f 100644 >--- a/source3/winbindd/winbindd_cm.c >+++ b/source3/winbindd/winbindd_cm.c >@@ -463,11 +463,11 @@ void set_domain_offline(struct winbindd_domain *domain) > primary domain goes offline */ > > if ( domain->primary ) { >- struct winbindd_child *idmap = idmap_child(); >+ pid_t idmap_pid = idmap_child_pid(); > >- if ( idmap->pid != 0 ) { >+ if (idmap_pid != 0) { > messaging_send_buf(global_messaging_context(), >- pid_to_procid(idmap->pid), >+ pid_to_procid(idmap_pid), > MSG_WINBIND_OFFLINE, > (const uint8_t *)domain->name, > strlen(domain->name)+1); >@@ -549,11 +549,11 @@ static void set_domain_online(struct winbindd_domain *domain) > primary domain comes online */ > > if ( domain->primary ) { >- struct winbindd_child *idmap = idmap_child(); >+ pid_t idmap_pid = idmap_child_pid(); > >- if ( idmap->pid != 0 ) { >+ if (idmap_pid != 0) { > messaging_send_buf(global_messaging_context(), >- pid_to_procid(idmap->pid), >+ pid_to_procid(idmap_pid), > MSG_WINBIND_ONLINE, > (const uint8_t *)domain->name, > strlen(domain->name)+1); >diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c >index b1c86b2979c3..0edfc2d205d0 100644 >--- a/source3/winbindd/winbindd_dual.c >+++ b/source3/winbindd/winbindd_dual.c >@@ -1071,11 +1071,11 @@ void winbind_msg_online(struct messaging_context *msg_ctx, > primary domain comes back online */ > > if ( domain->primary ) { >- struct winbindd_child *idmap = idmap_child(); >+ pid_t idmap_pid = idmap_child_pid(); > >- if ( idmap->pid != 0 ) { >+ if (idmap_pid != 0) { > messaging_send_buf(msg_ctx, >- pid_to_procid(idmap->pid), >+ pid_to_procid(idmap_pid), > MSG_WINBIND_ONLINE, > (const uint8_t *)domain->name, > strlen(domain->name)+1); >diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c >index 2ee436bc7dcd..965a7839f17d 100644 >--- a/source3/winbindd/winbindd_idmap.c >+++ b/source3/winbindd/winbindd_idmap.c >@@ -34,6 +34,11 @@ struct winbindd_child *idmap_child(void) > return &static_idmap_child; > } > >+pid_t idmap_child_pid(void) >+{ >+ return static_idmap_child.pid; >+} >+ > struct dcerpc_binding_handle *idmap_child_handle(void) > { > return static_idmap_child.binding_handle; >diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h >index 6d4ffa726f1d..ce391ab7ec55 100644 >--- a/source3/winbindd/winbindd_proto.h >+++ b/source3/winbindd/winbindd_proto.h >@@ -366,6 +366,7 @@ NTSTATUS winbindd_print_groupmembers(struct db_context *members, > > void init_idmap_child(void); > struct winbindd_child *idmap_child(void); >+pid_t idmap_child_pid(void); > struct dcerpc_binding_handle *idmap_child_handle(void); > struct idmap_domain *idmap_find_domain_with_sid(const char *domname, > const struct dom_sid *sid); >-- >2.25.1 > > >From d006bafb71799d18ff2900ae177b9c42bbdfa21c Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 14:06:04 +0200 >Subject: [PATCH 028/262] CVE-2020-25717 winbindd: add and use is_idmap_child() > >We should avoid calling idmap_child() as much as possible. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit cd9a9702c1f97c47bd3447e2014eeff3e56268cf) >--- > source3/winbindd/winbindd_dual.c | 4 ++-- > source3/winbindd/winbindd_idmap.c | 9 +++++++++ > source3/winbindd/winbindd_proto.h | 1 + > 3 files changed, 12 insertions(+), 2 deletions(-) > >diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c >index 0edfc2d205d0..4f07ff494451 100644 >--- a/source3/winbindd/winbindd_dual.c >+++ b/source3/winbindd/winbindd_dual.c >@@ -1776,7 +1776,7 @@ static bool fork_domain_child(struct winbindd_child *child) > > if (child_domain != NULL) { > setproctitle("domain child [%s]", child_domain->name); >- } else if (child == idmap_child()) { >+ } else if (is_idmap_child(child)) { > setproctitle("idmap child"); > } > >@@ -1826,7 +1826,7 @@ static bool fork_domain_child(struct winbindd_child *child) > * We are in idmap child, make sure that we set the > * check_online_event to bring primary domain online. > */ >- if (child == idmap_child()) { >+ if (is_idmap_child(child)) { > set_domain_online_request(primary_domain); > } > >diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c >index 965a7839f17d..bd5f3a67aade 100644 >--- a/source3/winbindd/winbindd_idmap.c >+++ b/source3/winbindd/winbindd_idmap.c >@@ -34,6 +34,15 @@ struct winbindd_child *idmap_child(void) > return &static_idmap_child; > } > >+bool is_idmap_child(const struct winbindd_child *child) >+{ >+ if (child == &static_idmap_child) { >+ return true; >+ } >+ >+ return false; >+} >+ > pid_t idmap_child_pid(void) > { > return static_idmap_child.pid; >diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h >index ce391ab7ec55..97c38018aac5 100644 >--- a/source3/winbindd/winbindd_proto.h >+++ b/source3/winbindd/winbindd_proto.h >@@ -366,6 +366,7 @@ NTSTATUS winbindd_print_groupmembers(struct db_context *members, > > void init_idmap_child(void); > struct winbindd_child *idmap_child(void); >+bool is_idmap_child(const struct winbindd_child *child); > pid_t idmap_child_pid(void); > struct dcerpc_binding_handle *idmap_child_handle(void); > struct idmap_domain *idmap_find_domain_with_sid(const char *domname, >-- >2.25.1 > > >From 6acee03ff416ff055859d9a4884355bc318aad50 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 12:16:00 +0200 >Subject: [PATCH 029/262] CVE-2020-25717 winbindd: add generic > wb_parent_idmap_setup_send/recv() helpers > >This is more or less a copy of wb_xids2sids_init_dom_maps_send/recv, >but it's more generic and doesn't imply global state. > >It also closes a initialization race by using a tevent_queue to >serialize the calls. > >In the next commits we'll replace wb_xids2sids_init_dom_maps_send/recv. > >We'll also use the new function in the wb_sids2xids code. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 209e81a2ea8c972ee57e2f0c9579da843c0e2ac7) >--- > source3/winbindd/winbindd.h | 13 ++ > source3/winbindd/winbindd_idmap.c | 314 ++++++++++++++++++++++++++++++ > source3/winbindd/winbindd_proto.h | 5 + > 3 files changed, 332 insertions(+) > >diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h >index a72d6aa7830a..480ba4f12822 100644 >--- a/source3/winbindd/winbindd.h >+++ b/source3/winbindd/winbindd.h >@@ -189,6 +189,19 @@ struct winbindd_domain { > struct winbindd_domain *prev, *next; > }; > >+struct wb_parent_idmap_config_dom { >+ unsigned low_id; >+ unsigned high_id; >+ const char *name; >+ struct dom_sid sid; >+}; >+ >+struct wb_parent_idmap_config { >+ struct tevent_queue *queue; >+ uint32_t num_doms; >+ struct wb_parent_idmap_config_dom *doms; >+}; >+ > struct wb_acct_info { > const char *acct_name; /* account name */ > const char *acct_desc; /* account name */ >diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c >index bd5f3a67aade..487f27fd94dd 100644 >--- a/source3/winbindd/winbindd_idmap.c >+++ b/source3/winbindd/winbindd_idmap.c >@@ -23,12 +23,21 @@ > > #include "includes.h" > #include "winbindd.h" >+#include "../libcli/security/security.h" >+#include "passdb/lookup_sid.h" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_WINBIND > > static struct winbindd_child static_idmap_child; > >+/* >+ * Map idmap ranges to domain names, taken from smb.conf. This is >+ * stored in the parent winbind and used to assemble xids2sids/sids2xids calls >+ * into per-idmap-domain chunks. >+ */ >+static struct wb_parent_idmap_config static_parent_idmap_config; >+ > struct winbindd_child *idmap_child(void) > { > return &static_idmap_child; >@@ -73,3 +82,308 @@ void init_idmap_child(void) > idmap_dispatch_table, > "log.winbindd", "idmap"); > } >+ >+struct wb_parent_idmap_setup_state { >+ struct tevent_context *ev; >+ struct wb_parent_idmap_config *cfg; >+ size_t dom_idx; >+}; >+ >+static void wb_parent_idmap_setup_cleanup(struct tevent_req *req, >+ enum tevent_req_state req_state) >+{ >+ struct wb_parent_idmap_setup_state *state = >+ tevent_req_data(req, >+ struct wb_parent_idmap_setup_state); >+ >+ if (req_state == TEVENT_REQ_DONE) { >+ state->cfg = NULL; >+ return; >+ } >+ >+ if (state->cfg == NULL) { >+ return; >+ } >+ >+ state->cfg->num_doms = 0; >+ TALLOC_FREE(state->cfg->doms); >+ state->cfg = NULL; >+} >+ >+static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq); >+static bool wb_parent_idmap_setup_scan_config(const char *domname, >+ void *private_data); >+static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req); >+static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq); >+ >+struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev) >+{ >+ struct tevent_req *req = NULL; >+ struct wb_parent_idmap_setup_state *state = NULL; >+ struct tevent_req *subreq = NULL; >+ >+ req = tevent_req_create(mem_ctx, &state, >+ struct wb_parent_idmap_setup_state); >+ if (req == NULL) { >+ return NULL; >+ } >+ *state = (struct wb_parent_idmap_setup_state) { >+ .ev = ev, >+ .cfg = &static_parent_idmap_config, >+ .dom_idx = 0, >+ }; >+ >+ if (state->cfg->queue == NULL) { >+ state->cfg->queue = tevent_queue_create(NULL, >+ "wb_parent_idmap_config_queue"); >+ if (tevent_req_nomem(state->cfg->queue, req)) { >+ return tevent_req_post(req, ev); >+ } >+ } >+ >+ subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue); >+ if (tevent_req_nomem(subreq, req)) { >+ return tevent_req_post(req, ev); >+ } >+ tevent_req_set_callback(subreq, >+ wb_parent_idmap_setup_queue_wait_done, >+ req); >+ >+ return req; >+} >+ >+static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq) >+{ >+ struct tevent_req *req = >+ tevent_req_callback_data(subreq, >+ struct tevent_req); >+ struct wb_parent_idmap_setup_state *state = >+ tevent_req_data(req, >+ struct wb_parent_idmap_setup_state); >+ bool ok; >+ >+ /* >+ * Note we don't call TALLOC_FREE(subreq) here in order to block the >+ * queue until tevent_req_received() in wb_parent_idmap_setup_recv() >+ * will destroy it implicitly. >+ */ >+ ok = tevent_queue_wait_recv(subreq); >+ if (!ok) { >+ DBG_ERR("tevent_queue_wait_recv() failed\n"); >+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >+ return; >+ } >+ >+ if (state->cfg->num_doms != 0) { >+ /* >+ * If we're not the first one we're done. >+ */ >+ tevent_req_done(req); >+ return; >+ } >+ >+ /* >+ * From this point we start changing state->cfg, >+ * which is &static_parent_idmap_config, >+ * so we better setup a cleanup function >+ * to undo the changes on failure. >+ */ >+ tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup); >+ >+ /* >+ * Put the passdb idmap domain first. We always need to try >+ * there first. >+ */ >+ state->cfg->doms = talloc_zero_array(NULL, >+ struct wb_parent_idmap_config_dom, >+ 1); >+ if (tevent_req_nomem(state->cfg->doms, req)) { >+ return; >+ } >+ state->cfg->doms[0].low_id = 0; >+ state->cfg->doms[0].high_id = UINT_MAX; >+ state->cfg->doms[0].name = talloc_strdup(state->cfg->doms, >+ get_global_sam_name()); >+ if (tevent_req_nomem(state->cfg->doms[0].name, req)) { >+ return; >+ } >+ state->cfg->num_doms += 1; >+ >+ lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req); >+ if (!tevent_req_is_in_progress(req)) { >+ return; >+ } >+ >+ wb_parent_idmap_setup_lookupname_next(req); >+} >+ >+static bool wb_parent_idmap_setup_scan_config(const char *domname, >+ void *private_data) >+{ >+ struct tevent_req *req = >+ talloc_get_type_abort(private_data, >+ struct tevent_req); >+ struct wb_parent_idmap_setup_state *state = >+ tevent_req_data(req, >+ struct wb_parent_idmap_setup_state); >+ struct wb_parent_idmap_config_dom *map = NULL; >+ size_t i; >+ const char *range; >+ unsigned low_id, high_id; >+ int ret; >+ >+ range = idmap_config_const_string(domname, "range", NULL); >+ if (range == NULL) { >+ DBG_DEBUG("No range for domain %s found\n", domname); >+ return false; >+ } >+ >+ ret = sscanf(range, "%u - %u", &low_id, &high_id); >+ if (ret != 2) { >+ DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n", >+ range, domname); >+ return false; >+ } >+ >+ if (low_id > high_id) { >+ DBG_DEBUG("Invalid range %u - %u for domain %s\n", >+ low_id, high_id, domname); >+ return false; >+ } >+ >+ for (i=0; i<state->cfg->num_doms; i++) { >+ if (strequal(domname, state->cfg->doms[i].name)) { >+ map = &state->cfg->doms[i]; >+ break; >+ } >+ } >+ >+ if (map == NULL) { >+ struct wb_parent_idmap_config_dom *tmp; >+ char *name; >+ >+ name = talloc_strdup(state, domname); >+ if (name == NULL) { >+ DBG_ERR("talloc failed\n"); >+ return false; >+ } >+ >+ tmp = talloc_realloc( >+ NULL, state->cfg->doms, struct wb_parent_idmap_config_dom, >+ state->cfg->num_doms+1); >+ if (tmp == NULL) { >+ DBG_ERR("talloc failed\n"); >+ return false; >+ } >+ state->cfg->doms = tmp; >+ >+ map = &state->cfg->doms[state->cfg->num_doms]; >+ state->cfg->num_doms += 1; >+ ZERO_STRUCTP(map); >+ map->name = talloc_move(state->cfg->doms, &name); >+ } >+ >+ map->low_id = low_id; >+ map->high_id = high_id; >+ >+ return false; >+} >+ >+static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req) >+{ >+ struct wb_parent_idmap_setup_state *state = >+ tevent_req_data(req, >+ struct wb_parent_idmap_setup_state); >+ struct wb_parent_idmap_config_dom *dom = >+ &state->cfg->doms[state->dom_idx]; >+ struct tevent_req *subreq = NULL; >+ >+ next_domain: >+ if (state->dom_idx == state->cfg->num_doms) { >+ tevent_req_done(req); >+ return; >+ } >+ >+ if (strequal(dom->name, "*")) { >+ state->dom_idx++; >+ goto next_domain; >+ } >+ >+ subreq = wb_lookupname_send(state, >+ state->ev, >+ dom->name, >+ dom->name, >+ "", >+ LOOKUP_NAME_NO_NSS); >+ if (tevent_req_nomem(subreq, req)) { >+ return; >+ } >+ tevent_req_set_callback(subreq, >+ wb_parent_idmap_setup_lookupname_done, >+ req); >+} >+ >+static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq) >+{ >+ struct tevent_req *req = >+ tevent_req_callback_data(subreq, >+ struct tevent_req); >+ struct wb_parent_idmap_setup_state *state = >+ tevent_req_data(req, >+ struct wb_parent_idmap_setup_state); >+ struct wb_parent_idmap_config_dom *dom = >+ &state->cfg->doms[state->dom_idx]; >+ enum lsa_SidType type; >+ NTSTATUS status; >+ >+ status = wb_lookupname_recv(subreq, &dom->sid, &type); >+ TALLOC_FREE(subreq); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG_ERR("Lookup domain name '%s' failed '%s'\n", >+ dom->name, >+ nt_errstr(status)); >+ >+ state->dom_idx++; >+ wb_parent_idmap_setup_lookupname_next(req); >+ return; >+ } >+ >+ if (type != SID_NAME_DOMAIN) { >+ struct dom_sid_buf buf; >+ >+ DBG_ERR("SID %s for idmap domain name '%s' " >+ "not a domain SID\n", >+ dom_sid_str_buf(&dom->sid, &buf), >+ dom->name); >+ >+ ZERO_STRUCT(dom->sid); >+ } >+ >+ state->dom_idx++; >+ wb_parent_idmap_setup_lookupname_next(req); >+ >+ return; >+} >+ >+NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req, >+ const struct wb_parent_idmap_config **_cfg) >+{ >+ const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config; >+ NTSTATUS status; >+ >+ *_cfg = NULL; >+ >+ if (tevent_req_is_nterror(req, &status)) { >+ tevent_req_received(req); >+ return status; >+ } >+ >+ /* >+ * Note state->cfg is already set to NULL by >+ * wb_parent_idmap_setup_cleanup() >+ */ >+ *_cfg = cfg; >+ tevent_req_received(req); >+ return NT_STATUS_OK; >+} >diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h >index 97c38018aac5..8923bb3124f9 100644 >--- a/source3/winbindd/winbindd_proto.h >+++ b/source3/winbindd/winbindd_proto.h >@@ -364,6 +364,11 @@ NTSTATUS winbindd_print_groupmembers(struct db_context *members, > > /* The following definitions come from winbindd/winbindd_idmap.c */ > >+struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev); >+NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req, >+ const struct wb_parent_idmap_config **_cfg); >+ > void init_idmap_child(void); > struct winbindd_child *idmap_child(void); > bool is_idmap_child(const struct winbindd_child *child); >-- >2.25.1 > > >From 886484256bb2d6aa40220f63502a491659443b07 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 12:31:13 +0200 >Subject: [PATCH 030/262] CVE-2020-25717 wb_xids2sids: make use of the new > wb_parent_idmap_setup_send/recv() helpers > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit a8f57c94fc2294c309ecb18ea79d0acac86c495b) >--- > source3/winbindd/wb_xids2sids.c | 255 +++----------------------------- > 1 file changed, 17 insertions(+), 238 deletions(-) > >diff --git a/source3/winbindd/wb_xids2sids.c b/source3/winbindd/wb_xids2sids.c >index f88c9be58a85..c68939b2bcd3 100644 >--- a/source3/winbindd/wb_xids2sids.c >+++ b/source3/winbindd/wb_xids2sids.c >@@ -25,231 +25,13 @@ > #include "librpc/gen_ndr/ndr_netlogon.h" > #include "passdb/lookup_sid.h" > >-struct wb_xids2sids_dom_map { >- unsigned low_id; >- unsigned high_id; >- const char *name; >- struct dom_sid sid; >-}; >- >-/* >- * Map idmap ranges to domain names, taken from smb.conf. This is >- * stored in the parent winbind and used to assemble xid2sid calls >- * into per-idmap-domain chunks. >- */ >-static struct wb_xids2sids_dom_map *dom_maps; >- >-static bool wb_xids2sids_add_dom(const char *domname, >- void *private_data) >-{ >- struct wb_xids2sids_dom_map *map = NULL; >- size_t num_maps = talloc_array_length(dom_maps); >- size_t i; >- const char *range; >- unsigned low_id, high_id; >- int ret; >- >- range = idmap_config_const_string(domname, "range", NULL); >- if (range == NULL) { >- DBG_DEBUG("No range for domain %s found\n", domname); >- return false; >- } >- >- ret = sscanf(range, "%u - %u", &low_id, &high_id); >- if (ret != 2) { >- DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n", >- range, domname); >- return false; >- } >- >- if (low_id > high_id) { >- DBG_DEBUG("Invalid range %u - %u for domain %s\n", >- low_id, high_id, domname); >- return false; >- } >- >- for (i=0; i<num_maps; i++) { >- if (strequal(domname, dom_maps[i].name)) { >- map = &dom_maps[i]; >- break; >- } >- } >- >- if (map == NULL) { >- struct wb_xids2sids_dom_map *tmp; >- char *name; >- >- name = talloc_strdup(talloc_tos(), domname); >- if (name == NULL) { >- DBG_DEBUG("talloc failed\n"); >- return false; >- } >- >- tmp = talloc_realloc( >- NULL, dom_maps, struct wb_xids2sids_dom_map, >- num_maps+1); >- if (tmp == NULL) { >- TALLOC_FREE(name); >- return false; >- } >- dom_maps = tmp; >- >- map = &dom_maps[num_maps]; >- ZERO_STRUCTP(map); >- map->name = talloc_move(dom_maps, &name); >- } >- >- map->low_id = low_id; >- map->high_id = high_id; >- >- return false; >-} >- >-struct wb_xids2sids_init_dom_maps_state { >- struct tevent_context *ev; >- struct tevent_req *req; >- size_t dom_idx; >-}; >- >-static void wb_xids2sids_init_dom_maps_lookupname_next( >- struct wb_xids2sids_init_dom_maps_state *state); >- >-static void wb_xids2sids_init_dom_maps_lookupname_done( >- struct tevent_req *subreq); >- >-static struct tevent_req *wb_xids2sids_init_dom_maps_send( >- TALLOC_CTX *mem_ctx, struct tevent_context *ev) >-{ >- struct tevent_req *req = NULL; >- struct wb_xids2sids_init_dom_maps_state *state = NULL; >- >- req = tevent_req_create(mem_ctx, &state, >- struct wb_xids2sids_init_dom_maps_state); >- if (req == NULL) { >- return NULL; >- } >- *state = (struct wb_xids2sids_init_dom_maps_state) { >- .ev = ev, >- .req = req, >- .dom_idx = 0, >- }; >- >- if (dom_maps != NULL) { >- tevent_req_done(req); >- return tevent_req_post(req, ev); >- } >- /* >- * Put the passdb idmap domain first. We always need to try >- * there first. >- */ >- >- dom_maps = talloc_zero_array(NULL, struct wb_xids2sids_dom_map, 1); >- if (tevent_req_nomem(dom_maps, req)) { >- return tevent_req_post(req, ev); >- } >- dom_maps[0].low_id = 0; >- dom_maps[0].high_id = UINT_MAX; >- dom_maps[0].name = talloc_strdup(dom_maps, get_global_sam_name()); >- if (tevent_req_nomem(dom_maps[0].name, req)) { >- TALLOC_FREE(dom_maps); >- return tevent_req_post(req, ev); >- } >- >- lp_scan_idmap_domains(wb_xids2sids_add_dom, NULL); >- >- wb_xids2sids_init_dom_maps_lookupname_next(state); >- if (!tevent_req_is_in_progress(req)) { >- tevent_req_post(req, ev); >- } >- return req; >-} >- >-static void wb_xids2sids_init_dom_maps_lookupname_next( >- struct wb_xids2sids_init_dom_maps_state *state) >-{ >- struct tevent_req *subreq = NULL; >- >- if (state->dom_idx == talloc_array_length(dom_maps)) { >- tevent_req_done(state->req); >- return; >- } >- >- if (strequal(dom_maps[state->dom_idx].name, "*")) { >- state->dom_idx++; >- if (state->dom_idx == talloc_array_length(dom_maps)) { >- tevent_req_done(state->req); >- return; >- } >- } >- >- subreq = wb_lookupname_send(state, >- state->ev, >- dom_maps[state->dom_idx].name, >- dom_maps[state->dom_idx].name, >- "", >- LOOKUP_NAME_NO_NSS); >- if (tevent_req_nomem(subreq, state->req)) { >- return; >- } >- tevent_req_set_callback(subreq, >- wb_xids2sids_init_dom_maps_lookupname_done, >- state->req); >-} >- >-static void wb_xids2sids_init_dom_maps_lookupname_done( >- struct tevent_req *subreq) >-{ >- struct tevent_req *req = tevent_req_callback_data( >- subreq, struct tevent_req); >- struct wb_xids2sids_init_dom_maps_state *state = tevent_req_data( >- req, struct wb_xids2sids_init_dom_maps_state); >- enum lsa_SidType type; >- NTSTATUS status; >- >- status = wb_lookupname_recv(subreq, >- &dom_maps[state->dom_idx].sid, >- &type); >- TALLOC_FREE(subreq); >- if (!NT_STATUS_IS_OK(status)) { >- DBG_WARNING("Lookup domain name '%s' failed '%s'\n", >- dom_maps[state->dom_idx].name, >- nt_errstr(status)); >- >- state->dom_idx++; >- wb_xids2sids_init_dom_maps_lookupname_next(state); >- return; >- } >- >- if (type != SID_NAME_DOMAIN) { >- struct dom_sid_buf buf; >- >- DBG_WARNING("SID %s for idmap domain name '%s' " >- "not a domain SID\n", >- dom_sid_str_buf(&dom_maps[state->dom_idx].sid, >- &buf), >- dom_maps[state->dom_idx].name); >- >- ZERO_STRUCT(dom_maps[state->dom_idx].sid); >- } >- >- state->dom_idx++; >- wb_xids2sids_init_dom_maps_lookupname_next(state); >- >- return; >-} >- >-static NTSTATUS wb_xids2sids_init_dom_maps_recv(struct tevent_req *req) >-{ >- return tevent_req_simple_recv_ntstatus(req); >-} >- > struct wb_xids2sids_dom_state { > struct tevent_context *ev; > struct unixid *all_xids; > const bool *cached; > size_t num_all_xids; > struct dom_sid *all_sids; >- struct wb_xids2sids_dom_map *dom_map; >+ const struct wb_parent_idmap_config_dom *dom_map; > bool tried_dclookup; > > size_t num_dom_xids; >@@ -262,7 +44,7 @@ static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq); > > static struct tevent_req *wb_xids2sids_dom_send( > TALLOC_CTX *mem_ctx, struct tevent_context *ev, >- struct wb_xids2sids_dom_map *dom_map, >+ const struct wb_parent_idmap_config_dom *dom_map, > struct unixid *xids, > const bool *cached, > size_t num_xids, >@@ -334,7 +116,7 @@ static void wb_xids2sids_dom_done(struct tevent_req *subreq) > subreq, struct tevent_req); > struct wb_xids2sids_dom_state *state = tevent_req_data( > req, struct wb_xids2sids_dom_state); >- struct wb_xids2sids_dom_map *dom_map = state->dom_map; >+ const struct wb_parent_idmap_config_dom *dom_map = state->dom_map; > NTSTATUS status, result; > size_t i; > size_t dom_sid_idx; >@@ -437,10 +219,11 @@ struct wb_xids2sids_state { > bool *cached; > > size_t dom_idx; >+ const struct wb_parent_idmap_config *cfg; > }; > >+static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq); > static void wb_xids2sids_done(struct tevent_req *subreq); >-static void wb_xids2sids_init_dom_maps_done(struct tevent_req *subreq); > > struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx, > struct tevent_context *ev, >@@ -495,38 +278,32 @@ struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx, > } > } > >- subreq = wb_xids2sids_init_dom_maps_send( >- state, state->ev); >+ subreq = wb_parent_idmap_setup_send(state, state->ev); > if (tevent_req_nomem(subreq, req)) { > return tevent_req_post(req, ev); > } >- tevent_req_set_callback(subreq, wb_xids2sids_init_dom_maps_done, req); >+ tevent_req_set_callback(subreq, wb_xids2sids_idmap_setup_done, req); > return req; > } > >-static void wb_xids2sids_init_dom_maps_done(struct tevent_req *subreq) >+static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq) > { > struct tevent_req *req = tevent_req_callback_data( > subreq, struct tevent_req); > struct wb_xids2sids_state *state = tevent_req_data( > req, struct wb_xids2sids_state); >- size_t num_domains; > NTSTATUS status; > >- status = wb_xids2sids_init_dom_maps_recv(subreq); >+ status = wb_parent_idmap_setup_recv(subreq, &state->cfg); > TALLOC_FREE(subreq); > if (tevent_req_nterror(req, status)) { > return; > } >- >- num_domains = talloc_array_length(dom_maps); >- if (num_domains == 0) { >- tevent_req_done(req); >- return; >- } >+ SMB_ASSERT(state->cfg->num_doms > 0); > > subreq = wb_xids2sids_dom_send( >- state, state->ev, &dom_maps[state->dom_idx], >+ state, state->ev, >+ &state->cfg->doms[state->dom_idx], > state->xids, state->cached, state->num_xids, state->sids); > if (tevent_req_nomem(subreq, req)) { > return; >@@ -541,7 +318,6 @@ static void wb_xids2sids_done(struct tevent_req *subreq) > subreq, struct tevent_req); > struct wb_xids2sids_state *state = tevent_req_data( > req, struct wb_xids2sids_state); >- size_t num_domains = talloc_array_length(dom_maps); > size_t i; > NTSTATUS status; > >@@ -553,10 +329,13 @@ static void wb_xids2sids_done(struct tevent_req *subreq) > > state->dom_idx += 1; > >- if (state->dom_idx < num_domains) { >+ if (state->dom_idx < state->cfg->num_doms) { >+ const struct wb_parent_idmap_config_dom *dom_map = >+ &state->cfg->doms[state->dom_idx]; >+ > subreq = wb_xids2sids_dom_send(state, > state->ev, >- &dom_maps[state->dom_idx], >+ dom_map, > state->xids, > state->cached, > state->num_xids, >-- >2.25.1 > > >From 15ac37456c147bba4a41b25ab6c1f147a8adbd88 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 12:52:40 +0200 >Subject: [PATCH 031/262] CVE-2020-25717 wb_sids2xids: call > wb_parent_idmap_setup_send/recv as the first step > >This isn't really used yet, but it will in the next commits. > >Also idmap_child_handle() will soon assert that >wb_parent_idmap_setup_send/recv() was called before it's used. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit d42aaeba6e0820acd17f204ff7ab6d1aede1b303) >--- > source3/winbindd/wb_sids2xids.c | 34 +++++++++++++++++++++++++++++---- > 1 file changed, 30 insertions(+), 4 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index b47856520eac..59f6ba5891eb 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -29,6 +29,8 @@ > struct wb_sids2xids_state { > struct tevent_context *ev; > >+ const struct wb_parent_idmap_config *cfg; >+ > struct dom_sid *sids; > uint32_t num_sids; > >@@ -58,7 +60,7 @@ struct wb_sids2xids_state { > struct wbint_TransIDArray ids; > }; > >- >+static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq); > static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map); > static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq); > static void wb_sids2xids_done(struct tevent_req *subreq); >@@ -126,15 +128,39 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > return tevent_req_post(req, ev); > } > >- subreq = wb_lookupsids_send(state, ev, state->non_cached, >- state->num_non_cached); >+ subreq = wb_parent_idmap_setup_send(state, state->ev); > if (tevent_req_nomem(subreq, req)) { > return tevent_req_post(req, ev); > } >- tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req); >+ tevent_req_set_callback(subreq, wb_sids2xids_idmap_setup_done, req); > return req; > } > >+static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq) >+{ >+ struct tevent_req *req = tevent_req_callback_data( >+ subreq, struct tevent_req); >+ struct wb_sids2xids_state *state = tevent_req_data( >+ req, struct wb_sids2xids_state); >+ NTSTATUS status; >+ >+ status = wb_parent_idmap_setup_recv(subreq, &state->cfg); >+ TALLOC_FREE(subreq); >+ if (tevent_req_nterror(req, status)) { >+ return; >+ } >+ SMB_ASSERT(state->cfg->num_doms > 0); >+ >+ subreq = wb_lookupsids_send(state, >+ state->ev, >+ state->non_cached, >+ state->num_non_cached); >+ if (tevent_req_nomem(subreq, req)) { >+ return; >+ } >+ tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req); >+} >+ > static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map) > { > struct unixid id; >-- >2.25.1 > > >From 6964ab0dc732cc225ee069c27f4e27e0d86c4c4a Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 13:52:17 +0200 >Subject: [PATCH 032/262] CVE-2020-25717 wb_queryuser: explain why > wb_parent_idmap_setup_send/recv is not needed > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 82fd07793f065e150729848566e7c30f4f4d472e) >--- > source3/winbindd/wb_queryuser.c | 15 +++++++++++++++ > 1 file changed, 15 insertions(+) > >diff --git a/source3/winbindd/wb_queryuser.c b/source3/winbindd/wb_queryuser.c >index 2e36643454b7..9db51909c02c 100644 >--- a/source3/winbindd/wb_queryuser.c >+++ b/source3/winbindd/wb_queryuser.c >@@ -138,6 +138,11 @@ static void wb_queryuser_got_uid(struct tevent_req *subreq) > return; > } > >+ /* >+ * Note wb_sids2xids_send/recv was called before, >+ * so we're sure that wb_parent_idmap_setup_send/recv >+ * was already called. >+ */ > child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_GetNssInfo_send( > state, state->ev, child_binding_handle, info); >@@ -185,6 +190,11 @@ static void wb_queryuser_got_domain(struct tevent_req *subreq) > return; > } > >+ /* >+ * Note wb_sids2xids_send/recv was called before, >+ * so we're sure that wb_parent_idmap_setup_send/recv >+ * was already called. >+ */ > child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_GetNssInfo_send( > state, state->ev, child_binding_handle, info); >@@ -284,6 +294,11 @@ static void wb_queryuser_got_dc(struct tevent_req *subreq) > return; > } > >+ /* >+ * Note wb_sids2xids_send/recv was called before, >+ * so we're sure that wb_parent_idmap_setup_send/recv >+ * was already called. >+ */ > child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_GetNssInfo_send( > state, state->ev, child_binding_handle, info); >-- >2.25.1 > > >From 02eb0f4a53d7f22ebfc8b7e4439e0083fb887308 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 14:12:17 +0200 >Subject: [PATCH 033/262] CVE-2020-25717 winbindd: assert > wb_parent_idmap_setup_send/recv() was called before idmap_child_handle() > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit b8c74b7b46d1c7f6b66e565ee08f8c88d6dc2cc4) >--- > source3/winbindd/winbindd_idmap.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c >index 487f27fd94dd..14836e3b8a00 100644 >--- a/source3/winbindd/winbindd_idmap.c >+++ b/source3/winbindd/winbindd_idmap.c >@@ -59,6 +59,11 @@ pid_t idmap_child_pid(void) > > struct dcerpc_binding_handle *idmap_child_handle(void) > { >+ /* >+ * The caller needs to use wb_parent_idmap_setup_send/recv >+ * before talking to the idmap child! >+ */ >+ SMB_ASSERT(static_parent_idmap_config.num_doms > 0); > return static_idmap_child.binding_handle; > } > >-- >2.25.1 > > >From c920ba20f8fe4b4fec8d8aba8f32dad8d7bb58ea Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 15:42:42 +0200 >Subject: [PATCH 034/262] CVE-2020-25717 winbindd: defer the setup_child() from > init_idmap_child() > >At startup we trigger a wb_parent_idmap_setup_send() and make >sure setup_child() is called just before wb_parent_idmap_setup_recv() >finished. > >This makes sure our view of the idmap config in the parent matches >what we have in the child. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 28e020c0a863411cfa95e3b1ed943d922b8635bd) >--- > source3/winbindd/winbindd_idmap.c | 45 ++++++++++++++++++++++++++++--- > 1 file changed, 42 insertions(+), 3 deletions(-) > >diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c >index 14836e3b8a00..3e2461478a9f 100644 >--- a/source3/winbindd/winbindd_idmap.c >+++ b/source3/winbindd/winbindd_idmap.c >@@ -81,11 +81,44 @@ static const struct winbindd_child_dispatch_table idmap_dispatch_table[] = { > } > }; > >+static void init_idmap_child_done(struct tevent_req *subreq); >+ > void init_idmap_child(void) > { >- setup_child(NULL, &static_idmap_child, >- idmap_dispatch_table, >- "log.winbindd", "idmap"); >+ struct tevent_req *subreq = NULL; >+ >+ subreq = wb_parent_idmap_setup_send(global_event_context(), >+ global_event_context()); >+ if (subreq == NULL) { >+ /* >+ * This is only an optimization, so we're free to >+ * to ignore errors >+ */ >+ DBG_ERR("wb_parent_idmap_setup_send() failed\n"); >+ return; >+ } >+ tevent_req_set_callback(subreq, init_idmap_child_done, NULL); >+ DBG_DEBUG("wb_parent_idmap_setup_send() started\n"); >+} >+ >+static void init_idmap_child_done(struct tevent_req *subreq) >+{ >+ const struct wb_parent_idmap_config *cfg = NULL; >+ NTSTATUS status; >+ >+ status = wb_parent_idmap_setup_recv(subreq, &cfg); >+ TALLOC_FREE(subreq); >+ if (!NT_STATUS_IS_OK(status)) { >+ /* >+ * This is only an optimization, so we're free to >+ * to ignore errors >+ */ >+ DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n", >+ nt_errstr(status)); >+ return; >+ } >+ >+ DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n"); > } > > struct wb_parent_idmap_setup_state { >@@ -306,6 +339,12 @@ static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req) > > next_domain: > if (state->dom_idx == state->cfg->num_doms) { >+ /* >+ * We're done, so start the idmap child >+ */ >+ setup_child(NULL, &static_idmap_child, >+ idmap_dispatch_table, >+ "log.winbindd", "idmap"); > tevent_req_done(req); > return; > } >-- >2.25.1 > > >From 3201198831c44679bc1141156531509c0161951b Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Fri, 3 Jul 2020 16:39:26 +0200 >Subject: [PATCH 035/262] CVE-2020-25717 wb_sids2xids: split out > wb_sids2xids_next_sids2unix() > >Put the code that calls the per-domain idmap backend >in its own function. > >This makes further reconstruction easier. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> > >Signed-off-by: Ralph Boehme <slow@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 79c1d3aaf6d465a8edd1871edb85211f8715fea1) >--- > source3/winbindd/wb_sids2xids.c | 34 ++++++++++++--------------------- > 1 file changed, 12 insertions(+), 22 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index 59f6ba5891eb..725fd857ef5d 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -65,6 +65,7 @@ static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map); > static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq); > static void wb_sids2xids_done(struct tevent_req *subreq); > static void wb_sids2xids_gotdc(struct tevent_req *subreq); >+static void wb_sids2xids_next_sids2unix(struct tevent_req *req); > > struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > struct tevent_context *ev, >@@ -194,7 +195,6 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > req, struct wb_sids2xids_state); > struct lsa_RefDomainList *domains = NULL; > struct lsa_TransNameArray *names = NULL; >- struct dcerpc_binding_handle *child_binding_handle = NULL; > NTSTATUS status; > uint32_t i; > >@@ -264,6 +264,16 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > TALLOC_FREE(names); > TALLOC_FREE(domains); > >+ wb_sids2xids_next_sids2unix(req); >+} >+ >+static void wb_sids2xids_next_sids2unix(struct tevent_req *req) >+{ >+ struct wb_sids2xids_state *state = tevent_req_data( >+ req, struct wb_sids2xids_state); >+ struct tevent_req *subreq = NULL; >+ struct dcerpc_binding_handle *child_binding_handle = NULL; >+ > state->dom_ids = wb_sids2xids_extract_for_domain_index( > state, &state->ids, state->dom_index); > if (tevent_req_nomem(state->dom_ids, req)) { >@@ -315,7 +325,6 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > struct wb_sids2xids_state *state = tevent_req_data( > req, struct wb_sids2xids_state); > NTSTATUS status, result; >- struct dcerpc_binding_handle *child_binding_handle = NULL; > struct wbint_TransIDArray *src, *dst; > uint32_t i, src_idx; > >@@ -376,26 +385,7 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > return; > } > >- state->dom_ids = wb_sids2xids_extract_for_domain_index( >- state, &state->ids, state->dom_index); >- if (tevent_req_nomem(state->dom_ids, req)) { >- return; >- } >- >- state->idmap_dom = (struct lsa_RefDomainList) { >- .count = 1, >- .domains = &state->idmap_doms.domains[state->dom_index], >- .max_size = 1 >- }; >- >- child_binding_handle = idmap_child_handle(); >- subreq = dcerpc_wbint_Sids2UnixIDs_send( >- state, state->ev, child_binding_handle, &state->idmap_dom, >- state->dom_ids); >- if (tevent_req_nomem(subreq, req)) { >- return; >- } >- tevent_req_set_callback(subreq, wb_sids2xids_done, req); >+ wb_sids2xids_next_sids2unix(req); > } > > static void wb_sids2xids_gotdc(struct tevent_req *subreq) >-- >2.25.1 > > >From a64717086496bbfc4d29df32db75b8fb29b83fa0 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Thu, 10 Sep 2020 16:45:03 +0200 >Subject: [PATCH 036/262] CVE-2020-25717 wb_sids2xids: maintain struct > wbint_TransIDArray all_ids as cache > >Entries with domain_index == UINT32_MAX are valid cache entries. > >In the following commits we'll fill in missing entries step by step >until all entries are marked as filled. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 04956350a5725325954b2caba662ecd6dace7829) >--- > source3/winbindd/wb_sids2xids.c | 49 ++++++++++++++++++++++++++++----- > 1 file changed, 42 insertions(+), 7 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index 725fd857ef5d..770a7f0d8b00 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -34,7 +34,7 @@ struct wb_sids2xids_state { > struct dom_sid *sids; > uint32_t num_sids; > >- struct id_map *cached; >+ struct wbint_TransIDArray all_ids; > > struct dom_sid *non_cached; > uint32_t num_non_cached; >@@ -75,6 +75,7 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > struct tevent_req *req, *subreq; > struct wb_sids2xids_state *state; > uint32_t i; >+ uint32_t num_valid = 0; > > req = tevent_req_create(mem_ctx, &state, > struct wb_sids2xids_state); >@@ -95,8 +96,9 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > sid_copy(&state->sids[i], &sids[i]); > } > >- state->cached = talloc_zero_array(state, struct id_map, num_sids); >- if (tevent_req_nomem(state->cached, req)) { >+ state->all_ids.num_ids = num_sids; >+ state->all_ids.ids = talloc_zero_array(state, struct wbint_TransID, num_sids); >+ if (tevent_req_nomem(state->all_ids.ids, req)) { > return tevent_req_post(req, ev); > } > >@@ -111,20 +113,53 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > * the same index. > */ > for (i=0; i<state->num_sids; i++) { >+ struct wbint_TransID *cur_id = &state->all_ids.ids[i]; >+ struct dom_sid domain_sid; > struct dom_sid_buf buf; >+ struct id_map map = { .status = ID_UNMAPPED, }; >+ uint32_t rid = 0; >+ bool in_cache; >+ >+ sid_copy(&domain_sid, &state->sids[i]); >+ sid_split_rid(&domain_sid, &rid); >+ >+ /* >+ * Start with an invalid entry. >+ */ >+ *cur_id = (struct wbint_TransID) { >+ .type_hint = ID_TYPE_NOT_SPECIFIED, >+ .domain_index = UINT32_MAX - 1, /* invalid */ >+ .rid = rid, >+ .xid = { >+ .id = UINT32_MAX, >+ .type = ID_TYPE_NOT_SPECIFIED, >+ }, >+ }; > > DEBUG(10, ("SID %d: %s\n", (int)i, > dom_sid_str_buf(&state->sids[i], &buf))); > >- if (wb_sids2xids_in_cache(&state->sids[i], &state->cached[i])) { >+ in_cache = wb_sids2xids_in_cache(&state->sids[i], &map); >+ if (in_cache) { >+ /* >+ * We used to ignore map.status and just rely >+ * on map.xid.type. >+ * >+ * Lets keep this logic for now... >+ */ >+ >+ cur_id->xid = map.xid; >+ cur_id->domain_index = UINT32_MAX; /* this marks it as filled entry */ >+ num_valid += 1; > continue; > } >+ > sid_copy(&state->non_cached[state->num_non_cached], > &state->sids[i]); > state->num_non_cached += 1; > } > >- if (state->num_non_cached == 0) { >+ if (num_valid == num_sids) { > tevent_req_done(req); > return tevent_req_post(req, ev); > } >@@ -453,8 +488,8 @@ NTSTATUS wb_sids2xids_recv(struct tevent_req *req, > > xid.id = UINT32_MAX; > >- if (state->cached[i].sid != NULL) { >- xid = state->cached[i].xid; >+ if (state->all_ids.ids[i].domain_index == UINT32_MAX) { >+ xid = state->all_ids.ids[i].xid; > } else { > xid = state->ids.ids[num_non_cached].xid; > >-- >2.25.1 > > >From 5225c3609b3620239e67ea036ba096b0ecdf7dea Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Thu, 10 Sep 2020 17:45:24 +0200 >Subject: [PATCH 037/262] CVE-2020-25717 wb_sids2xids: rename 'non_cached' to > 'lookup_sids' > >This array is used to pass to wb_lookupsids_send() >and that will be the only reason to have this in future. > >For now it's used for all non cached sids, but that will >also change in the next commits. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 797b11f198e819300007997ce536bc6d05f19843) >--- > source3/winbindd/wb_sids2xids.c | 34 ++++++++++++++++----------------- > 1 file changed, 16 insertions(+), 18 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index 770a7f0d8b00..2a30eee2c7b1 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -36,8 +36,8 @@ struct wb_sids2xids_state { > > struct wbint_TransIDArray all_ids; > >- struct dom_sid *non_cached; >- uint32_t num_non_cached; >+ uint32_t lookup_count; >+ struct dom_sid *lookup_sids; > > /* > * Domain array to use for the idmap call. The output from >@@ -102,8 +102,8 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > return tevent_req_post(req, ev); > } > >- state->non_cached = talloc_array(state, struct dom_sid, num_sids); >- if (tevent_req_nomem(state->non_cached, req)) { >+ state->lookup_sids = talloc_zero_array(state, struct dom_sid, num_sids); >+ if (tevent_req_nomem(state->lookup_sids, req)) { > return tevent_req_post(req, ev); > } > >@@ -154,9 +154,9 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > continue; > } > >- sid_copy(&state->non_cached[state->num_non_cached], >+ sid_copy(&state->lookup_sids[state->lookup_count], > &state->sids[i]); >- state->num_non_cached += 1; >+ state->lookup_count += 1; > } > > if (num_valid == num_sids) { >@@ -189,8 +189,8 @@ static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq) > > subreq = wb_lookupsids_send(state, > state->ev, >- state->non_cached, >- state->num_non_cached); >+ state->lookup_sids, >+ state->lookup_count); > if (tevent_req_nomem(subreq, req)) { > return; > } >@@ -239,15 +239,15 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > return; > } > >- state->ids.num_ids = state->num_non_cached; >+ state->ids.num_ids = state->lookup_count; > state->ids.ids = talloc_array(state, struct wbint_TransID, >- state->num_non_cached); >+ state->ids.num_ids); > if (tevent_req_nomem(state->ids.ids, req)) { > return; > } > >- for (i=0; i<state->num_non_cached; i++) { >- const struct dom_sid *sid = &state->non_cached[i]; >+ for (i=0; i<state->lookup_count; i++) { >+ const struct dom_sid *sid = &state->lookup_sids[i]; > struct dom_sid dom_sid; > struct lsa_TranslatedName *n = &names->names[i]; > struct wbint_TransID *t = &state->ids.ids[i]; >@@ -468,7 +468,7 @@ NTSTATUS wb_sids2xids_recv(struct tevent_req *req, > struct wb_sids2xids_state *state = tevent_req_data( > req, struct wb_sids2xids_state); > NTSTATUS status; >- uint32_t i, num_non_cached; >+ uint32_t i, lookup_count = 0; > > if (tevent_req_is_nterror(req, &status)) { > DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status))); >@@ -481,8 +481,6 @@ NTSTATUS wb_sids2xids_recv(struct tevent_req *req, > return NT_STATUS_INTERNAL_ERROR; > } > >- num_non_cached = 0; >- > for (i=0; i<state->num_sids; i++) { > struct unixid xid; > >@@ -491,13 +489,13 @@ NTSTATUS wb_sids2xids_recv(struct tevent_req *req, > if (state->all_ids.ids[i].domain_index == UINT32_MAX) { > xid = state->all_ids.ids[i].xid; > } else { >- xid = state->ids.ids[num_non_cached].xid; >+ xid = state->ids.ids[lookup_count].xid; > > idmap_cache_set_sid2unixid( >- &state->non_cached[num_non_cached], >+ &state->lookup_sids[lookup_count], > &xid); > >- num_non_cached += 1; >+ lookup_count += 1; > } > > xids[i] = xid; >-- >2.25.1 > > >From 41ec8338ebc20c6a11eaf1d4fb6c5a3951c8b94e Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 15 Sep 2020 13:19:14 +0200 >Subject: [PATCH 038/262] CVE-2020-25717 wb_sids2xids: move more checks to > wb_sids2xids_next_sids2unix() > >For the first run this is a no-op, but it simplified the caller. > >We'll call wb_sids2xids_next_sids2unix() in a few more places in future >and it's easier to have this all within wb_sids2xids_next_sids2unix(). > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 231c8d04b19a1c17937f988d142ca5c0f889d4e0) >--- > source3/winbindd/wb_sids2xids.c | 13 +++++++------ > 1 file changed, 7 insertions(+), 6 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index 2a30eee2c7b1..b934425f4fd6 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -309,6 +309,13 @@ static void wb_sids2xids_next_sids2unix(struct tevent_req *req) > struct tevent_req *subreq = NULL; > struct dcerpc_binding_handle *child_binding_handle = NULL; > >+ state->tried_dclookup = false; >+ >+ if (state->dom_index == state->idmap_doms.count) { >+ tevent_req_done(req); >+ return; >+ } >+ > state->dom_ids = wb_sids2xids_extract_for_domain_index( > state, &state->ids, state->dom_index); > if (tevent_req_nomem(state->dom_ids, req)) { >@@ -413,12 +420,6 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > TALLOC_FREE(state->dom_ids); > > state->dom_index += 1; >- state->tried_dclookup = false; >- >- if (state->dom_index == state->idmap_doms.count) { >- tevent_req_done(req); >- return; >- } > > wb_sids2xids_next_sids2unix(req); > } >-- >2.25.1 > > >From d14b9ab41511b9bc1c51ddb159ace24f47f67a0a Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 15 Sep 2020 13:36:43 +0200 >Subject: [PATCH 039/262] CVE-2020-25717 wb_sids2xids: inline > wb_sids2xids_extract_for_domain_index() into wb_sids2xids_next_sids2unix() > >Instead of re-creating the dom_ids element, >we just use a pre-allocated map_ids_in array. > >This is a bit tricky as we need to use map_ids_out as a copy of >map_ids_in, because the _ids argument of dcerpc_wbint_Sids2UnixIDs_send() >in [in,out], which means that _ids->ids is changed between >dcerpc_wbint_Sids2UnixIDs_send() and dcerpc_wbint_Sids2UnixIDs_recv()! > >If the domain doesn't need any mappings, we'll move to the next domain >early, for now this can't happend but it will in future. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit f6bb0ed21f82f2cf1f238f9f00cd049ecf8673af) >--- > source3/winbindd/wb_sids2xids.c | 115 +++++++++++++++++++++----------- > 1 file changed, 75 insertions(+), 40 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index b934425f4fd6..aefb9f93ccb4 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -39,6 +39,9 @@ struct wb_sids2xids_state { > uint32_t lookup_count; > struct dom_sid *lookup_sids; > >+ struct wbint_TransIDArray map_ids_in; >+ struct wbint_TransIDArray map_ids_out; >+ > /* > * Domain array to use for the idmap call. The output from > * lookupsids cannot be used directly since for migrated >@@ -53,7 +56,6 @@ struct wb_sids2xids_state { > struct lsa_RefDomainList idmap_doms; > > uint32_t dom_index; >- struct wbint_TransIDArray *dom_ids; > struct lsa_RefDomainList idmap_dom; > bool tried_dclookup; > >@@ -107,6 +109,11 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > return tevent_req_post(req, ev); > } > >+ state->map_ids_in.ids = talloc_zero_array(state, struct wbint_TransID, num_sids); >+ if (tevent_req_nomem(state->map_ids_in.ids, req)) { >+ return tevent_req_post(req, ev); >+ } >+ > /* > * Extract those sids that can not be resolved from cache > * into a separate list to be handed to id mapping, keeping >@@ -218,9 +225,6 @@ static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map) > } > > static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type); >-static struct wbint_TransIDArray *wb_sids2xids_extract_for_domain_index( >- TALLOC_CTX *mem_ctx, const struct wbint_TransIDArray *src, >- uint32_t domain_index); > > static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > { >@@ -308,7 +312,11 @@ static void wb_sids2xids_next_sids2unix(struct tevent_req *req) > req, struct wb_sids2xids_state); > struct tevent_req *subreq = NULL; > struct dcerpc_binding_handle *child_binding_handle = NULL; >+ const struct wbint_TransIDArray *src = NULL; >+ struct wbint_TransIDArray *dst = NULL; >+ uint32_t si; > >+ next_domain: > state->tried_dclookup = false; > > if (state->dom_index == state->idmap_doms.count) { >@@ -316,10 +324,23 @@ static void wb_sids2xids_next_sids2unix(struct tevent_req *req) > return; > } > >- state->dom_ids = wb_sids2xids_extract_for_domain_index( >- state, &state->ids, state->dom_index); >- if (tevent_req_nomem(state->dom_ids, req)) { >- return; >+ src = &state->ids; >+ dst = &state->map_ids_in; >+ dst->num_ids = 0; >+ >+ for (si=0; si < src->num_ids; si++) { >+ if (src->ids[si].domain_index != state->dom_index) { >+ continue; >+ } >+ >+ dst->ids[dst->num_ids] = src->ids[si]; >+ dst->ids[dst->num_ids].domain_index = 0; >+ dst->num_ids += 1; >+ } >+ >+ if (dst->num_ids == 0) { >+ state->dom_index += 1; >+ goto next_domain; > } > > state->idmap_dom = (struct lsa_RefDomainList) { >@@ -328,10 +349,23 @@ static void wb_sids2xids_next_sids2unix(struct tevent_req *req) > .max_size = 1 > }; > >+ /* >+ * dcerpc_wbint_Sids2UnixIDs_send/recv will >+ * allocate a new array for the response >+ * and overwrite _ids->ids pointer. >+ * >+ * So we better make a temporary copy >+ * of state->map_ids_in (which contains the request array) >+ * into state->map_ids_out. >+ * >+ * That makes it possible to reuse the pre-allocated >+ * state->map_ids_in.ids array. >+ */ >+ state->map_ids_out = state->map_ids_in; > child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_Sids2UnixIDs_send( > state, state->ev, child_binding_handle, &state->idmap_dom, >- state->dom_ids); >+ &state->map_ids_out); > if (tevent_req_nomem(subreq, req)) { > return; > } >@@ -394,7 +428,7 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > return; > } > >- src = state->dom_ids; >+ src = &state->map_ids_out; > src_idx = 0; > dst = &state->ids; > >@@ -405,11 +439,17 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > /* > * All we can do here is to report "not mapped" > */ >+ src = &state->map_ids_in; > for (i=0; i<src->num_ids; i++) { > src->ids[i].xid.type = ID_TYPE_NOT_SPECIFIED; > } > } > >+ if (src->num_ids != state->map_ids_in.num_ids) { >+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >+ return; >+ } >+ > for (i=0; i<dst->num_ids; i++) { > if (dst->ids[i].domain_index == state->dom_index) { > dst->ids[i].xid = src->ids[src_idx].xid; >@@ -417,7 +457,17 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > } > } > >- TALLOC_FREE(state->dom_ids); >+ state->map_ids_in.num_ids = 0; >+ if (NT_STATUS_IS_OK(status)) { >+ /* >+ * If we got a valid response, we expect >+ * state->map_ids_out.ids to be a new allocated >+ * array, which we want to free early. >+ */ >+ SMB_ASSERT(state->map_ids_out.ids != state->map_ids_in.ids); >+ TALLOC_FREE(state->map_ids_out.ids); >+ } >+ state->map_ids_out = (struct wbint_TransIDArray) { .num_ids = 0, }; > > state->dom_index += 1; > >@@ -453,10 +503,23 @@ static void wb_sids2xids_gotdc(struct tevent_req *subreq) > } > } > >+ /* >+ * dcerpc_wbint_Sids2UnixIDs_send/recv will >+ * allocate a new array for the response >+ * and overwrite _ids->ids pointer. >+ * >+ * So we better make a temporary copy >+ * of state->map_ids_in (which contains the request array) >+ * into state->map_ids_out. >+ * >+ * That makes it possible to reuse the pre-allocated >+ * state->map_ids_in.ids array. >+ */ >+ state->map_ids_out = state->map_ids_in; > child_binding_handle = idmap_child_handle(); > subreq = dcerpc_wbint_Sids2UnixIDs_send( > state, state->ev, child_binding_handle, &state->idmap_dom, >- state->dom_ids); >+ &state->map_ids_out); > if (tevent_req_nomem(subreq, req)) { > return; > } >@@ -504,31 +567,3 @@ NTSTATUS wb_sids2xids_recv(struct tevent_req *req, > > return NT_STATUS_OK; > } >- >-static struct wbint_TransIDArray *wb_sids2xids_extract_for_domain_index( >- TALLOC_CTX *mem_ctx, const struct wbint_TransIDArray *src, >- uint32_t domain_index) >-{ >- struct wbint_TransIDArray *ret; >- uint32_t i; >- >- ret = talloc_zero(mem_ctx, struct wbint_TransIDArray); >- if (ret == NULL) { >- return NULL; >- } >- ret->ids = talloc_array(ret, struct wbint_TransID, src->num_ids); >- if (ret->ids == NULL) { >- TALLOC_FREE(ret); >- return NULL; >- } >- >- for (i=0; i<src->num_ids; i++) { >- if (src->ids[i].domain_index == domain_index) { >- ret->ids[ret->num_ids] = src->ids[i]; >- ret->ids[ret->num_ids].domain_index = 0; >- ret->num_ids += 1; >- } >- } >- >- return ret; >-} >-- >2.25.1 > > >From 8b3a6c95e8d548f64b5e3df7036cc26f9ce53a92 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 15 Sep 2020 13:54:24 +0200 >Subject: [PATCH 040/262] CVE-2020-25717 wb_sids2xids: refactor > wb_sids2xids_done() a bit > >Here we don't change the logic. > >It will make the following changes easier. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit cda61f592a0b33d36da8da9b6837312396cceec4) >--- > source3/winbindd/wb_sids2xids.c | 27 ++++++++++++++++++--------- > 1 file changed, 18 insertions(+), 9 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index aefb9f93ccb4..d6655402b57c 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -401,8 +401,10 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > struct wb_sids2xids_state *state = tevent_req_data( > req, struct wb_sids2xids_state); > NTSTATUS status, result; >- struct wbint_TransIDArray *src, *dst; >- uint32_t i, src_idx; >+ const struct wbint_TransIDArray *src = NULL; >+ struct wbint_TransIDArray *dst = NULL; >+ uint32_t si; >+ uint32_t di; > > status = dcerpc_wbint_Sids2UnixIDs_recv(subreq, state, &result); > TALLOC_FREE(subreq); >@@ -429,7 +431,6 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > } > > src = &state->map_ids_out; >- src_idx = 0; > dst = &state->ids; > > if (any_nt_status_not_ok(status, result, &status)) { >@@ -440,8 +441,8 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > * All we can do here is to report "not mapped" > */ > src = &state->map_ids_in; >- for (i=0; i<src->num_ids; i++) { >- src->ids[i].xid.type = ID_TYPE_NOT_SPECIFIED; >+ for (si=0; si < src->num_ids; si++) { >+ src->ids[si].xid.type = ID_TYPE_NOT_SPECIFIED; > } > } > >@@ -450,11 +451,19 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > return; > } > >- for (i=0; i<dst->num_ids; i++) { >- if (dst->ids[i].domain_index == state->dom_index) { >- dst->ids[i].xid = src->ids[src_idx].xid; >- src_idx += 1; >+ si = 0; >+ for (di=0; di < dst->num_ids; di++) { >+ if (dst->ids[di].domain_index != state->dom_index) { >+ continue; >+ } >+ >+ if (si >= src->num_ids) { >+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >+ return; > } >+ >+ dst->ids[di].xid = src->ids[si].xid; >+ si += 1; > } > > state->map_ids_in.num_ids = 0; >-- >2.25.1 > > >From 7aef9ce0e316f0742cf808e00fd836d520a6a83b Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 15 Sep 2020 13:58:26 +0200 >Subject: [PATCH 041/262] CVE-2020-25717 wb_sids2xids: change 'i' to 'li' in > wb_sids2xids_lookupsids_done() > >With all the indexes we have into various array, this makes clear >'li' is the index into the state->lookup_sids array. > >This makes the following changes easier to review. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 19c8b6a8b188e45a6342a3d1308085800388a38e) >--- > source3/winbindd/wb_sids2xids.c | 10 +++++----- > 1 file changed, 5 insertions(+), 5 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index d6655402b57c..f01e36e6e55a 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -235,7 +235,7 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > struct lsa_RefDomainList *domains = NULL; > struct lsa_TransNameArray *names = NULL; > NTSTATUS status; >- uint32_t i; >+ uint32_t li; > > status = wb_lookupsids_recv(subreq, state, &domains, &names); > TALLOC_FREE(subreq); >@@ -250,11 +250,11 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > return; > } > >- for (i=0; i<state->lookup_count; i++) { >- const struct dom_sid *sid = &state->lookup_sids[i]; >+ for (li = 0; li < state->lookup_count; li++) { >+ const struct dom_sid *sid = &state->lookup_sids[li]; > struct dom_sid dom_sid; >- struct lsa_TranslatedName *n = &names->names[i]; >- struct wbint_TransID *t = &state->ids.ids[i]; >+ struct lsa_TranslatedName *n = &names->names[li]; >+ struct wbint_TransID *t = &state->ids.ids[li]; > int domain_index; > const char *domain_name = NULL; > >-- >2.25.1 > > >From 6d264a2748369b1c53aea84b18e8a093f87eeddd Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 15 Sep 2020 14:17:37 +0200 >Subject: [PATCH 042/262] CVE-2020-25717 wb_sids2xids: directly use > state->all_ids to collect results > >In order to translate the indexes from state->lookup_sids[] >for wb_lookupsids_send/recv() and state->map_ids.ids[] >for dcerpc_wbint_Sids2UnixIDs_send/recv() back to >state->all_ids.ids[] or state->sids[] we have state->tmp_idx[]. > >This simplifies wb_sids2xids_recv() a lot and make further >restructuring much easier. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 374acc2e5fcc3c4b40f41906d0349499e3304841) >--- > source3/winbindd/wb_sids2xids.c | 66 +++++++++++---------------------- > 1 file changed, 22 insertions(+), 44 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index f01e36e6e55a..cdbc70a0b498 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -36,6 +36,9 @@ struct wb_sids2xids_state { > > struct wbint_TransIDArray all_ids; > >+ /* Used to translated the idx back into all_ids.ids[idx] */ >+ uint32_t *tmp_idx; >+ > uint32_t lookup_count; > struct dom_sid *lookup_sids; > >@@ -58,8 +61,6 @@ struct wb_sids2xids_state { > uint32_t dom_index; > struct lsa_RefDomainList idmap_dom; > bool tried_dclookup; >- >- struct wbint_TransIDArray ids; > }; > > static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq); >@@ -104,6 +105,11 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > return tevent_req_post(req, ev); > } > >+ state->tmp_idx = talloc_zero_array(state, uint32_t, num_sids); >+ if (tevent_req_nomem(state->tmp_idx, req)) { >+ return tevent_req_post(req, ev); >+ } >+ > state->lookup_sids = talloc_zero_array(state, struct dom_sid, num_sids); > if (tevent_req_nomem(state->lookup_sids, req)) { > return tevent_req_post(req, ev); >@@ -161,6 +167,7 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > continue; > } > >+ state->tmp_idx[state->lookup_count] = i; > sid_copy(&state->lookup_sids[state->lookup_count], > &state->sids[i]); > state->lookup_count += 1; >@@ -243,18 +250,12 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > return; > } > >- state->ids.num_ids = state->lookup_count; >- state->ids.ids = talloc_array(state, struct wbint_TransID, >- state->ids.num_ids); >- if (tevent_req_nomem(state->ids.ids, req)) { >- return; >- } >- > for (li = 0; li < state->lookup_count; li++) { > const struct dom_sid *sid = &state->lookup_sids[li]; > struct dom_sid dom_sid; > struct lsa_TranslatedName *n = &names->names[li]; >- struct wbint_TransID *t = &state->ids.ids[li]; >+ uint32_t ai = state->tmp_idx[li]; >+ struct wbint_TransID *t = &state->all_ids.ids[ai]; > int domain_index; > const char *domain_name = NULL; > >@@ -295,9 +296,6 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > return; > } > t->domain_index = domain_index; >- >- t->xid.id = UINT32_MAX; >- t->xid.type = ID_TYPE_NOT_SPECIFIED; > } > > TALLOC_FREE(names); >@@ -324,7 +322,7 @@ static void wb_sids2xids_next_sids2unix(struct tevent_req *req) > return; > } > >- src = &state->ids; >+ src = &state->all_ids; > dst = &state->map_ids_in; > dst->num_ids = 0; > >@@ -333,6 +331,7 @@ static void wb_sids2xids_next_sids2unix(struct tevent_req *req) > continue; > } > >+ state->tmp_idx[dst->num_ids] = si; > dst->ids[dst->num_ids] = src->ids[si]; > dst->ids[dst->num_ids].domain_index = 0; > dst->num_ids += 1; >@@ -404,7 +403,6 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > const struct wbint_TransIDArray *src = NULL; > struct wbint_TransIDArray *dst = NULL; > uint32_t si; >- uint32_t di; > > status = dcerpc_wbint_Sids2UnixIDs_recv(subreq, state, &result); > TALLOC_FREE(subreq); >@@ -431,7 +429,7 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > } > > src = &state->map_ids_out; >- dst = &state->ids; >+ dst = &state->all_ids; > > if (any_nt_status_not_ok(status, result, &status)) { > DBG_DEBUG("status=%s, result=%s\n", nt_errstr(status), >@@ -451,19 +449,12 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > return; > } > >- si = 0; >- for (di=0; di < dst->num_ids; di++) { >- if (dst->ids[di].domain_index != state->dom_index) { >- continue; >- } >+ for (si=0; si < src->num_ids; si++) { >+ uint32_t di = state->tmp_idx[si]; > >- if (si >= src->num_ids) { >- tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >- return; >+ if (src->ids[si].xid.type != ID_TYPE_NOT_SPECIFIED) { >+ dst->ids[di].xid = src->ids[si].xid; > } >- >- dst->ids[di].xid = src->ids[si].xid; >- si += 1; > } > > state->map_ids_in.num_ids = 0; >@@ -541,7 +532,7 @@ NTSTATUS wb_sids2xids_recv(struct tevent_req *req, > struct wb_sids2xids_state *state = tevent_req_data( > req, struct wb_sids2xids_state); > NTSTATUS status; >- uint32_t i, lookup_count = 0; >+ uint32_t i; > > if (tevent_req_is_nterror(req, &status)) { > DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status))); >@@ -555,23 +546,10 @@ NTSTATUS wb_sids2xids_recv(struct tevent_req *req, > } > > for (i=0; i<state->num_sids; i++) { >- struct unixid xid; >- >- xid.id = UINT32_MAX; >- >- if (state->all_ids.ids[i].domain_index == UINT32_MAX) { >- xid = state->all_ids.ids[i].xid; >- } else { >- xid = state->ids.ids[lookup_count].xid; >- >- idmap_cache_set_sid2unixid( >- &state->lookup_sids[lookup_count], >- &xid); >- >- lookup_count += 1; >+ xids[i] = state->all_ids.ids[i].xid; >+ if (state->all_ids.ids[i].domain_index != UINT32_MAX) { >+ idmap_cache_set_sid2unixid(&state->sids[i], &xids[i]); > } >- >- xids[i] = xid; > } > > return NT_STATUS_OK; >-- >2.25.1 > > >From 2528668c245609e016bff15ec55f099549395aa7 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Thu, 10 Sep 2020 23:06:02 +0200 >Subject: [PATCH 043/262] CVE-2020-25717 wb_sids2xids: fill cache as soon as > possible > >After adding entries to the cache we can mark them >as filled from the cache by setting its domain_index >to UINT32_MAX. > >This will allow further changes to fill the results >into state->all_ids in steps. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 3f4626ea6d235470195918b77af35ac2cfeb227c) >--- > source3/winbindd/wb_sids2xids.c | 5 ++--- > 1 file changed, 2 insertions(+), 3 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index cdbc70a0b498..21bf5f901f3d 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -455,6 +455,8 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > if (src->ids[si].xid.type != ID_TYPE_NOT_SPECIFIED) { > dst->ids[di].xid = src->ids[si].xid; > } >+ dst->ids[di].domain_index = UINT32_MAX; /* mark as valid */ >+ idmap_cache_set_sid2unixid(&state->sids[di], &dst->ids[di].xid); > } > > state->map_ids_in.num_ids = 0; >@@ -547,9 +549,6 @@ NTSTATUS wb_sids2xids_recv(struct tevent_req *req, > > for (i=0; i<state->num_sids; i++) { > xids[i] = state->all_ids.ids[i].xid; >- if (state->all_ids.ids[i].domain_index != UINT32_MAX) { >- idmap_cache_set_sid2unixid(&state->sids[i], &xids[i]); >- } > } > > return NT_STATUS_OK; >-- >2.25.1 > > >From 6f39c5fbc2512b00d9789938b4f61b9fd2422b7c Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Thu, 10 Sep 2020 17:13:14 +0200 >Subject: [PATCH 044/262] CVE-2020-25717 wb_sids2xids: build state->idmap_doms > based on wb_parent_idmap_config > >In future we'll try to avoid wb_lookupsids_send() and only call >it if needed. > >The domain name passed should be only relevant to find the correct >idmap backend, and these should all be available in >wb_parent_idmap_config as it was created before the idmap child was forked. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit c55f4f37589130a0d8952489da175bbcf53f6748) >--- > source3/winbindd/wb_sids2xids.c | 101 +++++++++++++++++++------------- > 1 file changed, 61 insertions(+), 40 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index 21bf5f901f3d..3a3d47abbe55 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -193,6 +193,7 @@ static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq) > struct wb_sids2xids_state *state = tevent_req_data( > req, struct wb_sids2xids_state); > NTSTATUS status; >+ uint32_t i; > > status = wb_parent_idmap_setup_recv(subreq, &state->cfg); > TALLOC_FREE(subreq); >@@ -201,6 +202,66 @@ static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq) > } > SMB_ASSERT(state->cfg->num_doms > 0); > >+ /* >+ * Now we build a list with all domain >+ * with non cached entries >+ */ >+ for (i=0; i<state->num_sids; i++) { >+ struct wbint_TransID *t = &state->all_ids.ids[i]; >+ struct dom_sid domain_sid; >+ const char *domain_name = NULL; >+ int domain_index; >+ uint32_t rid = 0; >+ uint32_t di; >+ >+ if (t->domain_index == UINT32_MAX) { >+ /* ignore already filled entries */ >+ continue; >+ } >+ >+ sid_copy(&domain_sid, &state->sids[i]); >+ sid_split_rid(&domain_sid, &rid); >+ >+ for (di = 0; di < state->cfg->num_doms; di++) { >+ struct wb_parent_idmap_config_dom *dom = >+ &state->cfg->doms[di]; >+ bool match; >+ >+ match = dom_sid_equal(&domain_sid, >+ &dom->sid); >+ if (!match) { >+ continue; >+ } >+ >+ domain_name = dom->name; >+ break; >+ } >+ if (domain_name == NULL) { >+ struct winbindd_domain *wb_domain = NULL; >+ >+ /* >+ * Try to fill the name if we already know it >+ */ >+ wb_domain = find_domain_from_sid_noinit(&state->sids[i]); >+ if (wb_domain != NULL) { >+ domain_name = wb_domain->name; >+ } >+ } >+ if (domain_name == NULL) { >+ domain_name = ""; >+ } >+ >+ domain_index = init_lsa_ref_domain_list(state, >+ &state->idmap_doms, >+ domain_name, >+ &domain_sid); >+ if (domain_index == -1) { >+ tevent_req_oom(req); >+ return; >+ } >+ t->domain_index = domain_index; >+ } >+ > subreq = wb_lookupsids_send(state, > state->ev, > state->lookup_sids, >@@ -251,51 +312,11 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > } > > for (li = 0; li < state->lookup_count; li++) { >- const struct dom_sid *sid = &state->lookup_sids[li]; >- struct dom_sid dom_sid; > struct lsa_TranslatedName *n = &names->names[li]; > uint32_t ai = state->tmp_idx[li]; > struct wbint_TransID *t = &state->all_ids.ids[ai]; >- int domain_index; >- const char *domain_name = NULL; >- >- if (n->sid_index != UINT32_MAX) { >- const struct lsa_DomainInfo *info; >- bool match; >- >- info = &domains->domains[n->sid_index]; >- match = dom_sid_in_domain(info->sid, sid); >- if (match) { >- domain_name = info->name.string; >- } >- } >- if (domain_name == NULL) { >- struct winbindd_domain *wb_domain = NULL; >- >- /* >- * This is needed to handle Samba DCs >- * which always return sid_index == UINT32_MAX for >- * unknown sids. >- */ >- wb_domain = find_domain_from_sid_noinit(sid); >- if (wb_domain != NULL) { >- domain_name = wb_domain->name; >- } >- } >- if (domain_name == NULL) { >- domain_name = ""; >- } > >- sid_copy(&dom_sid, sid); >- sid_split_rid(&dom_sid, &t->rid); > t->type_hint = lsa_SidType_to_id_type(n->sid_type); >- domain_index = init_lsa_ref_domain_list( >- state, &state->idmap_doms, domain_name, &dom_sid); >- if (domain_index == -1) { >- tevent_req_oom(req); >- return; >- } >- t->domain_index = domain_index; > } > > TALLOC_FREE(names); >-- >2.25.1 > > >From f34b3a38cc6f81267e5ae962bcdaa32fb3eaf6f4 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 15 Sep 2020 17:26:11 +0200 >Subject: [PATCH 045/262] CVE-2020-25717 winbindd: allow idmap backends to mark > entries with ID_[TYPE_WB_]REQUIRE_TYPE > >This must only be used between winbindd parent and child! >It must not leak into outside world. > >Some backends require ID_TYPE_UID or ID_TYPE_GID as type_hint, >while others may only need ID_TYPE_BOTH in order to validate that >the domain exists. > >This will allow us to skip the wb_lookupsids_send/recv in the winbindd parent >in future and only do that on demand. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 493f5d6b078e0b0f80d1ef25043e2834cb4fcb87) >--- > librpc/idl/idmap.idl | 23 +++++++++++++++++-- > source3/passdb/lookup_sid.c | 7 ++++++ > source3/winbindd/idmap_autorid.c | 6 ++--- > source3/winbindd/idmap_ldap.c | 29 ++++++++++++++++++++++++ > source3/winbindd/idmap_rw.c | 32 +++++++++++++++++++++++++-- > source3/winbindd/idmap_tdb_common.c | 22 +++++++++++++++++- > source3/winbindd/wb_sids2xids.c | 11 +++++++++ > source3/winbindd/winbindd_dual_srv.c | 6 +++++ > source3/winbindd/winbindd_getgroups.c | 7 ++++++ > 9 files changed, 135 insertions(+), 8 deletions(-) > >diff --git a/librpc/idl/idmap.idl b/librpc/idl/idmap.idl >index 54fd888dcabe..e58e39210c70 100644 >--- a/librpc/idl/idmap.idl >+++ b/librpc/idl/idmap.idl >@@ -11,7 +11,18 @@ interface idmap > ID_TYPE_NOT_SPECIFIED, > ID_TYPE_UID, > ID_TYPE_GID, >- ID_TYPE_BOTH >+ ID_TYPE_BOTH, >+ /* >+ * This are internal between winbindd >+ * parent and child. >+ * >+ * It means the idmap backend/child requires a valid type_hint >+ * for wbint_Sids2UnixIDs(): >+ * >+ * - ID_TYPE_UID or ID_TYPE_GID means the user/group exists >+ * - ID_TYPE_BOTH means that only the domain exist >+ */ >+ ID_TYPE_WB_REQUIRE_TYPE > } id_type; > > typedef [public] struct { >@@ -23,7 +34,15 @@ interface idmap > ID_UNKNOWN, > ID_MAPPED, > ID_UNMAPPED, >- ID_EXPIRED >+ ID_EXPIRED, >+ /* >+ * This means the idmap backend requires a valid type_hint >+ * in order to map a sid to a unix id. >+ * >+ * - ID_TYPE_UID or ID_TYPE_GID means the user/group exists >+ * - ID_TYPE_BOTH means that only the domain exist >+ */ >+ ID_REQUIRE_TYPE > } id_mapping; > > typedef [public] struct { >diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c >index eb706c20e1bf..39b81f3147ad 100644 >--- a/source3/passdb/lookup_sid.c >+++ b/source3/passdb/lookup_sid.c >@@ -1427,6 +1427,13 @@ done: > break; > case ID_TYPE_NOT_SPECIFIED: > break; >+ case ID_TYPE_WB_REQUIRE_TYPE: >+ /* >+ * these are internal between winbindd >+ * parent and child. >+ */ >+ smb_panic(__location__); >+ break; > } > } > >diff --git a/source3/winbindd/idmap_autorid.c b/source3/winbindd/idmap_autorid.c >index 636852119b26..d97494360b0d 100644 >--- a/source3/winbindd/idmap_autorid.c >+++ b/source3/winbindd/idmap_autorid.c >@@ -670,9 +670,9 @@ static NTSTATUS idmap_autorid_sid_to_id(struct idmap_tdb_common_context *common, > * range. > */ > >- DBG_NOTICE("Allocating range for domain %s refused\n", range.domsid); >- map->status = ID_UNMAPPED; >- return NT_STATUS_NONE_MAPPED; >+ DBG_NOTICE("Allocating range for domain %s required type_hint\n", range.domsid); >+ map->status = ID_REQUIRE_TYPE; >+ return NT_STATUS_SOME_NOT_MAPPED; > > allocate: > ret = idmap_autorid_acquire_range(autorid_db, &range); >diff --git a/source3/winbindd/idmap_ldap.c b/source3/winbindd/idmap_ldap.c >index 82f425ec9d07..bc757f3c74e4 100644 >--- a/source3/winbindd/idmap_ldap.c >+++ b/source3/winbindd/idmap_ldap.c >@@ -250,6 +250,17 @@ static NTSTATUS idmap_ldap_allocate_id_internal(struct idmap_domain *dom, > LDAP_ATTR_GIDNUMBER); > break; > >+ case ID_TYPE_BOTH: >+ /* >+ * This is not supported here yet and >+ * already handled in idmap_rw_new_mapping() >+ */ >+ FALL_THROUGH; >+ case ID_TYPE_NOT_SPECIFIED: >+ /* >+ * This is handled in idmap_rw_new_mapping() >+ */ >+ FALL_THROUGH; > default: > DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type)); > return NT_STATUS_INVALID_PARAMETER; >@@ -867,6 +878,7 @@ static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom, > const char **attr_list; > char *filter = NULL; > bool multi = False; >+ size_t num_required = 0; > int idx = 0; > int bidx = 0; > int count; >@@ -1075,7 +1087,21 @@ again: > ids[i]->status = ID_UNMAPPED; > if (ids[i]->sid != NULL) { > ret = idmap_ldap_new_mapping(dom, ids[i]); >+ DBG_DEBUG("idmap_ldap_new_mapping returned %s\n", >+ nt_errstr(ret)); >+ if (NT_STATUS_EQUAL(ret, STATUS_SOME_UNMAPPED)) { >+ if (ids[i]->status == ID_REQUIRE_TYPE) { >+ num_required += 1; >+ continue; >+ } >+ } > if (!NT_STATUS_IS_OK(ret)) { >+ /* >+ * If we can't create >+ * a new mapping it's unlikely >+ * that it will work for the >+ * next entry. >+ */ > goto done; > } > } >@@ -1083,6 +1109,9 @@ again: > } > > ret = NT_STATUS_OK; >+ if (num_required > 0) { >+ ret = STATUS_SOME_UNMAPPED; >+ } > > done: > talloc_free(memctx); >diff --git a/source3/winbindd/idmap_rw.c b/source3/winbindd/idmap_rw.c >index 700a946fc62f..71bfc14e2043 100644 >--- a/source3/winbindd/idmap_rw.c >+++ b/source3/winbindd/idmap_rw.c >@@ -39,11 +39,39 @@ NTSTATUS idmap_rw_new_mapping(struct idmap_domain *dom, > return NT_STATUS_INVALID_PARAMETER; > } > >- if ((map->xid.type != ID_TYPE_UID) && (map->xid.type != ID_TYPE_GID)) { >+ if (map->sid == NULL) { > return NT_STATUS_INVALID_PARAMETER; > } > >- if (map->sid == NULL) { >+ switch (map->xid.type) { >+ case ID_TYPE_NOT_SPECIFIED: >+ /* >+ * We need to know if we need a user or group mapping. >+ * Ask the winbindd parent to provide a valid type hint. >+ */ >+ DBG_INFO("%s ID_TYPE_NOT_SPECIFIED => ID_REQUIRE_TYPE\n", >+ dom_sid_str_buf(map->sid, &buf)); >+ map->status = ID_REQUIRE_TYPE; >+ return NT_STATUS_SOME_NOT_MAPPED; >+ >+ case ID_TYPE_BOTH: >+ /* >+ * For now we still require >+ * an explicit type as hint >+ * and don't support ID_TYPE_BOTH >+ */ >+ DBG_INFO("%s ID_TYPE_BOTH => ID_REQUIRE_TYPE\n", >+ dom_sid_str_buf(map->sid, &buf)); >+ map->status = ID_REQUIRE_TYPE; >+ return NT_STATUS_SOME_NOT_MAPPED; >+ >+ case ID_TYPE_UID: >+ break; >+ >+ case ID_TYPE_GID: >+ break; >+ >+ default: > return NT_STATUS_INVALID_PARAMETER; > } > >diff --git a/source3/winbindd/idmap_tdb_common.c b/source3/winbindd/idmap_tdb_common.c >index 34269e3fe56e..0df8f2f3103b 100644 >--- a/source3/winbindd/idmap_tdb_common.c >+++ b/source3/winbindd/idmap_tdb_common.c >@@ -118,6 +118,17 @@ static NTSTATUS idmap_tdb_common_allocate_id(struct idmap_domain *dom, > hwmtype = "GID"; > break; > >+ case ID_TYPE_BOTH: >+ /* >+ * This is not supported here yet and >+ * already handled in idmap_rw_new_mapping() >+ */ >+ FALL_THROUGH; >+ case ID_TYPE_NOT_SPECIFIED: >+ /* >+ * This is handled in idmap_rw_new_mapping() >+ */ >+ FALL_THROUGH; > default: > DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type)); > return NT_STATUS_INVALID_PARAMETER; >@@ -529,7 +540,7 @@ static NTSTATUS idmap_tdb_common_sids_to_unixids_action(struct db_context *db, > void *private_data) > { > struct idmap_tdb_common_sids_to_unixids_context *state = private_data; >- size_t i, num_mapped = 0; >+ size_t i, num_mapped = 0, num_required = 0; > NTSTATUS ret = NT_STATUS_OK; > > DEBUG(10, ("idmap_tdb_common_sids_to_unixids: " >@@ -579,6 +590,12 @@ static NTSTATUS idmap_tdb_common_sids_to_unixids_action(struct db_context *db, > state->ids[i]); > DBG_DEBUG("idmap_tdb_common_new_mapping returned %s\n", > nt_errstr(ret)); >+ if (NT_STATUS_EQUAL(ret, STATUS_SOME_UNMAPPED)) { >+ if (state->ids[i]->status == ID_REQUIRE_TYPE) { >+ num_required += 1; >+ continue; >+ } >+ } > if (!NT_STATUS_IS_OK(ret)) { > ret = STATUS_SOME_UNMAPPED; > continue; >@@ -598,6 +615,9 @@ done: > } else { > ret = NT_STATUS_OK; > } >+ if (num_required > 0) { >+ ret = STATUS_SOME_UNMAPPED; >+ } > } > > return ret; >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index 3a3d47abbe55..35b6675520e9 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -473,6 +473,17 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > for (si=0; si < src->num_ids; si++) { > uint32_t di = state->tmp_idx[si]; > >+ if (src->ids[si].xid.type == ID_TYPE_WB_REQUIRE_TYPE) { >+ /* >+ * This should not happen yet, as we always >+ * do a lookupsids and fill type_hint. >+ * >+ * Make sure we don't expose ID_TYPE_WB_REQUIRE_TYPE >+ * outside of winbindd! >+ */ >+ src->ids[si].xid.type = ID_TYPE_NOT_SPECIFIED; >+ } >+ > if (src->ids[si].xid.type != ID_TYPE_NOT_SPECIFIED) { > dst->ids[di].xid = src->ids[si].xid; > } >diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c >index 138863cb0db8..4a4894c2658a 100644 >--- a/source3/winbindd/winbindd_dual_srv.c >+++ b/source3/winbindd/winbindd_dual_srv.c >@@ -227,6 +227,12 @@ NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p, > for (i=0; i<num_ids; i++) { > struct id_map *m = id_map_ptrs[i]; > >+ if (m->status == ID_REQUIRE_TYPE) { >+ ids[i].xid.id = UINT32_MAX; >+ ids[i].xid.type = ID_TYPE_WB_REQUIRE_TYPE; >+ continue; >+ } >+ > if (!idmap_unix_id_is_in_range(m->xid.id, dom)) { > DBG_DEBUG("id %"PRIu32" is out of range " > "%"PRIu32"-%"PRIu32" for domain %s\n", >diff --git a/source3/winbindd/winbindd_getgroups.c b/source3/winbindd/winbindd_getgroups.c >index 63206c28134e..7182156578b4 100644 >--- a/source3/winbindd/winbindd_getgroups.c >+++ b/source3/winbindd/winbindd_getgroups.c >@@ -202,6 +202,13 @@ static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq) > case ID_TYPE_BOTH: > include_gid = true; > break; >+ case ID_TYPE_WB_REQUIRE_TYPE: >+ /* >+ * these are internal between winbindd >+ * parent and child. >+ */ >+ smb_panic(__location__); >+ break; > } > > if (!include_gid) { >-- >2.25.1 > > >From 0c17c09560be150b759f571ee7e6108fcc215a44 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 11 Sep 2020 16:24:49 +0200 >Subject: [PATCH 046/262] CVE-2020-25717 wb_sids2xids: defer/skip > wb_lookupsids* unless we get ID_TYPE_WB_REQUIRE_TYPE > >We try to give a valid hint for predefined sids and >pass ID_TYPE_BOTH as a hint that the domain part of the sid is valid. > >In most cases the idmap child/backend does not require a type_hint >as mappings already exist. > >This is a speed up as we no longer need to contact a domain controller. > >It's also possible to accept kerberos authentication without reaching >out to a domain controller at all (if the idmap backend doesn't need a >hint). > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Gary Lockyer <gary@catalyst.net.nz> > >Autobuild-User(master): Andrew Bartlett <abartlet@samba.org> >Autobuild-Date(master): Fri Oct 23 04:47:26 UTC 2020 on sn-devel-184 > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 54b4d2d3cb307019a260d15c6e6b4a3fb7fc337c) >--- > source3/winbindd/wb_sids2xids.c | 177 ++++++++++++++++++++++++++++---- > 1 file changed, 158 insertions(+), 19 deletions(-) > >diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c >index 35b6675520e9..650d104254a8 100644 >--- a/source3/winbindd/wb_sids2xids.c >+++ b/source3/winbindd/wb_sids2xids.c >@@ -69,6 +69,7 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq); > static void wb_sids2xids_done(struct tevent_req *subreq); > static void wb_sids2xids_gotdc(struct tevent_req *subreq); > static void wb_sids2xids_next_sids2unix(struct tevent_req *req); >+static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type); > > struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > struct tevent_context *ev, >@@ -166,11 +167,6 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, > num_valid += 1; > continue; > } >- >- state->tmp_idx[state->lookup_count] = i; >- sid_copy(&state->lookup_sids[state->lookup_count], >- &state->sids[i]); >- state->lookup_count += 1; > } > > if (num_valid == num_sids) { >@@ -222,6 +218,25 @@ static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq) > sid_copy(&domain_sid, &state->sids[i]); > sid_split_rid(&domain_sid, &rid); > >+ if (t->type_hint == ID_TYPE_NOT_SPECIFIED) { >+ const char *tmp_name = NULL; >+ enum lsa_SidType sid_type = SID_NAME_USE_NONE; >+ const struct dom_sid *tmp_authority_sid = NULL; >+ const char *tmp_authority_name = NULL; >+ >+ /* >+ * Try to get a type hint from for predefined sids >+ */ >+ status = dom_sid_lookup_predefined_sid(&state->sids[i], >+ &tmp_name, >+ &sid_type, >+ &tmp_authority_sid, >+ &tmp_authority_name); >+ if (NT_STATUS_IS_OK(status)) { >+ t->type_hint = lsa_SidType_to_id_type(sid_type); >+ } >+ } >+ > for (di = 0; di < state->cfg->num_doms; di++) { > struct wb_parent_idmap_config_dom *dom = > &state->cfg->doms[di]; >@@ -251,6 +266,18 @@ static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq) > domain_name = ""; > } > >+ if (t->type_hint == ID_TYPE_NOT_SPECIFIED) { >+ if (domain_name[0] != '\0') { >+ /* >+ * We know the domain, we indicate this >+ * by passing ID_TYPE_BOTH as a hint >+ * >+ * Maybe that's already enough for the backend >+ */ >+ t->type_hint = ID_TYPE_BOTH; >+ } >+ } >+ > domain_index = init_lsa_ref_domain_list(state, > &state->idmap_doms, > domain_name, >@@ -262,14 +289,15 @@ static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq) > t->domain_index = domain_index; > } > >- subreq = wb_lookupsids_send(state, >- state->ev, >- state->lookup_sids, >- state->lookup_count); >- if (tevent_req_nomem(subreq, req)) { >- return; >- } >- tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req); >+ /* >+ * We defer lookupsids because it requires domain controller >+ * interaction. >+ * >+ * First we ask the idmap child without explicit type hints. >+ * In most cases mappings already exist in the backend and >+ * a type_hint is not needed. >+ */ >+ wb_sids2xids_next_sids2unix(req); > } > > static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map) >@@ -292,8 +320,6 @@ static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map) > return false; > } > >-static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type); >- > static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > { > struct tevent_req *req = tevent_req_callback_data( >@@ -311,17 +337,83 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) > return; > } > >+ if (domains == NULL) { >+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >+ return; >+ } >+ >+ if (names == NULL) { >+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >+ return; >+ } >+ > for (li = 0; li < state->lookup_count; li++) { > struct lsa_TranslatedName *n = &names->names[li]; > uint32_t ai = state->tmp_idx[li]; > struct wbint_TransID *t = &state->all_ids.ids[ai]; >+ enum id_type type_hint; >+ >+ type_hint = lsa_SidType_to_id_type(n->sid_type); >+ if (type_hint != ID_TYPE_NOT_SPECIFIED) { >+ /* >+ * We know it's a valid user or group. >+ */ >+ t->type_hint = type_hint; >+ continue; >+ } >+ >+ if (n->sid_index == UINT32_MAX) { >+ /* >+ * The domain is not known, there's >+ * no point to try mapping again. >+ * mark is done and add a negative cache >+ * entry. >+ */ >+ t->domain_index = UINT32_MAX; /* mark as valid */ >+ idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid); >+ continue; >+ } > >- t->type_hint = lsa_SidType_to_id_type(n->sid_type); >+ if (n->sid_index >= domains->count) { >+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >+ return; >+ } >+ >+ if (domains->domains[n->sid_index].name.string == NULL) { >+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >+ return; >+ } >+ if (domains->domains[n->sid_index].sid == NULL) { >+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >+ return; >+ } >+ >+ if (t->type_hint != ID_TYPE_NOT_SPECIFIED) { >+ /* >+ * We already tried with a type hint there's >+ * no point to try mapping again with ID_TYPE_BOTH. >+ * >+ * Mark is done and add a negative cache entry. >+ */ >+ t->domain_index = UINT32_MAX; /* mark as valid */ >+ idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid); >+ continue; >+ } >+ >+ /* >+ * We only know the domain exists, but the user doesn't >+ */ >+ t->type_hint = ID_TYPE_BOTH; > } > > TALLOC_FREE(names); > TALLOC_FREE(domains); > >+ /* >+ * Now that we have type_hints for the remaining sids, >+ * we need to restart with the first domain. >+ */ >+ state->dom_index = 0; > wb_sids2xids_next_sids2unix(req); > } > >@@ -339,7 +431,45 @@ static void wb_sids2xids_next_sids2unix(struct tevent_req *req) > state->tried_dclookup = false; > > if (state->dom_index == state->idmap_doms.count) { >- tevent_req_done(req); >+ if (state->lookup_count != 0) { >+ /* >+ * We already called wb_lookupsids_send() >+ * before, so we're done. >+ */ >+ tevent_req_done(req); >+ return; >+ } >+ >+ for (si=0; si < state->num_sids; si++) { >+ struct wbint_TransID *t = &state->all_ids.ids[si]; >+ >+ if (t->domain_index == UINT32_MAX) { >+ /* ignore already filled entries */ >+ continue; >+ } >+ >+ state->tmp_idx[state->lookup_count] = si; >+ sid_copy(&state->lookup_sids[state->lookup_count], >+ &state->sids[si]); >+ state->lookup_count += 1; >+ } >+ >+ if (state->lookup_count == 0) { >+ /* >+ * no wb_lookupsids_send() needed... >+ */ >+ tevent_req_done(req); >+ return; >+ } >+ >+ subreq = wb_lookupsids_send(state, >+ state->ev, >+ state->lookup_sids, >+ state->lookup_count); >+ if (tevent_req_nomem(subreq, req)) { >+ return; >+ } >+ tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req); > return; > } > >@@ -474,9 +604,18 @@ static void wb_sids2xids_done(struct tevent_req *subreq) > uint32_t di = state->tmp_idx[si]; > > if (src->ids[si].xid.type == ID_TYPE_WB_REQUIRE_TYPE) { >+ if (state->lookup_count == 0) { >+ /* >+ * The backend asks for more information >+ * (a type_hint), we'll do a lookupsids >+ * later. >+ */ >+ continue; >+ } >+ > /* >- * This should not happen yet, as we always >- * do a lookupsids and fill type_hint. >+ * lookupsids was not able to provide a type_hint that >+ * satisfied the backend. > * > * Make sure we don't expose ID_TYPE_WB_REQUIRE_TYPE > * outside of winbindd! >-- >2.25.1 > > >From 99326a5e3ece573f231aff63929185be14f364ae Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 23 Oct 2020 12:21:57 +0200 >Subject: [PATCH 047/262] CVE-2020-25717 s3:idmap_hash: reliable return > ID_TYPE_BOTH > >idmap_hash used to bounce back the requested type, >which was ID_TYPE_UID, ID_TYPE_GID or ID_TYPE_NOT_SPECIFIED >before as the winbindd parent always used a lookupsids. >When the lookupsids failed because of an unknown domain, >the idmap child weren't requested at all and the caller >sees ID_TYPE_NOT_SPECIFIED. > >This module should have supported ID_TYPE_BOTH since >samba-4.1.0, similar to idmap_rid and idmap_autorid. > >Now that the winbindd parent will pass ID_TYPE_BOTH in order to >indicate that the domain exists, it's better to always return >ID_TYPE_BOTH instead of a random mix of ID_TYPE_UID, ID_TYPE_GID >or ID_TYPE_BOTH. In order to request a type_hint it will return >ID_REQUIRE_TYPE for ID_TYPE_NOT_SPECIFIED, which means that >the parent at least assures that the domain sid exists. >And the caller still gets ID_TYPE_NOT_SPECIFIED if the >domain doesn't exist. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> > >Autobuild-User(master): Stefan Metzmacher <metze@samba.org> >Autobuild-Date(master): Fri Jan 22 11:32:46 UTC 2021 on sn-devel-184 > >(cherry picked from commit d8339056eef2845805f573bd8b0f3323370ecc8f) >Reviewed-by: Ralph Boehme <slow@samba.org> > >Autobuild-User(v4-14-test): Karolin Seeger <kseeger@samba.org> >Autobuild-Date(v4-14-test): Wed Jan 27 17:06:51 UTC 2021 on sn-devel-184 > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 99673b77b069674a6145552eb870de8829dfa503) >--- > source3/winbindd/idmap_hash/idmap_hash.c | 35 ++++++++++++++++++++++++ > 1 file changed, 35 insertions(+) > >diff --git a/source3/winbindd/idmap_hash/idmap_hash.c b/source3/winbindd/idmap_hash/idmap_hash.c >index be0ba45a0443..d0bed7631a61 100644 >--- a/source3/winbindd/idmap_hash/idmap_hash.c >+++ b/source3/winbindd/idmap_hash/idmap_hash.c >@@ -261,6 +261,25 @@ static NTSTATUS sids_to_unixids(struct idmap_domain *dom, > > ids[i]->status = ID_UNMAPPED; > >+ if (ids[i]->xid.type == ID_TYPE_NOT_SPECIFIED) { >+ /* >+ * idmap_hash used to bounce back the requested type, >+ * which was ID_TYPE_UID, ID_TYPE_GID or >+ * ID_TYPE_NOT_SPECIFIED before as the winbindd parent >+ * always used a lookupsids. When the lookupsids >+ * failed because of an unknown domain, the idmap child >+ * weren't requested at all and the caller sees >+ * ID_TYPE_NOT_SPECIFIED. >+ * >+ * Now that the winbindd parent will pass ID_TYPE_BOTH >+ * in order to indicate that the domain exists. >+ * We should ask the parent to fallback to lookupsids >+ * if the domain is not known yet. >+ */ >+ ids[i]->status = ID_REQUIRE_TYPE; >+ continue; >+ } >+ > sid_copy(&sid, ids[i]->sid); > sid_split_rid(&sid, &rid); > >@@ -270,6 +289,22 @@ static NTSTATUS sids_to_unixids(struct idmap_domain *dom, > /* Check that both hashes are non-zero*/ > > if (h_domain && h_rid) { >+ /* >+ * idmap_hash used to bounce back the requested type, >+ * which was ID_TYPE_UID, ID_TYPE_GID or >+ * ID_TYPE_NOT_SPECIFIED before as the winbindd parent >+ * always used a lookupsids. >+ * >+ * This module should have supported ID_TYPE_BOTH since >+ * samba-4.1.0, similar to idmap_rid and idmap_autorid. >+ * >+ * Now that the winbindd parent will pass ID_TYPE_BOTH >+ * in order to indicate that the domain exists, it's >+ * better to always return ID_TYPE_BOTH instead of a >+ * random mix of ID_TYPE_UID, ID_TYPE_GID or >+ * ID_TYPE_BOTH. >+ */ >+ ids[i]->xid.type = ID_TYPE_BOTH; > ids[i]->xid.id = combine_hashes(h_domain, h_rid); > ids[i]->status = ID_MAPPED; > } >-- >2.25.1 > > >From 3694a0cb132405e90c3d3be060a3b3c85d52639c Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Tue, 31 Aug 2021 17:04:56 +0200 >Subject: [PATCH 048/262] CVE-2020-25717 winbindd: call > wb_parent_idmap_setup_send() in wb_queryuser_send() > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14804 > >Signed-off-by: Ralph Boehme <slow@samba.org> >Reviewed-by: Volker Lendecke <vl@samba.org> >(cherry picked from commit 39c2ec72cb77945c3eb611fb1d7d7e9aad52bdfd) > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 7d1dd87a6538f8c7f1e4938b0ff52cbd231fff90) >--- > source3/winbindd/wb_queryuser.c | 30 +++++++++++++++++++++++++++--- > 1 file changed, 27 insertions(+), 3 deletions(-) > >diff --git a/source3/winbindd/wb_queryuser.c b/source3/winbindd/wb_queryuser.c >index 9db51909c02c..f5bc96f03f66 100644 >--- a/source3/winbindd/wb_queryuser.c >+++ b/source3/winbindd/wb_queryuser.c >@@ -25,10 +25,12 @@ > > struct wb_queryuser_state { > struct tevent_context *ev; >- struct wbint_userinfo *info; >+ struct wbint_userinfo *info; >+ const struct wb_parent_idmap_config *idmap_cfg; > bool tried_dclookup; > }; > >+static void wb_queryuser_idmap_setup_done(struct tevent_req *subreq); > static void wb_queryuser_got_uid(struct tevent_req *subreq); > static void wb_queryuser_got_domain(struct tevent_req *subreq); > static void wb_queryuser_got_dc(struct tevent_req *subreq); >@@ -60,13 +62,35 @@ struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx, > > sid_copy(&info->user_sid, user_sid); > >+ subreq = wb_parent_idmap_setup_send(state, state->ev); >+ if (tevent_req_nomem(subreq, req)) { >+ return tevent_req_post(req, ev); >+ } >+ tevent_req_set_callback(subreq, wb_queryuser_idmap_setup_done, req); >+ return req; >+} >+ >+static void wb_queryuser_idmap_setup_done(struct tevent_req *subreq) >+{ >+ struct tevent_req *req = tevent_req_callback_data( >+ subreq, struct tevent_req); >+ struct wb_queryuser_state *state = tevent_req_data( >+ req, struct wb_queryuser_state); >+ NTSTATUS status; >+ >+ status = wb_parent_idmap_setup_recv(subreq, &state->idmap_cfg); >+ TALLOC_FREE(subreq); >+ if (tevent_req_nterror(req, status)) { >+ return; >+ } >+ > subreq = wb_sids2xids_send( > state, state->ev, &state->info->user_sid, 1); > if (tevent_req_nomem(subreq, req)) { >- return tevent_req_post(req, ev); >+ return; > } > tevent_req_set_callback(subreq, wb_queryuser_got_uid, req); >- return req; >+ return; > } > > static void wb_queryuser_got_uid(struct tevent_req *subreq) >-- >2.25.1 > > >From aa9fbae50a707551c7fb59f14c49023da01a008c Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Fri, 20 Aug 2021 15:04:49 +0200 >Subject: [PATCH 049/262] CVE-2020-25717 winbind: ensure > wb_parent_idmap_setup_send() gets called in winbindd_allocate_uid_send() > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14804 >RN: winbindd can crash because idmap child state is not fully initialized > >Signed-off-by: Ralph Boehme <slow@samba.org> >Reviewed-by: Volker Lendecke <vl@samba.org> > >Autobuild-User(master): Volker Lendecke <vl@samba.org> >Autobuild-Date(master): Thu Sep 2 15:20:06 UTC 2021 on sn-devel-184 > >(cherry picked from commit d0f6d54354b02f5591706814fbd1e4844788fdfa) > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 446f89510f2e55a551e2975a6cbf01c6a023ba0c) >--- > source3/winbindd/winbindd_allocate_uid.c | 44 +++++++++++++++++++++--- > 1 file changed, 39 insertions(+), 5 deletions(-) > >diff --git a/source3/winbindd/winbindd_allocate_uid.c b/source3/winbindd/winbindd_allocate_uid.c >index 69ce61c872e7..64711f1b6611 100644 >--- a/source3/winbindd/winbindd_allocate_uid.c >+++ b/source3/winbindd/winbindd_allocate_uid.c >@@ -22,9 +22,11 @@ > #include "librpc/gen_ndr/ndr_winbind_c.h" > > struct winbindd_allocate_uid_state { >+ struct tevent_context *ev; > uint64_t uid; > }; > >+static void winbindd_allocate_uid_initialized(struct tevent_req *subreq); > static void winbindd_allocate_uid_done(struct tevent_req *subreq); > > struct tevent_req *winbindd_allocate_uid_send(TALLOC_CTX *mem_ctx, >@@ -34,25 +36,57 @@ struct tevent_req *winbindd_allocate_uid_send(TALLOC_CTX *mem_ctx, > { > struct tevent_req *req, *subreq; > struct winbindd_allocate_uid_state *state; >- struct dcerpc_binding_handle *child_binding_handle = NULL; > > req = tevent_req_create(mem_ctx, &state, > struct winbindd_allocate_uid_state); > if (req == NULL) { > return NULL; > } >+ state->ev = ev; > > DEBUG(3, ("allocate_uid\n")); > >- child_binding_handle = idmap_child_handle(); >+ subreq = wb_parent_idmap_setup_send(state, ev); >+ if (tevent_req_nomem(subreq, req)) { >+ return tevent_req_post(req, ev); >+ } >+ tevent_req_set_callback(subreq, winbindd_allocate_uid_initialized, req); >+ return req; >+} >+ >+static void winbindd_allocate_uid_initialized(struct tevent_req *subreq) >+{ >+ struct tevent_req *req = tevent_req_callback_data( >+ subreq, struct tevent_req); >+ struct dcerpc_binding_handle *child_binding_handle = NULL; >+ struct winbindd_allocate_uid_state *state = tevent_req_data( >+ req, struct winbindd_allocate_uid_state); >+ const struct wb_parent_idmap_config *cfg = NULL; >+ NTSTATUS status; >+ >+ status = wb_parent_idmap_setup_recv(subreq, &cfg); >+ TALLOC_FREE(subreq); >+ if (tevent_req_nterror(req, status)) { >+ return; >+ } >+ if (cfg->num_doms == 0) { >+ /* >+ * idmap_tdb also returns UNSUCCESSFUL if a range is full >+ */ >+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL); >+ return; >+ } >+ >+ child_binding_handle = idmap_child_handle(); > >- subreq = dcerpc_wbint_AllocateUid_send(state, ev, child_binding_handle, >+ subreq = dcerpc_wbint_AllocateUid_send(state, >+ state->ev, >+ child_binding_handle, > &state->uid); > if (tevent_req_nomem(subreq, req)) { >- return tevent_req_post(req, ev); >+ return; > } > tevent_req_set_callback(subreq, winbindd_allocate_uid_done, req); >- return req; > } > > static void winbindd_allocate_uid_done(struct tevent_req *subreq) >-- >2.25.1 > > >From 98c3d898f74e20ce9a2962e038a063c4fbb09d06 Mon Sep 17 00:00:00 2001 >From: Alexander Bokovoy <ab@samba.org> >Date: Wed, 11 Nov 2020 14:42:55 +0200 >Subject: [PATCH 050/262] CVE-2020-25717 auth_sam: use pdb_get_domain_info to > look up DNS forest information > >When Samba is used as a part of FreeIPA domain controller, Windows >clients for a trusted AD forest may try to authenticate (perform logon >operation) as a REALM\name user account. > >Fix auth_sam plugins to accept DNS forest name if we are running on a DC >with PASSDB module providing domain information (e.g. pdb_get_domain_info() >returning non-NULL structure). Right now, only FreeIPA or Samba AD DC >PASSDB backends return this information but Samba AD DC configuration is >explicitly ignored by the two auth_sam (strict and netlogon3) modules. > >Detailed logs below: > >[2020/11/11 09:23:53.281296, 1, pid=42677, effective(65534, 65534), real(65534, 0), class=rpc_parse] ../../librpc/ndr/ndr.c:482(ndr_print_function_debug) > netr_LogonSamLogonWithFlags: struct netr_LogonSamLogonWithFlags > in: struct netr_LogonSamLogonWithFlags > server_name : * > server_name : '\\master.ipa.test' > computer_name : * > computer_name : 'AD1' > credential : * > credential: struct netr_Authenticator > cred: struct netr_Credential > data : 529f4b087c5f6546 > timestamp : Wed Nov 11 09:23:55 AM 2020 UTC > return_authenticator : * > return_authenticator: struct netr_Authenticator > cred: struct netr_Credential > data : 204f28f622010000 > timestamp : Fri May 2 06:37:50 AM 1986 UTC > logon_level : NetlogonNetworkTransitiveInformation (6) > logon : * > logon : union netr_LogonLevel(case 6) > network : * > network: struct netr_NetworkInfo > identity_info: struct netr_IdentityInfo > domain_name: struct lsa_String > length : 0x0010 (16) > size : 0x01fe (510) > string : * > string : 'IPA.TEST' > parameter_control : 0x00002ae0 (10976) > 0: MSV1_0_CLEARTEXT_PASSWORD_ALLOWED > 0: MSV1_0_UPDATE_LOGON_STATISTICS > 0: MSV1_0_RETURN_USER_PARAMETERS > 0: MSV1_0_DONT_TRY_GUEST_ACCOUNT > 1: MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT > 1: MSV1_0_RETURN_PASSWORD_EXPIRY > 1: MSV1_0_USE_CLIENT_CHALLENGE > 0: MSV1_0_TRY_GUEST_ACCOUNT_ONLY > 1: MSV1_0_RETURN_PROFILE_PATH > 0: MSV1_0_TRY_SPECIFIED_DOMAIN_ONLY > 1: MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT > 0: MSV1_0_DISABLE_PERSONAL_FALLBACK > 1: MSV1_0_ALLOW_FORCE_GUEST > 0: MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED > 0: MSV1_0_USE_DOMAIN_FOR_ROUTING_ONLY > 0: MSV1_0_ALLOW_MSVCHAPV2 > 0: MSV1_0_S4U2SELF > 0: MSV1_0_CHECK_LOGONHOURS_FOR_S4U > 0: MSV1_0_SUBAUTHENTICATION_DLL_EX > logon_id : 0x0000000000884ef2 (8933106) > account_name: struct lsa_String > length : 0x000e (14) > size : 0x000e (14) > string : * > string : 'idmuser' > workstation: struct lsa_String > length : 0x0000 (0) > size : 0x0000 (0) > string : * > string : '' > challenge : 417207867bd33c74 > nt: struct netr_ChallengeResponse > length : 0x00c0 (192) > size : 0x00c0 (192) > data : * > data: ARRAY(192) > [0000] A5 24 62 6E 31 DF 69 66 9E DC 54 D6 63 4C D6 2F .$bn1.if ..T.cL./ > [0010] 01 01 00 00 00 00 00 00 50 37 D7 60 0C B8 D6 01 ........ P7.`.... > [0020] 15 1B 38 4F 47 95 4D 62 00 00 00 00 02 00 0E 00 ..8OG.Mb ........ > [0030] 57 00 49 00 4E 00 32 00 30 00 31 00 36 00 01 00 W.I.N.2. 0.1.6... > [0040] 06 00 41 00 44 00 31 00 04 00 18 00 77 00 69 00 ..A.D.1. ....w.i. > [0050] 6E 00 32 00 30 00 31 00 36 00 2E 00 74 00 65 00 n.2.0.1. 6...t.e. > [0060] 73 00 74 00 03 00 20 00 61 00 64 00 31 00 2E 00 s.t... . a.d.1... > [0070] 77 00 69 00 6E 00 32 00 30 00 31 00 36 00 2E 00 w.i.n.2. 0.1.6... > [0080] 74 00 65 00 73 00 74 00 05 00 18 00 77 00 69 00 t.e.s.t. ....w.i. > [0090] 6E 00 32 00 30 00 31 00 36 00 2E 00 74 00 65 00 n.2.0.1. 6...t.e. > [00A0] 73 00 74 00 07 00 08 00 50 37 D7 60 0C B8 D6 01 s.t..... P7.`.... > [00B0] 06 00 04 00 02 00 00 00 00 00 00 00 00 00 00 00 ........ ........ > lm: struct netr_ChallengeResponse > length : 0x0018 (24) > size : 0x0018 (24) > data : * > data : 000000000000000000000000000000000000000000000000 > validation_level : 0x0006 (6) > flags : * > flags : 0x00000000 (0) > 0: NETLOGON_SAMLOGON_FLAG_PASS_TO_FOREST_ROOT > 0: NETLOGON_SAMLOGON_FLAG_PASS_CROSS_FOREST_HOP > 0: NETLOGON_SAMLOGON_FLAG_RODC_TO_OTHER_DOMAIN > 0: NETLOGON_SAMLOGON_FLAG_RODC_NTLM_REQUEST > >In such case checks for a workgroup name will not match the DNS forest >name used in the username specification: > >[2020/11/11 09:23:53.283055, 3, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth.c:200(auth_check_ntlm_password) > check_ntlm_password: Checking password for unmapped user [IPA.TEST]\[idmuser]@[] with the new password interface >[2020/11/11 09:23:53.283073, 3, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth.c:203(auth_check_ntlm_password) > check_ntlm_password: mapped user is: [IPA.TEST]\[idmuser]@[] >[2020/11/11 09:23:53.283082, 10, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth.c:213(auth_check_ntlm_password) > check_ntlm_password: auth_context challenge created by fixed >[2020/11/11 09:23:53.283091, 10, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth.c:216(auth_check_ntlm_password) > challenge is: >[2020/11/11 09:23:53.283099, 5, pid=42677, effective(65534, 65534), real(65534, 0)] ../../lib/util/util.c:678(dump_data) > [0000] 41 72 07 86 7B D3 3C 74 Ar..{.<t >[2020/11/11 09:23:53.283113, 10, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth_sam.c:209(auth_sam_netlogon3_auth) > auth_sam_netlogon3_auth: Check auth for: [IPA.TEST]\[idmuser] >[2020/11/11 09:23:53.283123, 5, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth_sam.c:234(auth_sam_netlogon3_auth) > auth_sam_netlogon3_auth: IPA.TEST is not our domain name (DC for IPA) >[2020/11/11 09:23:53.283131, 10, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth.c:249(auth_check_ntlm_password) > auth_check_ntlm_password: sam_netlogon3 had nothing to say > >and overall authentication attempt will fail: auth_winbind will complain >that this domain is not a trusted one and refuse operating on it: > >[2020/11/11 09:23:53.283784, 10, pid=42663, effective(0, 0), real(0, 0), class=winbind] ../../source3/winbindd/winbindd.c:742(process_request_send) > process_request_send: process_request: Handling async request smbd(42677):PAM_AUTH_CRAP >[2020/11/11 09:23:53.283796, 3, pid=42663, effective(0, 0), real(0, 0), class=winbind] ../../source3/winbindd/winbindd_pam_auth_crap.c:110(winbindd_pam_auth_crap_send) > [42677]: pam auth crap domain: [IPA.TEST] user: idmuser >[2020/11/11 09:23:53.283810, 3, pid=42663, effective(0, 0), real(0, 0), class=winbind] ../../source3/winbindd/winbindd_pam.c:409(find_auth_domain) > Authentication for domain [IPA.TEST] refused as it is not a trusted domain >[2020/11/11 09:23:53.283825, 10, pid=42663, effective(0, 0), real(0, 0), class=winbind] ../../source3/winbindd/winbindd.c:810(process_request_done) > process_request_done: [smbd(42677):PAM_AUTH_CRAP]: NT_STATUS_NO_SUCH_USER >[2020/11/11 09:23:53.283844, 10, pid=42663, effective(0, 0), real(0, 0), class=winbind] ../../source3/winbindd/winbindd.c:855(process_request_written) > process_request_written: [smbd(42677):PAM_AUTH_CRAP]: delivered response to client > >Signed-off-by: Alexander Bokovoy <ab@samba.org> >Reviewed-by: Andreas Schneider <asn@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 2a8b672652dcbcf55ec59be537773d76f0f14d0a) >--- > source3/auth/auth_sam.c | 45 +++++++++++++++++++++++++++++++++++++---- > 1 file changed, 41 insertions(+), 4 deletions(-) > >diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c >index 3c12f959fafe..e8e0d543f8c3 100644 >--- a/source3/auth/auth_sam.c >+++ b/source3/auth/auth_sam.c >@@ -22,6 +22,7 @@ > > #include "includes.h" > #include "auth.h" >+#include "passdb.h" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_AUTH >@@ -142,10 +143,28 @@ static NTSTATUS auth_samstrict_auth(const struct auth_context *auth_context, > break; > case ROLE_DOMAIN_PDC: > case ROLE_DOMAIN_BDC: >- if ( !is_local_name && !is_my_domain ) { >- DEBUG(6,("check_samstrict_security: %s is not one of my local names or domain name (DC)\n", >- effective_domain)); >- return NT_STATUS_NOT_IMPLEMENTED; >+ if (!is_local_name && !is_my_domain) { >+ /* If we are running on a DC that has PASSDB module with domain >+ * information, check if DNS forest name is matching the domain >+ * name. This is the case of FreeIPA domain controller when >+ * trusted AD DCs attempt to authenticate FreeIPA users using >+ * the forest root domain (which is the only domain in FreeIPA). >+ */ >+ struct pdb_domain_info *dom_info = NULL; >+ >+ dom_info = pdb_get_domain_info(mem_ctx); >+ if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) { >+ is_my_domain = strequal(user_info->mapped.domain_name, >+ dom_info->dns_forest); >+ } >+ >+ TALLOC_FREE(dom_info); >+ if (!is_my_domain) { >+ DEBUG(6,("check_samstrict_security: %s is not one " >+ "of my local names or domain name (DC)\n", >+ effective_domain)); >+ return NT_STATUS_NOT_IMPLEMENTED; >+ } > } > > break; >@@ -230,6 +249,24 @@ static NTSTATUS auth_sam_netlogon3_auth(const struct auth_context *auth_context, > } > > is_my_domain = strequal(user_info->mapped.domain_name, lp_workgroup()); >+ if (!is_my_domain) { >+ /* If we are running on a DC that has PASSDB module with domain >+ * information, check if DNS forest name is matching the domain >+ * name. This is the case of FreeIPA domain controller when >+ * trusted AD DCs attempt to authenticate FreeIPA users using >+ * the forest root domain (which is the only domain in FreeIPA). >+ */ >+ struct pdb_domain_info *dom_info = NULL; >+ dom_info = pdb_get_domain_info(mem_ctx); >+ >+ if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) { >+ is_my_domain = strequal(user_info->mapped.domain_name, >+ dom_info->dns_forest); >+ } >+ >+ TALLOC_FREE(dom_info); >+ } >+ > if (!is_my_domain) { > DBG_INFO("%s is not our domain name (DC for %s)\n", > effective_domain, lp_workgroup()); >-- >2.25.1 > > >From 8c1fae11e712199a8ba0d26e6be028668362ec57 Mon Sep 17 00:00:00 2001 >From: Alexander Bokovoy <ab@samba.org> >Date: Tue, 10 Nov 2020 17:35:24 +0200 >Subject: [PATCH 051/262] CVE-2020-25717 lookup_name: allow lookup names > prefixed with DNS forest root for FreeIPA DC > >In FreeIPA deployment with active Global Catalog service, when a two-way >trust to Active Directory forest is established, Windows systems can >look up FreeIPA users and groups. When using a security tab in Windows >Explorer on AD side, a lookup over a trusted forest might come as >realm\name instead of NetBIOS domain name: > >-------------------------------------------------------------------- >[2020/01/13 11:12:39.859134, 1, pid=33253, effective(1732401004, 1732401004), real(1732401004, 0), class=rpc_parse] ../../librpc/ndr/ndr.c:471(ndr_print_function_debug) > lsa_LookupNames3: struct lsa_LookupNames3 > in: struct lsa_LookupNames3 > handle : * > handle: struct policy_handle > handle_type : 0x00000000 (0) > uuid : 0000000e-0000-0000-1c5e-a750e5810000 > num_names : 0x00000001 (1) > names: ARRAY(1) > names: struct lsa_String > length : 0x001e (30) > size : 0x0020 (32) > string : * > string : 'ipa.test\admins' > sids : * > sids: struct lsa_TransSidArray3 > count : 0x00000000 (0) > sids : NULL > level : LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2 (6) > count : * > count : 0x00000000 (0) > lookup_options : LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES (0) > client_revision : LSA_CLIENT_REVISION_2 (2) >-------------------------------------------------------------------- > >If we are running as a DC and PASSDB supports returning domain info >(pdb_get_domain_info() returns a valid structure), check domain of the >name in lookup_name() against DNS forest name and allow the request to >be done against the primary domain. This corresponds to FreeIPA's use of >Samba as a DC. For normal domain members a realm-based lookup falls back >to a lookup over to its own domain controller with the help of winbindd. > >Signed-off-by: Alexander Bokovoy <ab@samba.org> >Reviewed-by: Stefan Metzmacher <metze@samba.org> > >Autobuild-User(master): Alexander Bokovoy <ab@samba.org> >Autobuild-Date(master): Wed Nov 11 10:59:01 UTC 2020 on sn-devel-184 > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 31c703766fd2b89737826fb7e9a707f0622bb8cd) >--- > source3/passdb/lookup_sid.c | 37 ++++++++++++++++++++++++++++--------- > 1 file changed, 28 insertions(+), 9 deletions(-) > >diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c >index 39b81f3147ad..0e01467b3cb4 100644 >--- a/source3/passdb/lookup_sid.c >+++ b/source3/passdb/lookup_sid.c >@@ -114,17 +114,36 @@ bool lookup_name(TALLOC_CTX *mem_ctx, > full_name, domain, name)); > DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags)); > >- if (((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) && >- strequal(domain, get_global_sam_name())) >- { >+ if ((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) { >+ bool check_global_sam = false; >+ >+ check_global_sam = strequal(domain, get_global_sam_name()); >+ >+ /* If we are running on a DC that has PASSDB module with domain >+ * information, check if DNS forest name is matching the domain >+ * name. This is the case of FreeIPA domain controller when >+ * trusted AD DC looks up users found in a Global Catalog of >+ * the forest root domain. */ >+ if (!check_global_sam && (IS_DC)) { >+ struct pdb_domain_info *dom_info = NULL; >+ dom_info = pdb_get_domain_info(tmp_ctx); >+ >+ if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) { >+ check_global_sam = strequal(domain, dom_info->dns_forest); >+ } > >- /* It's our own domain, lookup the name in passdb */ >- if (lookup_global_sam_name(name, flags, &rid, &type)) { >- sid_compose(&sid, get_global_sam_sid(), rid); >- goto ok; >+ TALLOC_FREE(dom_info); >+ } >+ >+ if (check_global_sam) { >+ /* It's our own domain, lookup the name in passdb */ >+ if (lookup_global_sam_name(name, flags, &rid, &type)) { >+ sid_compose(&sid, get_global_sam_sid(), rid); >+ goto ok; >+ } >+ TALLOC_FREE(tmp_ctx); >+ return false; > } >- TALLOC_FREE(tmp_ctx); >- return false; > } > > if ((flags & LOOKUP_NAME_BUILTIN) && >-- >2.25.1 > > >From 9e88616ac7143023ac847cae0f1f914837d31706 Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?Bj=C3=B6rn=20Jacke?= <bj@sernet.de> >Date: Sun, 18 Oct 2020 21:07:14 +0200 >Subject: [PATCH 052/262] CVE-2020-25717 auth_generic: fix empty initializer > compile warning > >Signed-off-by: Bjoern Jacke <bjacke@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit cce4e8012c5eafb6d98111b92923d748d72d077b) >--- > source3/auth/auth_generic.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c >index 0e9500ac08d1..8af744810345 100644 >--- a/source3/auth/auth_generic.c >+++ b/source3/auth/auth_generic.c >@@ -66,7 +66,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > > if (pac_blob) { > #ifdef HAVE_KRB5 >- struct wbcAuthUserParams params = {}; >+ struct wbcAuthUserParams params = { 0 }; > struct wbcAuthUserInfo *info = NULL; > struct wbcAuthErrorInfo *err = NULL; > wbcErr wbc_err; >-- >2.25.1 > > >From e094944989b622021680a57283781216f91fd6cd Mon Sep 17 00:00:00 2001 >From: Andreas Schneider <asn@samba.org> >Date: Tue, 11 May 2021 17:59:51 +0200 >Subject: [PATCH 053/262] CVE-2020-25717 selftest: Pass down the machine > account name to provision_ad_member > >Signed-off-by: Andreas Schneider <asn@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit fbe68dcbb783409589cdefd8ee551c9971c51f08) > >Needed as preparation for CVE-2020-25717 >--- > selftest/target/Samba.pm | 1 + > selftest/target/Samba3.pm | 10 ++++++++-- > 2 files changed, 9 insertions(+), 2 deletions(-) > >diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm >index d47f933376ef..1e3b321258fb 100644 >--- a/selftest/target/Samba.pm >+++ b/selftest/target/Samba.pm >@@ -578,6 +578,7 @@ sub get_interface($) > addcsmb1 => 54, > lclnt4dc2smb1 => 55, > fipsdc => 56, >+ fipsadmember => 57, > > rootdnsforwarder => 64, > >diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm >index 8de5fe6a374a..6abec28d8628 100755 >--- a/selftest/target/Samba3.pm >+++ b/selftest/target/Samba3.pm >@@ -648,6 +648,7 @@ sub provision_ad_member > { > my ($self, > $prefix, >+ $machine_account, > $dcvars, > $trustvars_f, > $trustvars_e, >@@ -724,7 +725,7 @@ sub provision_ad_member > prefix => $prefix, > domain => $dcvars->{DOMAIN}, > realm => $dcvars->{REALM}, >- server => "LOCALADMEMBER", >+ server => $machine_account, > password => "loCalMemberPass", > extra_options => $member_options, > resolv_conf => $dcvars->{RESOLV_CONF}); >@@ -838,7 +839,11 @@ sub setup_ad_member > > print "PROVISIONING AD MEMBER..."; > >- return $self->provision_ad_member($prefix, $dcvars, $trustvars_f, $trustvars_e); >+ return $self->provision_ad_member($prefix, >+ "LOCALADMEMBER", >+ $dcvars, >+ $trustvars_f, >+ $trustvars_e); > } > > sub setup_ad_member_rfc2307 >@@ -1159,6 +1164,7 @@ sub setup_ad_member_fips > print "PROVISIONING AD FIPS MEMBER..."; > > return $self->provision_ad_member($prefix, >+ "FIPSADMEMBER", > $dcvars, > $trustvars_f, > $trustvars_e, >-- >2.25.1 > > >From f4fa820fd5d52dc79d066ac3b1919fd979702ca4 Mon Sep 17 00:00:00 2001 >From: Andreas Schneider <asn@samba.org> >Date: Thu, 10 Jun 2021 16:20:28 +0200 >Subject: [PATCH 054/262] CVE-2020-25717 selftest: Only set netbios aliases for > the ad_member env > >The provision_ad_member() function is reused by different >setup_ad_member*() functions. Each environment needs to have unique >netbios aliases as they are all in the same network. >The aliases should only be set for the 'ad_member' environment. > >Signed-Off-By: Andreas Schneider <asn@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >Autobuild-User(master): Jeremy Allison <jra@samba.org> >Autobuild-Date(master): Fri Jun 11 01:26:36 UTC 2021 on sn-devel-184 > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit e165dcc770ec58c3749d653d6cb85f6ecf9479d6) >--- > selftest/target/Samba3.pm | 8 +++++++- > 1 file changed, 7 insertions(+), 1 deletion(-) > >diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm >index 6abec28d8628..9481d1896162 100755 >--- a/selftest/target/Samba3.pm >+++ b/selftest/target/Samba3.pm >@@ -684,11 +684,17 @@ sub provision_ad_member > $substitution_path = "$share_dir/D_$dcvars->{DOMAIN}/u_$dcvars->{DOMAIN}/alice/g_$dcvars->{DOMAIN}/domain users"; > push(@dirs, $substitution_path); > >+ >+ my $netbios_aliases = ""; >+ if ($machine_account eq "LOCALADMEMBER") { >+ $netbios_aliases = "netbios aliases = foo bar"; >+ } >+ > my $member_options = " > security = ads > workgroup = $dcvars->{DOMAIN} > realm = $dcvars->{REALM} >- netbios aliases = foo bar >+ $netbios_aliases > template homedir = /home/%D/%G/%U > auth event notification = true > password server = $dcvars->{SERVER} >-- >2.25.1 > > >From 869efac3876ffe1f5faad1221cb4fedc7ebf6053 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Wed, 14 Apr 2021 10:05:59 +0200 >Subject: [PATCH 055/262] CVE-2020-25717 auth3: Simplify > check_samba4_security() > >First set up "server_info" in a local variable and once it's fully set >up, assign it to the out parameter "pserver_info". > >Pointer dereferencing obfuscates the code for me. > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 062a0c14c6ee0b74e7619af73747df59c5e67672) >--- > source3/auth/auth_samba4.c | 29 +++++++++++++++++------------ > 1 file changed, 17 insertions(+), 12 deletions(-) > >diff --git a/source3/auth/auth_samba4.c b/source3/auth/auth_samba4.c >index 6dee9c6f4116..418e2cfa56d1 100644 >--- a/source3/auth/auth_samba4.c >+++ b/source3/auth/auth_samba4.c >@@ -107,11 +107,12 @@ static struct server_id *new_server_id_task(TALLOC_CTX *mem_ctx) > * services the AD DC. It is tested via pdbtest. > */ > >-static NTSTATUS check_samba4_security(const struct auth_context *auth_context, >- void *my_private_data, >- TALLOC_CTX *mem_ctx, >- const struct auth_usersupplied_info *user_info, >- struct auth_serversupplied_info **server_info) >+static NTSTATUS check_samba4_security( >+ const struct auth_context *auth_context, >+ void *my_private_data, >+ TALLOC_CTX *mem_ctx, >+ const struct auth_usersupplied_info *user_info, >+ struct auth_serversupplied_info **pserver_info) > { > TALLOC_CTX *frame = talloc_stackframe(); > struct netr_SamInfo3 *info3 = NULL; >@@ -119,6 +120,7 @@ static NTSTATUS check_samba4_security(const struct auth_context *auth_context, > struct auth_user_info_dc *user_info_dc; > struct auth4_context *auth4_context; > uint8_t authoritative = 0; >+ struct auth_serversupplied_info *server_info = NULL; > > nt_status = make_auth4_context_s4(auth_context, mem_ctx, &auth4_context); > if (!NT_STATUS_IS_OK(nt_status)) { >@@ -160,17 +162,19 @@ static NTSTATUS check_samba4_security(const struct auth_context *auth_context, > } > > if (user_info->flags & USER_INFO_INFO3_AND_NO_AUTHZ) { >- *server_info = make_server_info(mem_ctx); >- if (*server_info == NULL) { >+ server_info = make_server_info(mem_ctx); >+ if (server_info == NULL) { > nt_status = NT_STATUS_NO_MEMORY; > goto done; > } >- (*server_info)->info3 = talloc_steal(*server_info, info3); >- >+ server_info->info3 = talloc_move(server_info, &info3); > } else { >- nt_status = make_server_info_info3(mem_ctx, user_info->client.account_name, >- user_info->mapped.domain_name, server_info, >- info3); >+ nt_status = make_server_info_info3( >+ mem_ctx, >+ user_info->client.account_name, >+ user_info->mapped.domain_name, >+ &server_info, >+ info3); > if (!NT_STATUS_IS_OK(nt_status)) { > DEBUG(10, ("make_server_info_info3 failed: %s\n", > nt_errstr(nt_status))); >@@ -178,6 +182,7 @@ static NTSTATUS check_samba4_security(const struct auth_context *auth_context, > } > } > >+ *pserver_info = server_info; > nt_status = NT_STATUS_OK; > > done: >-- >2.25.1 > > >From 638619137b92e0f40a5703e8ead938a65838c07a Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Tue, 13 Apr 2021 15:14:01 +0000 >Subject: [PATCH 056/262] CVE-2020-25717 auth: Simplify DEBUG statements in > make_auth3_context_for_ntlm() > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 8536bf7fce41c43bbed25f7ed4ce5775a1b9c0d5) >--- > source3/auth/auth.c | 15 +++++++++------ > 1 file changed, 9 insertions(+), 6 deletions(-) > >diff --git a/source3/auth/auth.c b/source3/auth/auth.c >index e8bb9d7821a2..12f7917b38d7 100644 >--- a/source3/auth/auth.c >+++ b/source3/auth/auth.c >@@ -529,28 +529,28 @@ NTSTATUS make_auth3_context_for_ntlm(TALLOC_CTX *mem_ctx, > struct auth_context **auth_context) > { > const char *methods = NULL; >+ const char *role = NULL; > > switch (lp_server_role()) { > case ROLE_ACTIVE_DIRECTORY_DC: >- DEBUG(5,("Making default auth method list for server role = " >- "'active directory domain controller'\n")); >+ role = "'active directory domain controller'"; > methods = "samba4"; > break; > case ROLE_DOMAIN_MEMBER: >- DEBUG(5,("Making default auth method list for server role = 'domain member'\n")); >+ role = "'domain member'"; > methods = "anonymous sam winbind sam_ignoredomain"; > break; > case ROLE_DOMAIN_BDC: > case ROLE_DOMAIN_PDC: >- DEBUG(5,("Making default auth method list for DC\n")); >+ role = "'DC'"; > methods = "anonymous sam winbind sam_ignoredomain"; > break; > case ROLE_STANDALONE: >- DEBUG(5,("Making default auth method list for server role = 'standalone server', encrypt passwords = yes\n")); > if (lp_encrypt_passwords()) { >+ role = "'standalone server', encrypt passwords = yes"; > methods = "anonymous sam_ignoredomain"; > } else { >- DEBUG(5,("Making default auth method list for server role = 'standalone server', encrypt passwords = no\n")); >+ role = "'standalone server', encrypt passwords = no"; > methods = "anonymous unix"; > } > break; >@@ -559,6 +559,9 @@ NTSTATUS make_auth3_context_for_ntlm(TALLOC_CTX *mem_ctx, > return NT_STATUS_UNSUCCESSFUL; > } > >+ DBG_INFO("Making default auth method list for server role = %s\n", >+ role); >+ > return make_auth_context_specific(mem_ctx, auth_context, methods); > } > >-- >2.25.1 > > >From 9bf5f6809b21b9147b1812e3b357587163e77746 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Wed, 14 Apr 2021 21:48:32 +0200 >Subject: [PATCH 057/262] CVE-2020-25717 auth4: Make auth_anonymous > pseudo-async > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 759573136876ef2b1b1c7484f99570d7de957e0d) >--- > source4/auth/ntlm/auth_anonymous.c | 66 ++++++++++++++++++++++++++---- > source4/auth/ntlm/wscript_build | 2 +- > 2 files changed, 58 insertions(+), 10 deletions(-) > >diff --git a/source4/auth/ntlm/auth_anonymous.c b/source4/auth/ntlm/auth_anonymous.c >index 83aeb431f5f4..a25aacaa1378 100644 >--- a/source4/auth/ntlm/auth_anonymous.c >+++ b/source4/auth/ntlm/auth_anonymous.c >@@ -20,9 +20,11 @@ > */ > > #include "includes.h" >+#include <tevent.h> > #include "auth/auth.h" > #include "auth/ntlm/auth_proto.h" > #include "param/param.h" >+#include "lib/util/tevent_ntstatus.h" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_AUTH >@@ -84,19 +86,65 @@ static NTSTATUS anonymous_want_check(struct auth_method_context *ctx, > * anonymou logons to be dealt with in one place. Non-anonymou logons 'fail' > * and pass onto the next module. > **/ >-static NTSTATUS anonymous_check_password(struct auth_method_context *ctx, >- TALLOC_CTX *mem_ctx, >- const struct auth_usersupplied_info *user_info, >- struct auth_user_info_dc **_user_info_dc, >- bool *authoritative) >+ >+struct anonymous_check_password_state { >+ struct auth_user_info_dc *user_info_dc; >+}; >+ >+static struct tevent_req *anonymous_check_password_send( >+ TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct auth_method_context *ctx, >+ const struct auth_usersupplied_info *user_info) >+{ >+ struct tevent_req *req = NULL; >+ struct anonymous_check_password_state *state = NULL; >+ NTSTATUS status; >+ >+ req = tevent_req_create( >+ mem_ctx, >+ &state, >+ struct anonymous_check_password_state); >+ if (req == NULL) { >+ return NULL; >+ } >+ >+ status = auth_anonymous_user_info_dc( >+ state, >+ lpcfg_netbios_name(ctx->auth_ctx->lp_ctx), >+ &state->user_info_dc); >+ if (tevent_req_nterror(req, status)) { >+ return tevent_req_post(req, ev); >+ } >+ tevent_req_done(req); >+ return tevent_req_post(req, ev); >+} >+ >+static NTSTATUS anonymous_check_password_recv( >+ struct tevent_req *req, >+ TALLOC_CTX *mem_ctx, >+ struct auth_user_info_dc **interim_info, >+ bool *authoritative) > { >- return auth_anonymous_user_info_dc(mem_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx), _user_info_dc); >+ struct anonymous_check_password_state *state = tevent_req_data( >+ req, struct anonymous_check_password_state); >+ NTSTATUS status; >+ >+ if (tevent_req_is_nterror(req, &status)) { >+ tevent_req_received(req); >+ return status; >+ } >+ *interim_info = talloc_move(mem_ctx, &state->user_info_dc); >+ tevent_req_received(req); >+ return NT_STATUS_OK; > } > >+ > static const struct auth_operations anonymous_auth_ops = { >- .name = "anonymous", >- .want_check = anonymous_want_check, >- .check_password = anonymous_check_password >+ .name = "anonymous", >+ .want_check = anonymous_want_check, >+ .check_password_send = anonymous_check_password_send, >+ .check_password_recv = anonymous_check_password_recv, > }; > > _PUBLIC_ NTSTATUS auth4_anonymous_init(TALLOC_CTX *ctx) >diff --git a/source4/auth/ntlm/wscript_build b/source4/auth/ntlm/wscript_build >index 04a760c3e495..6ea0c4d7e3a8 100644 >--- a/source4/auth/ntlm/wscript_build >+++ b/source4/auth/ntlm/wscript_build >@@ -12,7 +12,7 @@ bld.SAMBA_MODULE('auth4_anonymous', > source='auth_anonymous.c', > subsystem='auth4', > init_function='auth4_anonymous_init', >- deps='talloc' >+ deps='tevent' > ) > > >-- >2.25.1 > > >From c171c0a9b96acf9052328c85b1d92882a130e458 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Wed, 14 Apr 2021 22:22:18 +0200 >Subject: [PATCH 058/262] CVE-2020-25717 auth4: Make auth_developer > pseudo-async > >This is a simpler approach to really just wrap the code. > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 43a1e42815718591faa8d526319b96d089a758fa) >--- > source4/auth/ntlm/auth_developer.c | 61 +++++++++++++++++++++++++++++- > source4/auth/ntlm/wscript_build | 2 +- > 2 files changed, 61 insertions(+), 2 deletions(-) > >diff --git a/source4/auth/ntlm/auth_developer.c b/source4/auth/ntlm/auth_developer.c >index b655283975b1..551f0ae16053 100644 >--- a/source4/auth/ntlm/auth_developer.c >+++ b/source4/auth/ntlm/auth_developer.c >@@ -20,9 +20,11 @@ > */ > > #include "includes.h" >+#include <tevent.h> > #include "auth/auth.h" > #include "auth/ntlm/auth_proto.h" > #include "libcli/security/security.h" >+#include "lib/util/tevent_ntstatus.h" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_AUTH >@@ -135,10 +137,67 @@ static NTSTATUS name_to_ntstatus_check_password(struct auth_method_context *ctx, > return nt_status; > } > >+struct name_to_ntstatus_check_password_state { >+ struct auth_user_info_dc *user_info_dc; >+ bool authoritative; >+}; >+ >+static struct tevent_req *name_to_ntstatus_check_password_send( >+ TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct auth_method_context *ctx, >+ const struct auth_usersupplied_info *user_info) >+{ >+ struct tevent_req *req = NULL; >+ struct name_to_ntstatus_check_password_state *state = NULL; >+ NTSTATUS status; >+ >+ req = tevent_req_create( >+ mem_ctx, >+ &state, >+ struct name_to_ntstatus_check_password_state); >+ if (req == NULL) { >+ return NULL; >+ } >+ >+ status = name_to_ntstatus_check_password( >+ ctx, >+ state, >+ user_info, >+ &state->user_info_dc, >+ &state->authoritative); >+ if (tevent_req_nterror(req, status)) { >+ return tevent_req_post(req, ev); >+ } >+ tevent_req_done(req); >+ return tevent_req_post(req, ev); >+} >+ >+static NTSTATUS name_to_ntstatus_check_password_recv( >+ struct tevent_req *req, >+ TALLOC_CTX *mem_ctx, >+ struct auth_user_info_dc **interim_info, >+ bool *authoritative) >+{ >+ struct name_to_ntstatus_check_password_state *state = tevent_req_data( >+ req, struct name_to_ntstatus_check_password_state); >+ NTSTATUS status; >+ >+ if (tevent_req_is_nterror(req, &status)) { >+ tevent_req_received(req); >+ return status; >+ } >+ *interim_info = talloc_move(mem_ctx, &state->user_info_dc); >+ *authoritative = state->authoritative; >+ tevent_req_received(req); >+ return NT_STATUS_OK; >+} >+ > static const struct auth_operations name_to_ntstatus_auth_ops = { > .name = "name_to_ntstatus", > .want_check = name_to_ntstatus_want_check, >- .check_password = name_to_ntstatus_check_password >+ .check_password_send = name_to_ntstatus_check_password_send, >+ .check_password_recv = name_to_ntstatus_check_password_recv, > }; > > _PUBLIC_ NTSTATUS auth4_developer_init(TALLOC_CTX *ctx) >diff --git a/source4/auth/ntlm/wscript_build b/source4/auth/ntlm/wscript_build >index 6ea0c4d7e3a8..1ee8d79563a1 100644 >--- a/source4/auth/ntlm/wscript_build >+++ b/source4/auth/ntlm/wscript_build >@@ -28,7 +28,7 @@ bld.SAMBA_MODULE('auth4_developer', > source='auth_developer.c', > subsystem='auth4', > init_function='auth4_developer_init', >- deps='talloc' >+ deps='tevent' > ) > > >-- >2.25.1 > > >From 923001ef7eb0bf06992b7c746aa74e5359fb8593 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Wed, 14 Apr 2021 21:59:55 +0200 >Subject: [PATCH 059/262] CVE-2020-25717 auth4: Make auth_unix pseudo-async > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit a6f42ab8a778b9863990da3112c2e868cd006303) >--- > source4/auth/ntlm/auth_unix.c | 85 ++++++++++++++++++++++++----------- > 1 file changed, 59 insertions(+), 26 deletions(-) > >diff --git a/source4/auth/ntlm/auth_unix.c b/source4/auth/ntlm/auth_unix.c >index 67cd5f3dc44c..cfe4f1a073f1 100644 >--- a/source4/auth/ntlm/auth_unix.c >+++ b/source4/auth/ntlm/auth_unix.c >@@ -27,6 +27,7 @@ > #include "lib/tsocket/tsocket.h" > #include "../libcli/auth/pam_errors.h" > #include "param/param.h" >+#include "lib/util/tevent_ntstatus.h" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_AUTH >@@ -713,46 +714,78 @@ static NTSTATUS authunix_want_check(struct auth_method_context *ctx, > return NT_STATUS_OK; > } > >-static NTSTATUS authunix_check_password(struct auth_method_context *ctx, >- TALLOC_CTX *mem_ctx, >- const struct auth_usersupplied_info *user_info, >- struct auth_user_info_dc **user_info_dc, >- bool *authoritative) >+struct authunix_check_password_state { >+ struct auth_user_info_dc *user_info_dc; >+}; >+ >+static struct tevent_req *authunix_check_password_send( >+ TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct auth_method_context *ctx, >+ const struct auth_usersupplied_info *user_info) > { >- TALLOC_CTX *check_ctx; >- NTSTATUS nt_status; >- struct passwd *pwd; >+ struct tevent_req *req = NULL; >+ struct authunix_check_password_state *state = NULL; >+ struct passwd *pwd = NULL; >+ NTSTATUS status; > >- if (user_info->password_state != AUTH_PASSWORD_PLAIN) { >- return NT_STATUS_INVALID_PARAMETER; >+ req = tevent_req_create( >+ mem_ctx, >+ &state, >+ struct authunix_check_password_state); >+ if (req == NULL) { >+ return NULL; > } > >- check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password"); >- if (check_ctx == NULL) { >- return NT_STATUS_NO_MEMORY; >+ if (user_info->password_state != AUTH_PASSWORD_PLAIN) { >+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); >+ return tevent_req_post(req, ev); > } > >- nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd); >- if (!NT_STATUS_IS_OK(nt_status)) { >- talloc_free(check_ctx); >- return nt_status; >+ status = check_unix_password( >+ state, ctx->auth_ctx->lp_ctx, user_info, &pwd); >+ if (tevent_req_nterror(req, status)) { >+ return tevent_req_post(req, ev); > } > >- nt_status = authunix_make_user_info_dc(mem_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx), >- user_info, pwd, user_info_dc); >- if (!NT_STATUS_IS_OK(nt_status)) { >- talloc_free(check_ctx); >- return nt_status; >+ status = authunix_make_user_info_dc( >+ state, >+ lpcfg_netbios_name(ctx->auth_ctx->lp_ctx), >+ user_info, >+ pwd, >+ &state->user_info_dc); >+ if (tevent_req_nterror(req, status)) { >+ return tevent_req_post(req, ev); > } > >- talloc_free(check_ctx); >+ tevent_req_done(req); >+ return tevent_req_post(req, ev); >+} >+ >+static NTSTATUS authunix_check_password_recv( >+ struct tevent_req *req, >+ TALLOC_CTX *mem_ctx, >+ struct auth_user_info_dc **interim_info, >+ bool *authoritative) >+{ >+ struct authunix_check_password_state *state = tevent_req_data( >+ req, struct authunix_check_password_state); >+ NTSTATUS status; >+ >+ if (tevent_req_is_nterror(req, &status)) { >+ tevent_req_received(req); >+ return status; >+ } >+ *interim_info = talloc_move(mem_ctx, &state->user_info_dc); >+ tevent_req_received(req); > return NT_STATUS_OK; > } > > static const struct auth_operations unix_ops = { >- .name = "unix", >- .want_check = authunix_want_check, >- .check_password = authunix_check_password >+ .name = "unix", >+ .want_check = authunix_want_check, >+ .check_password_send = authunix_check_password_send, >+ .check_password_recv = authunix_check_password_recv, > }; > > _PUBLIC_ NTSTATUS auth4_unix_init(TALLOC_CTX *ctx) >-- >2.25.1 > > >From f2ebaffbcce8d2acb41aa37a61f7d77e4a556e7b Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Thu, 15 Apr 2021 10:04:21 +0200 >Subject: [PATCH 060/262] CVE-2020-25717 auth4: Make auth_sam pseudo-async > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit f852fb4cd4e2bcd676a9ea104c5bf00979771eed) >--- > source4/auth/ntlm/auth_sam.c | 69 ++++++++++++++++++++++++++++++++++-- > 1 file changed, 67 insertions(+), 2 deletions(-) > >diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c >index 70eddc12c53c..e4ebeae75234 100644 >--- a/source4/auth/ntlm/auth_sam.c >+++ b/source4/auth/ntlm/auth_sam.c >@@ -36,6 +36,7 @@ > #include "lib/messaging/irpc.h" > #include "libcli/auth/libcli_auth.h" > #include "libds/common/roles.h" >+#include "lib/util/tevent_ntstatus.h" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_AUTH >@@ -732,6 +733,68 @@ static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx > return NT_STATUS_OK; > } > >+struct authsam_check_password_state { >+ struct auth_user_info_dc *user_info_dc; >+ bool authoritative; >+}; >+ >+static struct tevent_req *authsam_check_password_send( >+ TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct auth_method_context *ctx, >+ const struct auth_usersupplied_info *user_info) >+{ >+ struct tevent_req *req = NULL; >+ struct authsam_check_password_state *state = NULL; >+ NTSTATUS status; >+ >+ req = tevent_req_create( >+ mem_ctx, &state, struct authsam_check_password_state); >+ if (req == NULL) { >+ return NULL; >+ } >+ /* >+ * authsam_check_password_internals() sets this to false in >+ * the rodc case, otherwise it leaves it untouched. Default to >+ * "we're authoritative". >+ */ >+ state->authoritative = true; >+ >+ status = authsam_check_password_internals( >+ ctx, >+ state, >+ user_info, >+ &state->user_info_dc, >+ &state->authoritative); >+ if (tevent_req_nterror(req, status)) { >+ return tevent_req_post(req, ev); >+ } >+ >+ tevent_req_done(req); >+ return tevent_req_post(req, ev); >+} >+ >+static NTSTATUS authsam_check_password_recv( >+ struct tevent_req *req, >+ TALLOC_CTX *mem_ctx, >+ struct auth_user_info_dc **interim_info, >+ bool *authoritative) >+{ >+ struct authsam_check_password_state *state = tevent_req_data( >+ req, struct authsam_check_password_state); >+ NTSTATUS status; >+ >+ *authoritative = state->authoritative; >+ >+ if (tevent_req_is_nterror(req, &status)) { >+ tevent_req_received(req); >+ return status; >+ } >+ *interim_info = talloc_move(mem_ctx, &state->user_info_dc); >+ tevent_req_received(req); >+ return NT_STATUS_OK; >+} >+ > static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx, > TALLOC_CTX *mem_ctx, > const struct auth_usersupplied_info *user_info) >@@ -887,14 +950,16 @@ static NTSTATUS authsam_get_user_info_dc_principal_wrapper(TALLOC_CTX *mem_ctx, > static const struct auth_operations sam_ignoredomain_ops = { > .name = "sam_ignoredomain", > .want_check = authsam_ignoredomain_want_check, >- .check_password = authsam_check_password_internals, >+ .check_password_send = authsam_check_password_send, >+ .check_password_recv = authsam_check_password_recv, > .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, > }; > > static const struct auth_operations sam_ops = { > .name = "sam", > .want_check = authsam_want_check, >- .check_password = authsam_check_password_internals, >+ .check_password_send = authsam_check_password_send, >+ .check_password_recv = authsam_check_password_recv, > .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, > }; > >-- >2.25.1 > > >From 92bca7824cc0c7a17834b9c43459b3a4c0933a83 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Wed, 14 Apr 2021 22:24:44 +0200 >Subject: [PATCH 061/262] CVE-2020-25717 auth4: Remove sync check_password from > auth_operations > >Remove complexity in the data structures, and pushes the async-ness >one level down. > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >(cherry picked from commit 254af19ba89b4c42e5f45ec731e6577d2fcc6736) >--- > source4/auth/auth.h | 4 ---- > source4/auth/ntlm/auth.c | 44 ++++------------------------------------ > 2 files changed, 4 insertions(+), 44 deletions(-) > >diff --git a/source4/auth/auth.h b/source4/auth/auth.h >index 51895c9259f3..3f9fb1ae3cbc 100644 >--- a/source4/auth/auth.h >+++ b/source4/auth/auth.h >@@ -61,10 +61,6 @@ struct auth_operations { > > /* Given the user supplied info, check a password */ > >- NTSTATUS (*check_password)(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, >- const struct auth_usersupplied_info *user_info, >- struct auth_user_info_dc **interim_info, >- bool *authoritative); > struct tevent_req *(*check_password_send)(TALLOC_CTX *mem_ctx, > struct tevent_context *ev, > struct auth_method_context *ctx, >diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c >index ead5326705e6..1aa2e3b065fc 100644 >--- a/source4/auth/ntlm/auth.c >+++ b/source4/auth/ntlm/auth.c >@@ -331,7 +331,6 @@ static void auth_check_password_next(struct tevent_req *req) > struct auth_check_password_state *state = > tevent_req_data(req, struct auth_check_password_state); > struct tevent_req *subreq = NULL; >- bool authoritative = true; > NTSTATUS status; > > if (state->method == NULL) { >@@ -356,47 +355,12 @@ static void auth_check_password_next(struct tevent_req *req) > return; > } > >- if (state->method->ops->check_password_send != NULL) { >- subreq = state->method->ops->check_password_send(state, >- state->ev, >- state->method, >- state->user_info); >- if (tevent_req_nomem(subreq, req)) { >- return; >- } >- tevent_req_set_callback(subreq, >- auth_check_password_done, >- req); >- return; >- } >- >- if (state->method->ops->check_password == NULL) { >- tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >- return; >- } >- >- status = state->method->ops->check_password(state->method, >- state, >- state->user_info, >- &state->user_info_dc, >- &authoritative); >- if (!authoritative || >- NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) { >- DEBUG(11,("auth_check_password_send: " >- "%s passes to the next method\n", >- state->method->ops->name)); >- state->method = state->method->next; >- auth_check_password_next(req); >- return; >- } >- >- /* the backend has handled the request */ >- >- if (tevent_req_nterror(req, status)) { >+ subreq = state->method->ops->check_password_send( >+ state, state->ev, state->method, state->user_info); >+ if (tevent_req_nomem(subreq, req)) { > return; > } >- >- tevent_req_done(req); >+ tevent_req_set_callback(subreq, auth_check_password_done, req); > } > > static void auth_check_password_done(struct tevent_req *subreq) >-- >2.25.1 > > >From 7ae6928d6b54a184c9da4bffc9326ce39884d44f Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 2 Nov 2021 15:39:53 +0100 >Subject: [PATCH 062/262] CVE-2020-25719 selftest/knownfail_mit_kdc: Add > pointless knownfail to allow a later cherry-pick to apply cleanly > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 >--- > selftest/knownfail_mit_kdc | 1 + > 1 file changed, 1 insertion(+) > >diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc >index 0f845fb9b1ce..4fc68ffd854c 100644 >--- a/selftest/knownfail_mit_kdc >+++ b/selftest/knownfail_mit_kdc >@@ -276,6 +276,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_ldap_service_ticket\(ad_dc\) > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_get_ticket_for_host_service_of_machine_account\(ad_dc\) > # >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac\(ad_dc\) > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_request_no_pac\(ad_dc\) > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_service_no_auth_data_required\(ad_dc\) > # >-- >2.25.1 > > >From cdbce9d9597293ee02bb9c8a77b61c85de6aef3c Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 13 Sep 2021 21:48:13 +1200 >Subject: [PATCH 063/262] CVE-2020-25722 selftest: Move > self.assertRaisesLdbError() to samba.tests.TestCase > >This is easier to reason with regarding which cases should work >and which cases should fail, avoiding issues where more success >than expected would be OK because a self.fail() was missed in a >try: block. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >(cherry picked from commit 298515cac2f35082483c2b4e4b7dbfe4df1d2e0c) >--- > python/samba/tests/__init__.py | 25 +++++++++++++++++++ > .../dsdb/tests/python/linked_attributes.py | 21 ---------------- > source4/dsdb/tests/python/subtree_rename.py | 25 ------------------- > 3 files changed, 25 insertions(+), 46 deletions(-) > >diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py >index d895802c34f0..f47455196174 100644 >--- a/python/samba/tests/__init__.py >+++ b/python/samba/tests/__init__.py >@@ -298,6 +298,31 @@ class TestCase(unittest.TestCase): > > self.fail(msg) > >+ def assertRaisesLdbError(self, errcode, message, f, *args, **kwargs): >+ """Assert a function raises a particular LdbError.""" >+ try: >+ f(*args, **kwargs) >+ except ldb.LdbError as e: >+ (num, msg) = e.args >+ if num != errcode: >+ lut = {v: k for k, v in vars(ldb).items() >+ if k.startswith('ERR_') and isinstance(v, int)} >+ self.fail("%s, expected " >+ "LdbError %s, (%d) " >+ "got %s (%d) " >+ "%s" % (message, >+ lut.get(errcode), errcode, >+ lut.get(num), num, >+ msg)) >+ else: >+ lut = {v: k for k, v in vars(ldb).items() >+ if k.startswith('ERR_') and isinstance(v, int)} >+ self.fail("%s, expected " >+ "LdbError %s, (%d) " >+ "but we got success" % (message, >+ lut.get(errcode), >+ errcode)) >+ > > class LdbTestCase(TestCase): > """Trivial test case for running tests against a LDB.""" >diff --git a/source4/dsdb/tests/python/linked_attributes.py b/source4/dsdb/tests/python/linked_attributes.py >index 533fa9437365..5c6bb7ebac81 100644 >--- a/source4/dsdb/tests/python/linked_attributes.py >+++ b/source4/dsdb/tests/python/linked_attributes.py >@@ -166,27 +166,6 @@ class LATests(samba.tests.TestCase): > attrs=['objectGUID']) > return str(misc.GUID(res[0]['objectGUID'][0])) > >- def assertRaisesLdbError(self, errcode, msg, f, *args, **kwargs): >- """Assert a function raises a particular LdbError.""" >- try: >- f(*args, **kwargs) >- except ldb.LdbError as e: >- (num, msg) = e.args >- if num != errcode: >- lut = {v: k for k, v in vars(ldb).items() >- if k.startswith('ERR_') and isinstance(v, int)} >- self.fail("%s, expected " >- "LdbError %s, (%d) " >- "got %s (%d)" % (msg, >- lut.get(errcode), errcode, >- lut.get(num), num)) >- else: >- lut = {v: k for k, v in vars(ldb).items() >- if k.startswith('ERR_') and isinstance(v, int)} >- self.fail("%s, expected " >- "LdbError %s, (%d) " >- "but we got success" % (msg, lut.get(errcode), errcode)) >- > def _test_la_backlinks(self, reveal=False): > tag = 'backlinks' > kwargs = {} >diff --git a/source4/dsdb/tests/python/subtree_rename.py b/source4/dsdb/tests/python/subtree_rename.py >index c4f6bc7a160b..e422c2e2b010 100644 >--- a/source4/dsdb/tests/python/subtree_rename.py >+++ b/source4/dsdb/tests/python/subtree_rename.py >@@ -201,31 +201,6 @@ class SubtreeRenameTests(samba.tests.TestCase): > attrs=['objectGUID']) > return str(misc.GUID(res[0]['objectGUID'][0])) > >- def assertRaisesLdbError(self, errcode, message, f, *args, **kwargs): >- """Assert a function raises a particular LdbError.""" >- try: >- f(*args, **kwargs) >- except ldb.LdbError as e: >- (num, msg) = e.args >- if num != errcode: >- lut = {v: k for k, v in vars(ldb).items() >- if k.startswith('ERR_') and isinstance(v, int)} >- self.fail("%s, expected " >- "LdbError %s, (%d) " >- "got %s (%d) " >- "%s" % (message, >- lut.get(errcode), errcode, >- lut.get(num), num, >- msg)) >- else: >- lut = {v: k for k, v in vars(ldb).items() >- if k.startswith('ERR_') and isinstance(v, int)} >- self.fail("%s, expected " >- "LdbError %s, (%d) " >- "but we got success" % (message, >- lut.get(errcode), >- errcode)) >- > def test_la_move_ou_tree(self): > tag = 'move_tree' > >-- >2.25.1 > > >From 09caff9c232e11d18198ec3654f9c7d4051973f8 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 30 Aug 2021 10:07:31 +1200 >Subject: [PATCH 064/262] CVE-2020-25722 selftest: Modernise > user_account_control.py tests use a common self.OU > >We set and use a single self.OU to ensure consistancy and >reduce string duplication. > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 >(cherry picked from commit 8b078bbf8717b9407cdbc1588dd065164ab78e1b) >--- > .../dsdb/tests/python/user_account_control.py | 46 +++++++++---------- > 1 file changed, 23 insertions(+), 23 deletions(-) > >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index 2d62d4c32b19..cb614b165e59 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -90,7 +90,7 @@ class UserAccountControlTests(samba.tests.TestCase): > def add_computer_ldap(self, computername, others=None, samdb=None): > if samdb is None: > samdb = self.samdb >- dn = "CN=%s,OU=test_computer_ou1,%s" % (computername, self.base_dn) >+ dn = "CN=%s,%s" % (computername, self.OU) > domainname = ldb.Dn(self.samdb, self.samdb.domain_dn()).canonical_str().replace("/", "") > samaccountname = "%s$" % computername > dnshostname = "%s.%s" % (computername, domainname) >@@ -131,8 +131,9 @@ class UserAccountControlTests(samba.tests.TestCase): > self.unpriv_user_pw = "samba123@" > self.unpriv_creds = self.get_creds(self.unpriv_user, self.unpriv_user_pw) > >- delete_force(self.admin_samdb, "CN=testcomputer-t,OU=test_computer_ou1,%s" % (self.base_dn)) >- delete_force(self.admin_samdb, "OU=test_computer_ou1,%s" % (self.base_dn)) >+ self.OU = "OU=test_computer_ou1,%s" % (self.base_dn) >+ >+ delete_force(self.admin_samdb, self.OU, controls=["tree_delete:0"]) > delete_force(self.admin_samdb, "CN=%s,CN=Users,%s" % (self.unpriv_user, self.base_dn)) > > self.admin_samdb.newuser(self.unpriv_user, self.unpriv_user_pw) >@@ -151,27 +152,27 @@ class UserAccountControlTests(samba.tests.TestCase): > self.samr_domain = self.samr.OpenDomain(self.samr_handle, security.SEC_FLAG_MAXIMUM_ALLOWED, self.domain_sid) > > self.sd_utils = sd_utils.SDUtils(self.admin_samdb) >+ self.admin_samdb.create_ou(self.OU) > >- self.admin_samdb.create_ou("OU=test_computer_ou1," + self.base_dn) > self.unpriv_user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.unpriv_user_sid) > >- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn) >+ old_sd = self.sd_utils.read_sd_on_dn(self.OU) > >- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod) >+ self.sd_utils.dacl_add_ace(self.OU, mod) > > self.add_computer_ldap("testcomputer-t") > >- self.sd_utils.modify_sd_on_dn("OU=test_computer_ou1," + self.base_dn, old_sd) >+ self.sd_utils.modify_sd_on_dn(self.OU, old_sd) > > self.computernames = ["testcomputer-0"] > > # Get the SD of the template account, then force it to match > # what we expect for SeMachineAccountPrivilege accounts, so we > # can confirm we created the accounts correctly >- self.sd_reference_cc = self.sd_utils.read_sd_on_dn("CN=testcomputer-t,OU=test_computer_ou1,%s" % (self.base_dn)) >+ self.sd_reference_cc = self.sd_utils.read_sd_on_dn("CN=testcomputer-t,%s" % (self.OU)) > >- self.sd_reference_modify = self.sd_utils.read_sd_on_dn("CN=testcomputer-t,OU=test_computer_ou1,%s" % (self.base_dn)) >+ self.sd_reference_modify = self.sd_utils.read_sd_on_dn("CN=testcomputer-t,%s" % (self.OU)) > for ace in self.sd_reference_modify.dacl.aces: > if ace.type == security.SEC_ACE_TYPE_ACCESS_ALLOWED and ace.trustee == self.unpriv_user_sid: > ace.access_mask = ace.access_mask | security.SEC_ADS_SELF_WRITE | security.SEC_ADS_WRITE_PROP >@@ -191,9 +192,8 @@ class UserAccountControlTests(samba.tests.TestCase): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) > >- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn) >- >- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod) >+ old_sd = self.sd_utils.read_sd_on_dn(self.OU) >+ self.sd_utils.dacl_add_ace(self.OU, mod) > > computername = self.computernames[0] > sd = ldb.MessageElement((ndr_pack(self.sd_reference_modify)), >@@ -276,9 +276,9 @@ class UserAccountControlTests(samba.tests.TestCase): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) > >- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn) >+ old_sd = self.sd_utils.read_sd_on_dn(self.OU) > >- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod) >+ self.sd_utils.dacl_add_ace(self.OU, mod) > > computername = self.computernames[0] > self.add_computer_ldap(computername) >@@ -392,9 +392,9 @@ class UserAccountControlTests(samba.tests.TestCase): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) > >- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn) >+ old_sd = self.sd_utils.read_sd_on_dn(self.OU) > >- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod) >+ self.sd_utils.dacl_add_ace(self.OU, mod) > > computername = self.computernames[0] > self.add_computer_ldap(computername) >@@ -446,9 +446,9 @@ class UserAccountControlTests(samba.tests.TestCase): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) > >- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn) >+ old_sd = self.sd_utils.read_sd_on_dn(self.OU) > >- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod) >+ self.sd_utils.dacl_add_ace(self.OU, mod) > > computername = self.computernames[0] > self.add_computer_ldap(computername, others={"userAccountControl": [str(account_type)]}) >@@ -621,9 +621,9 @@ class UserAccountControlTests(samba.tests.TestCase): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) > >- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn) >+ old_sd = self.sd_utils.read_sd_on_dn(self.OU) > >- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod) >+ self.sd_utils.dacl_add_ace(self.OU, mod) > > invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT, UF_PARTIAL_SECRETS_ACCOUNT]) > # These bits are privileged, but authenticated users have that CAR by default, so this is a pain to test >@@ -637,7 +637,7 @@ class UserAccountControlTests(samba.tests.TestCase): > for bit in bits: > try: > self.add_computer_ldap(computername, others={"userAccountControl": [str(bit)]}) >- delete_force(self.admin_samdb, "CN=%s,OU=test_computer_ou1,%s" % (computername, self.base_dn)) >+ delete_force(self.admin_samdb, "CN=%s,%s" % (computername, self.OU)) > if bit in priv_bits: > self.fail("Unexpectdly able to set userAccountControl bit 0x%08X on %s" % (bit, computername)) > >@@ -659,9 +659,9 @@ class UserAccountControlTests(samba.tests.TestCase): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) > >- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn) >+ old_sd = self.sd_utils.read_sd_on_dn(self.OU) > >- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod) >+ self.sd_utils.dacl_add_ace(self.OU, mod) > try: > # When creating a new object, you can not ever set the primaryGroupID > self.add_computer_ldap(computername, others={"primaryGroupID": [str(security.DOMAIN_RID_ADMINS)]}) >-- >2.25.1 > > >From cc9c13c44678453b372050a6f2caa916e384f0e0 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 30 Aug 2021 10:10:56 +1200 >Subject: [PATCH 065/262] CVE-2020-25722 selftest: Use addCleanup rather than > tearDown in user_account_control.py > >self.addCleanup() is called regardless of the test failure or error status >and so is more reliable, particularly during development. > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 >(cherry picked from commit 8c455268165f0bbfce17407df2c1746a0e03f828) >--- > source4/dsdb/tests/python/user_account_control.py | 10 ++-------- > 1 file changed, 2 insertions(+), 8 deletions(-) > >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index cb614b165e59..81664079adfe 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -144,6 +144,7 @@ class UserAccountControlTests(samba.tests.TestCase): > > self.unpriv_user_sid = ndr_unpack(security.dom_sid, res[0]["objectSid"][0]) > self.unpriv_user_dn = res[0].dn >+ self.addCleanup(self.admin_samdb.delete, self.unpriv_user_dn) > > self.samdb = SamDB(url=ldaphost, credentials=self.unpriv_creds, lp=lp) > >@@ -153,6 +154,7 @@ class UserAccountControlTests(samba.tests.TestCase): > > self.sd_utils = sd_utils.SDUtils(self.admin_samdb) > self.admin_samdb.create_ou(self.OU) >+ self.addCleanup(self.admin_samdb.delete, self.OU, ["tree_delete:1"]) > > self.unpriv_user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.unpriv_user_sid) >@@ -180,14 +182,6 @@ class UserAccountControlTests(samba.tests.TestCase): > # Now reconnect without domain admin rights > self.samdb = SamDB(url=ldaphost, credentials=self.unpriv_creds, lp=lp) > >- def tearDown(self): >- super(UserAccountControlTests, self).tearDown() >- for computername in self.computernames: >- delete_force(self.admin_samdb, "CN=%s,OU=test_computer_ou1,%s" % (computername, self.base_dn)) >- delete_force(self.admin_samdb, "CN=testcomputer-t,OU=test_computer_ou1,%s" % (self.base_dn)) >- delete_force(self.admin_samdb, "OU=test_computer_ou1,%s" % (self.base_dn)) >- delete_force(self.admin_samdb, "CN=%s,CN=Users,%s" % (self.unpriv_user, self.base_dn)) >- > def test_add_computer_sd_cc(self): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) >-- >2.25.1 > > >From 050b8440612f22c885cc67ac10af781c9df6db87 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 30 Aug 2021 13:03:15 +1200 >Subject: [PATCH 066/262] CVE-2020-25722 pydsdb: Add API to return strings of > known UF_ flags > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 >(cherry picked from commit fb6c0b9e2a10c9559d3e056bb020bd2c990da998) >--- > libds/common/flag_mapping.c | 50 +++++++++++++++++++++++++++++ > libds/common/flag_mapping.h | 1 + > libds/common/flags.h | 5 +++ > python/samba/tests/dsdb_api.py | 57 ++++++++++++++++++++++++++++++++++ > selftest/tests.py | 1 + > source4/dsdb/pydsdb.c | 30 ++++++++++++++++++ > 6 files changed, 144 insertions(+) > create mode 100644 python/samba/tests/dsdb_api.py > >diff --git a/libds/common/flag_mapping.c b/libds/common/flag_mapping.c >index ddc8ec5c1982..020922db6599 100644 >--- a/libds/common/flag_mapping.c >+++ b/libds/common/flag_mapping.c >@@ -164,3 +164,53 @@ uint32_t ds_uf2prim_group_rid(uint32_t uf) > > return prim_group_rid; > } >+ >+#define FLAG(x) { .name = #x, .uf = x } >+struct { >+ const char *name; >+ uint32_t uf; >+} user_account_control_name_map[] = { >+ FLAG(UF_SCRIPT), >+ FLAG(UF_ACCOUNTDISABLE), >+ FLAG(UF_00000004), >+ FLAG(UF_HOMEDIR_REQUIRED), >+ FLAG(UF_LOCKOUT), >+ FLAG(UF_PASSWD_NOTREQD), >+ FLAG(UF_PASSWD_CANT_CHANGE), >+ FLAG(UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED), >+ >+ FLAG(UF_TEMP_DUPLICATE_ACCOUNT), >+ FLAG(UF_NORMAL_ACCOUNT), >+ FLAG(UF_00000400), >+ FLAG(UF_INTERDOMAIN_TRUST_ACCOUNT), >+ >+ FLAG(UF_WORKSTATION_TRUST_ACCOUNT), >+ FLAG(UF_SERVER_TRUST_ACCOUNT), >+ FLAG(UF_00004000), >+ FLAG(UF_00008000), >+ >+ FLAG(UF_DONT_EXPIRE_PASSWD), >+ FLAG(UF_MNS_LOGON_ACCOUNT), >+ FLAG(UF_SMARTCARD_REQUIRED), >+ FLAG(UF_TRUSTED_FOR_DELEGATION), >+ >+ FLAG(UF_NOT_DELEGATED), >+ FLAG(UF_USE_DES_KEY_ONLY), >+ FLAG(UF_DONT_REQUIRE_PREAUTH), >+ FLAG(UF_PASSWORD_EXPIRED), >+ FLAG(UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION), >+ FLAG(UF_NO_AUTH_DATA_REQUIRED), >+ FLAG(UF_PARTIAL_SECRETS_ACCOUNT), >+ FLAG(UF_USE_AES_KEYS) >+}; >+ >+const char *dsdb_user_account_control_flag_bit_to_string(uint32_t uf) >+{ >+ int i; >+ for (i=0; i < ARRAY_SIZE(user_account_control_name_map); i++) { >+ if (uf == user_account_control_name_map[i].uf) { >+ return user_account_control_name_map[i].name; >+ } >+ } >+ return NULL; >+} >diff --git a/libds/common/flag_mapping.h b/libds/common/flag_mapping.h >index ae721da894a0..f08d5593af6d 100644 >--- a/libds/common/flag_mapping.h >+++ b/libds/common/flag_mapping.h >@@ -31,5 +31,6 @@ uint32_t ds_uf2atype(uint32_t uf); > uint32_t ds_gtype2atype(uint32_t gtype); > enum lsa_SidType ds_atype_map(uint32_t atype); > uint32_t ds_uf2prim_group_rid(uint32_t uf); >+const char *dsdb_user_account_control_flag_bit_to_string(uint32_t uf); > > #endif /* __LIBDS_COMMON_FLAG_MAPPING_H__ */ >diff --git a/libds/common/flags.h b/libds/common/flags.h >index d436f2bafd81..75e04b0c488b 100644 >--- a/libds/common/flags.h >+++ b/libds/common/flags.h >@@ -18,6 +18,8 @@ > along with this program. If not, see <http://www.gnu.org/licenses/>. > */ > >+/* Please keep this list in sync with the flag_mapping.c and pydsdb.c */ >+ > /* User flags for "userAccountControl" */ > #define UF_SCRIPT 0x00000001 /* NT or Lan Manager Login script must be executed */ > #define UF_ACCOUNTDISABLE 0x00000002 >@@ -53,6 +55,9 @@ > #define UF_PARTIAL_SECRETS_ACCOUNT 0x04000000 > #define UF_USE_AES_KEYS 0x08000000 > >+/* Please keep this list in sync with the flag_mapping.c and pydsdb.c */ >+ >+ > #define UF_TRUST_ACCOUNT_MASK (\ > UF_INTERDOMAIN_TRUST_ACCOUNT |\ > UF_WORKSTATION_TRUST_ACCOUNT |\ >diff --git a/python/samba/tests/dsdb_api.py b/python/samba/tests/dsdb_api.py >new file mode 100644 >index 000000000000..997407917af4 >--- /dev/null >+++ b/python/samba/tests/dsdb_api.py >@@ -0,0 +1,57 @@ >+# Unix SMB/CIFS implementation. Tests for dsdb >+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2021 >+# >+# 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 <http://www.gnu.org/licenses/>. >+# >+ >+"""Tests for samba.dsdb.""" >+ >+from samba.tests import TestCase, DynamicTestCase >+from samba.dsdb import user_account_control_flag_bit_to_string >+import samba >+ >+ >+@DynamicTestCase >+class DsdbFlagTests(TestCase): >+ >+ @classmethod >+ def setUpDynamicTestCases(cls): >+ >+ for x in dir(samba.dsdb): >+ if x.startswith("UF_"): >+ cls.generate_dynamic_test("test", >+ x, >+ x, >+ getattr(samba.dsdb, x)) >+ >+ >+ def _test_with_args(self, uf_string, uf_bit): >+ self.assertEqual(user_account_control_flag_bit_to_string(uf_bit), >+ uf_string) >+ >+ >+ def test_not_a_flag(self): >+ self.assertRaises(KeyError, >+ user_account_control_flag_bit_to_string, >+ 0xabcdef) >+ >+ def test_too_long(self): >+ self.assertRaises(OverflowError, >+ user_account_control_flag_bit_to_string, >+ 0xabcdefffff) >+ >+ def test_way_too_long(self): >+ self.assertRaises(OverflowError, >+ user_account_control_flag_bit_to_string, >+ 0xabcdeffffffffffff) >diff --git a/selftest/tests.py b/selftest/tests.py >index 5b1ebcf42704..a2b8bf5c4d5b 100644 >--- a/selftest/tests.py >+++ b/selftest/tests.py >@@ -87,6 +87,7 @@ planpythontestsuite("none", "samba.tests.s3registry") > planpythontestsuite("none", "samba.tests.s3windb") > planpythontestsuite("none", "samba.tests.s3idmapdb") > planpythontestsuite("none", "samba.tests.samba3sam") >+planpythontestsuite("none", "samba.tests.dsdb_api") > planpythontestsuite( > "none", "wafsamba.tests.test_suite", > extra_path=[os.path.join(samba4srcdir, "..", "buildtools"), >diff --git a/source4/dsdb/pydsdb.c b/source4/dsdb/pydsdb.c >index 79015545109f..c205c63d66b9 100644 >--- a/source4/dsdb/pydsdb.c >+++ b/source4/dsdb/pydsdb.c >@@ -33,6 +33,7 @@ > #include "lib/util/dlinklist.h" > #include "dsdb/kcc/garbage_collect_tombstones.h" > #include "dsdb/kcc/scavenge_dns_records.h" >+#include "libds/common/flag_mapping.h" > > > /* FIXME: These should be in a header file somewhere */ >@@ -1400,6 +1401,30 @@ static PyObject *py_dsdb_load_udv_v2(PyObject *self, PyObject *args) > return pylist; > } > >+static PyObject *py_dsdb_user_account_control_flag_bit_to_string(PyObject *self, PyObject *args) >+{ >+ const char *str; >+ long long uf; >+ if (!PyArg_ParseTuple(args, "L", &uf)) { >+ return NULL; >+ } >+ >+ if (uf > UINT32_MAX) { >+ return PyErr_Format(PyExc_OverflowError, "No UF_ flags are over UINT32_MAX"); >+ } >+ if (uf < 0) { >+ return PyErr_Format(PyExc_KeyError, "No UF_ flags are less then zero"); >+ } >+ >+ str = dsdb_user_account_control_flag_bit_to_string(uf); >+ if (str == NULL) { >+ return PyErr_Format(PyExc_KeyError, >+ "No such UF_ flag 0x%08x", >+ (unsigned int)uf); >+ } >+ return PyUnicode_FromString(str); >+} >+ > static PyMethodDef py_dsdb_methods[] = { > { "_samdb_server_site_name", (PyCFunction)py_samdb_server_site_name, > METH_VARARGS, "Get the server site name as a string"}, >@@ -1479,6 +1504,11 @@ static PyMethodDef py_dsdb_methods[] = { > "_dsdb_allocate_rid(samdb)" > " -> RID" }, > { "_dsdb_load_udv_v2", (PyCFunction)py_dsdb_load_udv_v2, METH_VARARGS, NULL }, >+ { "user_account_control_flag_bit_to_string", >+ (PyCFunction)py_dsdb_user_account_control_flag_bit_to_string, >+ METH_VARARGS, >+ "user_account_control_flag_bit_to_string(bit)" >+ " -> string name" }, > {0} > }; > >-- >2.25.1 > > >From be16e3ed38af5a1aefcb2f7681fc4b7739defbe4 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 30 Aug 2021 14:37:06 +1200 >Subject: [PATCH 067/262] CVE-2020-25722 selftest: Use @DynamicTestCase in > user_account_control test_uac_bits_unrelated_modify() > >This is a nice easy example of how the test generation >code works, and it combined nicely with the earlier >patch to return string names from the UF_ constants. > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 >(cherry picked from commit 8701ce492fc3a209035b152961d8c17e801b082a) >--- > .../dsdb/tests/python/user_account_control.py | 19 +++++++++++-------- > 1 file changed, 11 insertions(+), 8 deletions(-) > >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index 81664079adfe..4ef43502c8cf 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -27,7 +27,7 @@ from samba.samdb import SamDB > from samba.dcerpc import samr, security, lsa > from samba.credentials import Credentials > from samba.ndr import ndr_unpack, ndr_pack >-from samba.tests import delete_force >+from samba.tests import delete_force, DynamicTestCase > from samba import gensec, sd_utils > from samba.credentials import DONT_USE_KERBEROS > from ldb import SCOPE_SUBTREE, SCOPE_BASE, LdbError >@@ -41,6 +41,7 @@ from samba.dsdb import UF_SCRIPT, UF_ACCOUNTDISABLE, UF_00000004, UF_HOMEDIR_REQ > UF_TRUSTED_FOR_DELEGATION, UF_NOT_DELEGATED, UF_USE_DES_KEY_ONLY, UF_DONT_REQUIRE_PREAUTH, \ > UF_PASSWORD_EXPIRED, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION, UF_NO_AUTH_DATA_REQUIRED, \ > UF_PARTIAL_SECRETS_ACCOUNT, UF_USE_AES_KEYS >+from samba import dsdb > > > parser = optparse.OptionParser("user_account_control.py [options] <host>") >@@ -86,7 +87,15 @@ bits = [UF_SCRIPT, UF_ACCOUNTDISABLE, UF_00000004, UF_HOMEDIR_REQUIRED, > account_types = set([UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT]) > > >+@DynamicTestCase > class UserAccountControlTests(samba.tests.TestCase): >+ @classmethod >+ def setUpDynamicTestCases(cls): >+ for account_type in [UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT]: >+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type) >+ cls.generate_dynamic_test("test_uac_bits_unrelated_modify", >+ account_type_str, account_type) >+ > def add_computer_ldap(self, computername, others=None, samdb=None): > if samdb is None: > samdb = self.samdb >@@ -436,7 +445,7 @@ class UserAccountControlTests(samba.tests.TestCase): > else: > self.fail("Unable to set userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr)) > >- def uac_bits_unrelated_modify_helper(self, account_type): >+ def _test_uac_bits_unrelated_modify_with_args(self, account_type): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) > >@@ -603,12 +612,6 @@ class UserAccountControlTests(samba.tests.TestCase): > UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD, > "bit 0X%08x should have been removed" % bit) > >- def test_uac_bits_unrelated_modify_normal(self): >- self.uac_bits_unrelated_modify_helper(UF_NORMAL_ACCOUNT) >- >- def test_uac_bits_unrelated_modify_workstation(self): >- self.uac_bits_unrelated_modify_helper(UF_WORKSTATION_TRUST_ACCOUNT) >- > def test_uac_bits_add(self): > computername = self.computernames[0] > >-- >2.25.1 > > >From 26e9162f679df5dc65fd3b3cd4201cff9aeeefb7 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 30 Aug 2021 14:51:27 +1200 >Subject: [PATCH 068/262] CVE-2020-25722 selftest: Replace internal loop in > test_uac_bits_add() using @DynamicTestClass > >This generates a single test per bit which is easier to >debug. Elsewhere we use this pattern where we want to >be able to put some cases in a knownfail, which is otherwise >not possible. > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 >(cherry picked from commit 60f1b6cf0ef0bf6736d8db9c53fa48fe9f3d8e75) >--- > .../dsdb/tests/python/user_account_control.py | 54 ++++++++++++------- > 1 file changed, 35 insertions(+), 19 deletions(-) > >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index 4ef43502c8cf..1a396740df0d 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -96,6 +96,16 @@ class UserAccountControlTests(samba.tests.TestCase): > cls.generate_dynamic_test("test_uac_bits_unrelated_modify", > account_type_str, account_type) > >+ for bit in bits: >+ try: >+ bit_str = dsdb.user_account_control_flag_bit_to_string(bit) >+ except KeyError: >+ bit_str = hex(bit) >+ >+ cls.generate_dynamic_test("test_uac_bits_add", >+ bit_str, bit, bit_str) >+ >+ > def add_computer_ldap(self, computername, others=None, samdb=None): > if samdb is None: > samdb = self.samdb >@@ -612,7 +622,7 @@ class UserAccountControlTests(samba.tests.TestCase): > UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD, > "bit 0X%08x should have been removed" % bit) > >- def test_uac_bits_add(self): >+ def _test_uac_bits_add_with_args(self, bit, bit_str): > computername = self.computernames[0] > > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) >@@ -631,24 +641,30 @@ class UserAccountControlTests(samba.tests.TestCase): > priv_bits = set([UF_INTERDOMAIN_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT, > UF_TRUSTED_FOR_DELEGATION, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION]) > >- for bit in bits: >- try: >- self.add_computer_ldap(computername, others={"userAccountControl": [str(bit)]}) >- delete_force(self.admin_samdb, "CN=%s,%s" % (computername, self.OU)) >- if bit in priv_bits: >- self.fail("Unexpectdly able to set userAccountControl bit 0x%08X on %s" % (bit, computername)) >- >- except LdbError as e4: >- (enum, estr) = e4.args >- if bit in invalid_bits: >- self.assertEqual(enum, ldb.ERR_OTHER, "Invalid bit 0x%08X was able to be set on %s" % (bit, computername)) >- # No point going on, try the next bit >- continue >- elif bit in priv_bits: >- self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) >- continue >- else: >- self.fail("Unable to set userAccountControl bit 0x%08X on %s: %s" % (bit, computername, estr)) >+ try: >+ self.add_computer_ldap(computername, others={"userAccountControl": [str(bit)]}) >+ delete_force(self.admin_samdb, "CN=%s,%s" % (computername, self.OU)) >+ if bit in priv_bits: >+ self.fail("Unexpectdly able to set userAccountControl bit 0x%08X (%s) on %s" >+ % (bit, bit_str, computername)) >+ >+ except LdbError as e4: >+ (enum, estr) = e4.args >+ if bit in invalid_bits: >+ self.assertEqual(enum, >+ ldb.ERR_OTHER, >+ "Invalid bit 0x%08X (%s) was able to be set on %s" >+ % (bit, >+ bit_str, >+ computername)) >+ elif bit in priv_bits: >+ self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) >+ else: >+ self.fail("Unable to set userAccountControl bit 0x%08X (%s) on %s: %s" >+ % (bit, >+ bit_str, >+ computername, >+ estr)) > > def test_primarygroupID_cc_add(self): > computername = self.computernames[0] >-- >2.25.1 > > >From c42a772c8f1b9714abeeab8b9034892cb339fcb7 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 30 Aug 2021 14:54:39 +1200 >Subject: [PATCH 069/262] CVE-2020-25722 selftest: Replace internal loop in > test_uac_bits_set() using @DynamicTestClass > >This generates a single test per bit which is easier to >debug. Elsewhere we use this pattern where we want to >be able to put some cases in a knownfail, which is otherwise >not possible. > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 >(cherry picked from commit 17ae0319db53a7b88e7fb44a9e2fd4bf1d1daa0e) >--- > .../dsdb/tests/python/user_account_control.py | 45 ++++++++++--------- > 1 file changed, 25 insertions(+), 20 deletions(-) > >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index 1a396740df0d..fd0ae38a3f99 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -105,6 +105,9 @@ class UserAccountControlTests(samba.tests.TestCase): > cls.generate_dynamic_test("test_uac_bits_add", > bit_str, bit, bit_str) > >+ cls.generate_dynamic_test("test_uac_bits_set", >+ bit_str, bit, bit_str) >+ > > def add_computer_ldap(self, computername, others=None, samdb=None): > if samdb is None: >@@ -401,7 +404,7 @@ class UserAccountControlTests(samba.tests.TestCase): > > self.assertEqual(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE) > >- def test_uac_bits_set(self): >+ def _test_uac_bits_set_with_args(self, bit, bit_str): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) > mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) > >@@ -435,25 +438,27 @@ class UserAccountControlTests(samba.tests.TestCase): > > invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT, UF_PARTIAL_SECRETS_ACCOUNT]) > >- for bit in bits: >- m = ldb.Message() >- m.dn = res[0].dn >- m["userAccountControl"] = ldb.MessageElement(str(bit | UF_PASSWD_NOTREQD), >- ldb.FLAG_MOD_REPLACE, "userAccountControl") >- try: >- self.samdb.modify(m) >- if (bit in priv_bits): >- self.fail("Unexpectedly able to set userAccountControl bit 0x%08X on %s" % (bit, m.dn)) >- except LdbError as e: >- (enum, estr) = e.args >- if bit in invalid_bits: >- self.assertEqual(enum, ldb.ERR_OTHER, "was not able to set 0x%08X on %s" % (bit, m.dn)) >- # No point going on, try the next bit >- continue >- elif (bit in priv_bits): >- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) >- else: >- self.fail("Unable to set userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr)) >+ m = ldb.Message() >+ m.dn = res[0].dn >+ m["userAccountControl"] = ldb.MessageElement(str(bit | UF_PASSWD_NOTREQD), >+ ldb.FLAG_MOD_REPLACE, "userAccountControl") >+ try: >+ self.samdb.modify(m) >+ if (bit in priv_bits): >+ self.fail("Unexpectedly able to set userAccountControl bit 0x%08X (%s), on %s" >+ % (bit, bit_str, m.dn)) >+ except LdbError as e: >+ (enum, estr) = e.args >+ if bit in invalid_bits: >+ self.assertEqual(enum, >+ ldb.ERR_OTHER, >+ "was not able to set 0x%08X (%s) on %s" >+ % (bit, bit_str, m.dn)) >+ elif (bit in priv_bits): >+ self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) >+ else: >+ self.fail("Unable to set userAccountControl bit 0x%08X (%s) on %s: %s" >+ % (bit, bit_str, m.dn, estr)) > > def _test_uac_bits_unrelated_modify_with_args(self, account_type): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) >-- >2.25.1 > > >From b769f9089cb5c78b44ee357ca935f6cb0a2d996f Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 30 Aug 2021 18:17:47 +1200 >Subject: [PATCH 070/262] CVE-2020-25722 selftest: Update user_account_control > tests to pass against Windows 2019 > >This gets us closer to passing against Windows 2019, without >making major changes to what was tested. More tests are needed, >but it is important to get what was being tested tested again. > >Account types (eg UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT) >are now required on all objects, this can't be omitted any more. > >Also for UF_NORMAL_ACCOUNT for these accounts without a password >set |UF_PASSWD_NOTREQD must be included. > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Alexander Bokovoy <ab@samba.org> >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Autobuild-User(master): Andrew Bartlett <abartlet@samba.org> >Autobuild-Date(master): Wed Sep 15 08:49:11 UTC 2021 on sn-devel-184 > >(cherry picked from commit d12cb47724c2e8d19a28286d4c3ef72271a002fd) >--- > selftest/knownfail.d/user_account_control | 1 + > .../dsdb/tests/python/user_account_control.py | 114 ++++++++++++++++-- > 2 files changed, 103 insertions(+), 12 deletions(-) > create mode 100644 selftest/knownfail.d/user_account_control > >diff --git a/selftest/knownfail.d/user_account_control b/selftest/knownfail.d/user_account_control >new file mode 100644 >index 000000000000..ad3af6787080 >--- /dev/null >+++ b/selftest/knownfail.d/user_account_control >@@ -0,0 +1 @@ >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_add_computer_cc_normal_bare.ad_dc_default >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index fd0ae38a3f99..efb83b2dcfff 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -84,7 +84,7 @@ bits = [UF_SCRIPT, UF_ACCOUNTDISABLE, UF_00000004, UF_HOMEDIR_REQUIRED, > UF_PARTIAL_SECRETS_ACCOUNT, UF_USE_AES_KEYS, > int("0x10000000", 16), int("0x20000000", 16), int("0x40000000", 16), int("0x80000000", 16)] > >-account_types = set([UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT]) >+account_types = set([UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT, UF_INTERDOMAIN_TRUST_ACCOUNT]) > > > @DynamicTestCase >@@ -108,6 +108,11 @@ class UserAccountControlTests(samba.tests.TestCase): > cls.generate_dynamic_test("test_uac_bits_set", > bit_str, bit, bit_str) > >+ cls.generate_dynamic_test("test_uac_bits_add", >+ "UF_NORMAL_ACCOUNT_UF_PASSWD_NOTREQD", >+ UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD, >+ "UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD") >+ > > def add_computer_ldap(self, computername, others=None, samdb=None): > if samdb is None: >@@ -272,7 +277,7 @@ class UserAccountControlTests(samba.tests.TestCase): > > m = ldb.Message() > m.dn = res[0].dn >- m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT), >+ m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD), > ldb.FLAG_MOD_REPLACE, "userAccountControl") > self.samdb.modify(m) > >@@ -334,9 +339,10 @@ class UserAccountControlTests(samba.tests.TestCase): > (enum, estr) = e10.args > self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) > >+ > m = ldb.Message() > m.dn = res[0].dn >- m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT), >+ m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD), > ldb.FLAG_MOD_REPLACE, "userAccountControl") > self.samdb.modify(m) > >@@ -351,6 +357,50 @@ class UserAccountControlTests(samba.tests.TestCase): > (enum, estr) = e11.args > self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) > >+ def test_add_computer_cc_normal_bare(self): >+ user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) >+ mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) >+ >+ old_sd = self.sd_utils.read_sd_on_dn(self.OU) >+ self.sd_utils.dacl_add_ace(self.OU, mod) >+ >+ computername = self.computernames[0] >+ sd = ldb.MessageElement((ndr_pack(self.sd_reference_modify)), >+ ldb.FLAG_MOD_ADD, >+ "nTSecurityDescriptor") >+ self.add_computer_ldap(computername, >+ others={"nTSecurityDescriptor": sd}) >+ >+ res = self.admin_samdb.search("%s" % self.base_dn, >+ expression="(&(objectClass=computer)(samAccountName=%s$))" % computername, >+ scope=SCOPE_SUBTREE, >+ attrs=["ntSecurityDescriptor"]) >+ >+ desc = res[0]["nTSecurityDescriptor"][0] >+ desc = ndr_unpack(security.descriptor, desc, allow_remaining=True) >+ >+ sddl = desc.as_sddl(self.domain_sid) >+ self.assertEqual(self.sd_reference_modify.as_sddl(self.domain_sid), sddl) >+ >+ m = ldb.Message() >+ m.dn = res[0].dn >+ m["description"] = ldb.MessageElement( >+ ("A description"), ldb.FLAG_MOD_REPLACE, >+ "description") >+ self.samdb.modify(m) >+ >+ m = ldb.Message() >+ m.dn = res[0].dn >+ m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT), >+ ldb.FLAG_MOD_REPLACE, "userAccountControl") >+ try: >+ self.samdb.modify(m) >+ self.fail("Unexpectedly able to set userAccountControl to be an Normal account without |UF_PASSWD_NOTREQD on %s" % m.dn) >+ except LdbError as e7: >+ (enum, estr) = e7.args >+ self.assertEqual(ldb.ERR_UNWILLING_TO_PERFORM, enum) >+ >+ > def test_admin_mod_uac(self): > computername = self.computernames[0] > self.add_computer_ldap(computername, samdb=self.admin_samdb) >@@ -469,13 +519,23 @@ class UserAccountControlTests(samba.tests.TestCase): > self.sd_utils.dacl_add_ace(self.OU, mod) > > computername = self.computernames[0] >- self.add_computer_ldap(computername, others={"userAccountControl": [str(account_type)]}) >+ if account_type == UF_WORKSTATION_TRUST_ACCOUNT: >+ self.add_computer_ldap(computername, others={"userAccountControl": [str(account_type)]}) >+ else: >+ self.add_computer_ldap(computername) > >- res = self.admin_samdb.search("%s" % self.base_dn, >- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername, >+ res = self.admin_samdb.search(self.OU, >+ expression=f"(cn={computername})", > scope=SCOPE_SUBTREE, > attrs=["userAccountControl"]) >- self.assertEqual(int(res[0]["userAccountControl"][0]), account_type) >+ self.assertEqual(len(res), 1) >+ >+ orig_uac = int(res[0]["userAccountControl"][0]) >+ if account_type == UF_WORKSTATION_TRUST_ACCOUNT: >+ self.assertEqual(orig_uac, account_type) >+ else: >+ self.assertEqual(orig_uac & UF_NORMAL_ACCOUNT, >+ account_type) > > m = ldb.Message() > m.dn = res[0].dn >@@ -504,7 +564,7 @@ class UserAccountControlTests(samba.tests.TestCase): > # Reset this to the initial position, just to be sure > m = ldb.Message() > m.dn = res[0].dn >- m["userAccountControl"] = ldb.MessageElement(str(account_type), >+ m["userAccountControl"] = ldb.MessageElement(str(orig_uac), > ldb.FLAG_MOD_REPLACE, "userAccountControl") > self.admin_samdb.modify(m) > >@@ -513,7 +573,11 @@ class UserAccountControlTests(samba.tests.TestCase): > scope=SCOPE_SUBTREE, > attrs=["userAccountControl"]) > >- self.assertEqual(int(res[0]["userAccountControl"][0]), account_type) >+ if account_type == UF_WORKSTATION_TRUST_ACCOUNT: >+ self.assertEqual(orig_uac, account_type) >+ else: >+ self.assertEqual(orig_uac & UF_NORMAL_ACCOUNT, >+ account_type) > > m = ldb.Message() > m.dn = res[0].dn >@@ -521,6 +585,7 @@ class UserAccountControlTests(samba.tests.TestCase): > ldb.FLAG_MOD_REPLACE, "userAccountControl") > try: > self.admin_samdb.modify(m) >+ > if bit in invalid_bits: > self.fail("Should have been unable to set userAccountControl bit 0x%08X on %s" % (bit, m.dn)) > >@@ -534,6 +599,19 @@ class UserAccountControlTests(samba.tests.TestCase): > self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) > # No point going on, try the next bit > continue >+ >+ elif (account_type == UF_NORMAL_ACCOUNT) \ >+ and (bit in account_types) \ >+ and (bit != account_type): >+ self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM) >+ continue >+ >+ elif (account_type == UF_WORKSTATION_TRUST_ACCOUNT) \ >+ and (bit != UF_NORMAL_ACCOUNT) \ >+ and (bit != account_type): >+ self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM) >+ continue >+ > else: > self.fail("Unable to set userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr)) > >@@ -637,17 +715,27 @@ class UserAccountControlTests(samba.tests.TestCase): > > self.sd_utils.dacl_add_ace(self.OU, mod) > >- invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT, UF_PARTIAL_SECRETS_ACCOUNT]) >+ invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT]) >+ # UF_NORMAL_ACCOUNT is invalid alone, needs UF_PASSWD_NOTREQD >+ unwilling_bits = set([UF_NORMAL_ACCOUNT]) >+ > # These bits are privileged, but authenticated users have that CAR by default, so this is a pain to test > priv_to_auth_users_bits = set([UF_PASSWD_NOTREQD, UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED, > UF_DONT_EXPIRE_PASSWD]) > > # These bits really are privileged > priv_bits = set([UF_INTERDOMAIN_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT, >- UF_TRUSTED_FOR_DELEGATION, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION]) >+ UF_TRUSTED_FOR_DELEGATION, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION, >+ UF_PARTIAL_SECRETS_ACCOUNT]) >+ >+ if bit not in account_types and ((bit & UF_NORMAL_ACCOUNT) == 0): >+ bit_add = bit|UF_WORKSTATION_TRUST_ACCOUNT >+ else: >+ bit_add = bit > > try: >- self.add_computer_ldap(computername, others={"userAccountControl": [str(bit)]}) >+ >+ self.add_computer_ldap(computername, others={"userAccountControl": [str(bit_add)]}) > delete_force(self.admin_samdb, "CN=%s,%s" % (computername, self.OU)) > if bit in priv_bits: > self.fail("Unexpectdly able to set userAccountControl bit 0x%08X (%s) on %s" >@@ -664,6 +752,8 @@ class UserAccountControlTests(samba.tests.TestCase): > computername)) > elif bit in priv_bits: > self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) >+ elif bit in unwilling_bits: >+ self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM) > else: > self.fail("Unable to set userAccountControl bit 0x%08X (%s) on %s: %s" > % (bit, >-- >2.25.1 > > >From 78ae7751ebb84dceea5468d6f466bdc048fc4cfa Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 16 Sep 2021 16:09:24 +1200 >Subject: [PATCH 071/262] CVE-2020-25722 selftest: Use > self.assertRaisesLdbError() in user_account_control.py test > >This changes most of the simple pattern with self.samdb.modify() >to use the wrapper. Some other calls still need to be converted, while >the complex decision tree tests should remain as-is for now. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >Autobuild-User(master): Jeremy Allison <jra@samba.org> >Autobuild-Date(master): Mon Oct 4 21:55:43 UTC 2021 on sn-devel-184 > >(cherry picked from commit b45190bdac7bd9dcefd5ed88be4bd9a97a712664) >--- > .../dsdb/tests/python/user_account_control.py | 100 +++++++----------- > 1 file changed, 37 insertions(+), 63 deletions(-) > >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index efb83b2dcfff..c9b50b83e9da 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -245,35 +245,27 @@ class UserAccountControlTests(samba.tests.TestCase): > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_SERVER_TRUST_ACCOUNT), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- try: >- self.samdb.modify(m) >- self.fail("Unexpectedly able to set userAccountControl to be a DC on %s" % m.dn) >- except LdbError as e5: >- (enum, estr) = e5.args >- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) >+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ f"Unexpectedly able to set userAccountControl to be a DC on {m.dn}", >+ self.samdb.modify, m) > > m = ldb.Message() > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT | > samba.dsdb.UF_PARTIAL_SECRETS_ACCOUNT), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- try: >- self.samdb.modify(m) >- self.fail("Unexpectedly able to set userAccountControl to be an RODC on %s" % m.dn) >- except LdbError as e6: >- (enum, estr) = e6.args >- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) >+ >+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ f"Unexpectedly able to set userAccountControl to be a RODC on {m.dn}", >+ self.samdb.modify, m) > > m = ldb.Message() > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- try: >- self.samdb.modify(m) >- self.fail("Unexpectedly able to set userAccountControl to be an Workstation on %s" % m.dn) >- except LdbError as e7: >- (enum, estr) = e7.args >- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) >+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ f"Unexpectedly able to set userAccountControl to be a Workstation on {m.dn}", >+ self.samdb.modify, m) > > m = ldb.Message() > m.dn = res[0].dn >@@ -285,13 +277,10 @@ class UserAccountControlTests(samba.tests.TestCase): > m.dn = res[0].dn > m["primaryGroupID"] = ldb.MessageElement(str(security.DOMAIN_RID_ADMINS), > ldb.FLAG_MOD_REPLACE, "primaryGroupID") >- try: >- self.samdb.modify(m) >- except LdbError as e8: >- (enum, estr) = e8.args >- self.assertEqual(ldb.ERR_UNWILLING_TO_PERFORM, enum) >- return >- self.fail() >+ self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM, >+ f"Unexpectedly able to set primaryGroupID on {m.dn}", >+ self.samdb.modify, m) >+ > > def test_mod_computer_cc(self): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) >@@ -321,24 +310,17 @@ class UserAccountControlTests(samba.tests.TestCase): > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT | > samba.dsdb.UF_PARTIAL_SECRETS_ACCOUNT), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- try: >- self.samdb.modify(m) >- self.fail("Unexpectedly able to set userAccountControl on %s" % m.dn) >- except LdbError as e9: >- (enum, estr) = e9.args >- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) >+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ f"Unexpectedly able to set userAccountControl as RODC on {m.dn}", >+ self.samdb.modify, m) > > m = ldb.Message() > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_SERVER_TRUST_ACCOUNT), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- try: >- self.samdb.modify(m) >- self.fail() >- except LdbError as e10: >- (enum, estr) = e10.args >- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) >- >+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ f"Unexpectedly able to set userAccountControl as DC on {m.dn}", >+ self.samdb.modify, m) > > m = ldb.Message() > m.dn = res[0].dn >@@ -350,12 +332,10 @@ class UserAccountControlTests(samba.tests.TestCase): > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- try: >- self.samdb.modify(m) >- self.fail("Unexpectedly able to set userAccountControl to be an Workstation on %s" % m.dn) >- except LdbError as e11: >- (enum, estr) = e11.args >- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) >+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ f"Unexpectedly able to set userAccountControl to be a workstation on {m.dn}", >+ self.samdb.modify, m) >+ > > def test_add_computer_cc_normal_bare(self): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) >@@ -393,12 +373,11 @@ class UserAccountControlTests(samba.tests.TestCase): > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- try: >- self.samdb.modify(m) >- self.fail("Unexpectedly able to set userAccountControl to be an Normal account without |UF_PASSWD_NOTREQD on %s" % m.dn) >- except LdbError as e7: >- (enum, estr) = e7.args >- self.assertEqual(ldb.ERR_UNWILLING_TO_PERFORM, enum) >+ self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM, >+ f"Unexpectedly able to set userAccountControl to be an Normal " >+ "account without |UF_PASSWD_NOTREQD Unexpectedly able to " >+ "set userAccountControl to be a workstation on {m.dn}", >+ self.samdb.modify, m) > > > def test_admin_mod_uac(self): >@@ -420,12 +399,11 @@ class UserAccountControlTests(samba.tests.TestCase): > UF_PARTIAL_SECRETS_ACCOUNT | > UF_TRUSTED_FOR_DELEGATION), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- try: >- self.admin_samdb.modify(m) >- self.fail("Unexpectedly able to set userAccountControl to UF_WORKSTATION_TRUST_ACCOUNT|UF_PARTIAL_SECRETS_ACCOUNT|UF_TRUSTED_FOR_DELEGATION on %s" % m.dn) >- except LdbError as e12: >- (enum, estr) = e12.args >- self.assertEqual(ldb.ERR_OTHER, enum) >+ self.assertRaisesLdbError(ldb.ERR_OTHER, >+ f"Unexpectedly able to set userAccountControl to " >+ "UF_WORKSTATION_TRUST_ACCOUNT|UF_PARTIAL_SECRETS_ACCOUNT|" >+ "UF_TRUSTED_FOR_DELEGATION on {m.dn}", >+ self.admin_samdb.modify, m) > > m = ldb.Message() > m.dn = res[0].dn >@@ -835,14 +813,10 @@ class UserAccountControlTests(samba.tests.TestCase): > m["primaryGroupID"] = ldb.MessageElement( > [str(security.DOMAIN_RID_USERS)], ldb.FLAG_MOD_REPLACE, > "primaryGroupID") >- try: >- self.admin_samdb.modify(m) > >- # When creating a new object, you can not ever set the primaryGroupID >- self.fail("Unexpectedly able to set primaryGroupID to be other than DCS on %s" % computername) >- except LdbError as e15: >- (enum, estr) = e15.args >- self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM) >+ self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM, >+ f"Unexpectedly able to set primaryGroupID to be other than DCS on {m.dn}", >+ self.admin_samdb.modify, m) > > def test_primarygroupID_priv_user_modify(self): > computername = self.computernames[0] >-- >2.25.1 > > >From 4007053dfab6e1946b2a5a81368acf7155ae6752 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Thu, 21 Oct 2021 16:46:56 +1300 >Subject: [PATCH 072/262] CVE-2020-17049 tests/krb5: Check account name and SID > in PAC for S4U tests > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andreas Schneider <asn@cryptomilk.org> > >Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org> >Autobuild-Date(master): Mon Oct 25 09:23:35 UTC 2021 on sn-devel-184 > >(cherry picked from commit c174e9ebe715aad6910d53c1f427a0512c09d651) >--- > python/samba/tests/krb5/kdc_base_test.py | 4 ++++ > python/samba/tests/krb5/raw_testcase.py | 26 ++++++++++++++++++++++++ > python/samba/tests/krb5/s4u_tests.py | 12 +++++++++++ > 3 files changed, 42 insertions(+) > >diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py >index b24c6376ab0c..8ae9c24b0fc3 100644 >--- a/python/samba/tests/krb5/kdc_base_test.py >+++ b/python/samba/tests/krb5/kdc_base_test.py >@@ -1337,6 +1337,8 @@ class KDCBaseTest(RawKerberosTest): > > def get_tgt(self, creds, to_rodc=False, kdc_options=None, > expected_flags=None, unexpected_flags=None, >+ expected_account_name=None, >+ expected_sid=None, > pac_request=True, expect_pac=True, fresh=False): > user_name = creds.get_username() > cache_key = (user_name, to_rodc, kdc_options, pac_request) >@@ -1386,6 +1388,8 @@ class KDCBaseTest(RawKerberosTest): > expected_cname=cname, > expected_srealm=realm, > expected_sname=sname, >+ expected_account_name=expected_account_name, >+ expected_sid=expected_sid, > expected_salt=salt, > expected_flags=expected_flags, > unexpected_flags=unexpected_flags, >diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py >index f352615db1fd..fdf078ea788e 100644 >--- a/python/samba/tests/krb5/raw_testcase.py >+++ b/python/samba/tests/krb5/raw_testcase.py >@@ -1984,6 +1984,8 @@ class RawKerberosTest(TestCaseInTempDir): > expected_anon=False, > expected_srealm=None, > expected_sname=None, >+ expected_account_name=None, >+ expected_sid=None, > expected_supported_etypes=None, > expected_flags=None, > unexpected_flags=None, >@@ -2033,6 +2035,8 @@ class RawKerberosTest(TestCaseInTempDir): > 'expected_anon': expected_anon, > 'expected_srealm': expected_srealm, > 'expected_sname': expected_sname, >+ 'expected_account_name': expected_account_name, >+ 'expected_sid': expected_sid, > 'expected_supported_etypes': expected_supported_etypes, > 'expected_flags': expected_flags, > 'unexpected_flags': unexpected_flags, >@@ -2078,6 +2082,8 @@ class RawKerberosTest(TestCaseInTempDir): > expected_anon=False, > expected_srealm=None, > expected_sname=None, >+ expected_account_name=None, >+ expected_sid=None, > expected_supported_etypes=None, > expected_flags=None, > unexpected_flags=None, >@@ -2128,6 +2134,8 @@ class RawKerberosTest(TestCaseInTempDir): > 'expected_anon': expected_anon, > 'expected_srealm': expected_srealm, > 'expected_sname': expected_sname, >+ 'expected_account_name': expected_account_name, >+ 'expected_sid': expected_sid, > 'expected_supported_etypes': expected_supported_etypes, > 'expected_flags': expected_flags, > 'unexpected_flags': unexpected_flags, >@@ -2561,6 +2569,9 @@ class RawKerberosTest(TestCaseInTempDir): > f'expected: {expected_types} ' > f'got: {buffer_types}') > >+ expected_account_name = kdc_exchange_dict['expected_account_name'] >+ expected_sid = kdc_exchange_dict['expected_sid'] >+ > for pac_buffer in pac.buffers: > if pac_buffer.type == krb5pac.PAC_TYPE_CONSTRAINED_DELEGATION: > expected_proxy_target = kdc_exchange_dict[ >@@ -2584,6 +2595,17 @@ class RawKerberosTest(TestCaseInTempDir): > > self.assertEqual(account_name, pac_buffer.info.account_name) > >+ elif pac_buffer.type == krb5pac.PAC_TYPE_LOGON_INFO: >+ logon_info = pac_buffer.info.info.info3.base >+ >+ if expected_account_name is not None: >+ self.assertEqual(expected_account_name, >+ str(logon_info.account_name)) >+ >+ if expected_sid is not None: >+ expected_rid = int(expected_sid.rsplit('-', 1)[1]) >+ self.assertEqual(expected_rid, logon_info.rid) >+ > def generic_check_kdc_error(self, > kdc_exchange_dict, > callback_dict, >@@ -3548,6 +3570,8 @@ class RawKerberosTest(TestCaseInTempDir): > etypes, > padata, > kdc_options, >+ expected_account_name=None, >+ expected_sid=None, > expected_flags=None, > unexpected_flags=None, > expected_supported_etypes=None, >@@ -3580,6 +3604,8 @@ class RawKerberosTest(TestCaseInTempDir): > expected_cname=expected_cname, > expected_srealm=expected_srealm, > expected_sname=expected_sname, >+ expected_account_name=expected_account_name, >+ expected_sid=expected_sid, > expected_supported_etypes=expected_supported_etypes, > ticket_decryption_key=ticket_decryption_key, > generate_padata_fn=generate_padata_fn, >diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py >index ea629d297067..593ef94c9103 100755 >--- a/python/samba/tests/krb5/s4u_tests.py >+++ b/python/samba/tests/krb5/s4u_tests.py >@@ -238,6 +238,10 @@ class S4UKerberosTests(KDCBaseTest): > client_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, > names=[client_name]) > >+ samdb = self.get_samdb() >+ client_dn = client_creds.get_dn() >+ sid = self.get_objectSid(samdb, client_dn) >+ > service_name = service_creds.get_username()[:-1] > service_sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, > names=['host', service_name]) >@@ -279,6 +283,8 @@ class S4UKerberosTests(KDCBaseTest): > expected_cname=client_cname, > expected_srealm=realm, > expected_sname=service_sname, >+ expected_account_name=client_name, >+ expected_sid=sid, > expected_flags=expected_flags, > unexpected_flags=unexpected_flags, > ticket_decryption_key=service_decryption_key, >@@ -438,6 +444,10 @@ class S4UKerberosTests(KDCBaseTest): > account_type=self.AccountType.USER, > opts=client_opts) > >+ samdb = self.get_samdb() >+ client_dn = client_creds.get_dn() >+ sid = self.get_objectSid(samdb, client_dn) >+ > service1_opts = kdc_dict.pop('service1_opts', {}) > service2_opts = kdc_dict.pop('service2_opts', {}) > >@@ -552,6 +562,8 @@ class S4UKerberosTests(KDCBaseTest): > expected_cname=client_cname, > expected_srealm=service2_realm, > expected_sname=service2_sname, >+ expected_account_name=client_username, >+ expected_sid=sid, > expected_supported_etypes=service2_etypes, > ticket_decryption_key=service2_decryption_key, > check_error_fn=check_error_fn, >-- >2.25.1 > > >From 48f942a289db70faa383bca2702fb9708d4847b6 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Tue, 10 Aug 2021 22:31:02 +1200 >Subject: [PATCH 073/262] CVE-2020-25722 dsdb: Tests for our known set of > privileged attributes > >This, except for where we choose to disagree, does pass >against Windows 2019. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14703 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14778 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14775 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/priv_attr | 54 ++++ > source4/dsdb/tests/python/priv_attrs.py | 388 ++++++++++++++++++++++++ > source4/selftest/tests.py | 2 + > 3 files changed, 444 insertions(+) > create mode 100644 selftest/knownfail.d/priv_attr > create mode 100644 source4/dsdb/tests/python/priv_attrs.py > >diff --git a/selftest/knownfail.d/priv_attr b/selftest/knownfail.d/priv_attr >new file mode 100644 >index 000000000000..31b9cb23b442 >--- /dev/null >+++ b/selftest/knownfail.d/priv_attr >@@ -0,0 +1,54 @@ >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_WP_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_WP_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_default_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_default_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_WP_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_WP_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_default_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_default_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_WP_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_WP_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_default_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_default_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_WP_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_WP_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_default_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_default_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_WP_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_WP_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_default_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_default_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_WP_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_WP_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_default_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_default_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_WP_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_WP_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_default_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_default_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-RODC_add_CC_WP_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-RODC_add_CC_default_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-computer_add_CC_WP_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-computer_add_CC_default_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_WP_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_WP_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_default_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_default_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_mod-del-add_CC_default_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_mod-replace_CC_default_computer >diff --git a/source4/dsdb/tests/python/priv_attrs.py b/source4/dsdb/tests/python/priv_attrs.py >new file mode 100644 >index 000000000000..ec2b13045e5a >--- /dev/null >+++ b/source4/dsdb/tests/python/priv_attrs.py >@@ -0,0 +1,388 @@ >+#!/usr/bin/env python3 >+# -*- coding: utf-8 -*- >+# This tests the restrictions on userAccountControl that apply even if write access is permitted >+# >+# Copyright Samuel Cabrero 2014 <samuelcabrero@kernevil.me> >+# Copyright Andrew Bartlett 2014 <abartlet@samba.org> >+# >+# Licenced under the GPLv3 >+# >+ >+import optparse >+import sys >+import unittest >+import samba >+import samba.getopt as options >+import samba.tests >+import ldb >+import base64 >+ >+sys.path.insert(0, "bin/python") >+from samba.tests.subunitrun import TestProgram, SubunitOptions >+from samba.tests import DynamicTestCase >+from samba.subunit.run import SubunitTestRunner >+from samba.auth import system_session >+from samba.samdb import SamDB >+from samba.dcerpc import samr, security, lsa >+from samba.credentials import Credentials >+from samba.ndr import ndr_unpack, ndr_pack >+from samba.tests import delete_force >+from samba import gensec, sd_utils >+from samba.credentials import DONT_USE_KERBEROS >+from ldb import SCOPE_SUBTREE, SCOPE_BASE, LdbError >+from ldb import Message, MessageElement, Dn >+from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE >+from samba.dsdb import UF_SCRIPT, UF_ACCOUNTDISABLE, UF_00000004, UF_HOMEDIR_REQUIRED, \ >+ UF_LOCKOUT, UF_PASSWD_NOTREQD, UF_PASSWD_CANT_CHANGE, UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,\ >+ UF_TEMP_DUPLICATE_ACCOUNT, UF_NORMAL_ACCOUNT, UF_00000400, UF_INTERDOMAIN_TRUST_ACCOUNT, \ >+ UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT, UF_00004000, \ >+ UF_00008000, UF_DONT_EXPIRE_PASSWD, UF_MNS_LOGON_ACCOUNT, UF_SMARTCARD_REQUIRED, \ >+ UF_TRUSTED_FOR_DELEGATION, UF_NOT_DELEGATED, UF_USE_DES_KEY_ONLY, UF_DONT_REQUIRE_PREAUTH, \ >+ UF_PASSWORD_EXPIRED, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION, UF_NO_AUTH_DATA_REQUIRED, \ >+ UF_PARTIAL_SECRETS_ACCOUNT, UF_USE_AES_KEYS >+ >+ >+parser = optparse.OptionParser("user_account_control.py [options] <host>") >+sambaopts = options.SambaOptions(parser) >+parser.add_option_group(sambaopts) >+parser.add_option_group(options.VersionOptions(parser)) >+ >+# use command line creds if available >+credopts = options.CredentialsOptions(parser) >+parser.add_option_group(credopts) >+opts, args = parser.parse_args() >+ >+if len(args) < 1: >+ parser.print_usage() >+ sys.exit(1) >+host = args[0] >+ >+if "://" not in host: >+ ldaphost = "ldap://%s" % host >+else: >+ ldaphost = host >+ start = host.rindex("://") >+ host = host.lstrip(start + 3) >+ >+lp = sambaopts.get_loadparm() >+creds = credopts.get_credentials(lp) >+creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL) >+ >+ >+""" >+Check the combinations of: >+ >+rodc kdc >+a2d2 >+useraccountcontrol (trusted for delegation) >+sidHistory >+ >+x >+ >+add >+modify(replace) >+modify(add) >+ >+x >+ >+sd WP on add >+cc default perms >+admin created, WP to user >+ >+x >+ >+computer >+user >+""" >+ >+attrs = {"sidHistory": >+ {"value": ndr_pack(security.dom_sid(security.SID_BUILTIN_ADMINISTRATORS)), >+ "priv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS}, >+ "msDS-AllowedToDelegateTo": >+ {"value": f"host/{host}", >+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS}, >+ "userAccountControl-a2d-user": >+ {"attr": "userAccountControl", >+ "value": str(UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION|UF_NORMAL_ACCOUNT), >+ "priv-error": ldb.ERR_UNWILLING_TO_PERFORM, >+ "unpriv-add-error": ldb.ERR_UNWILLING_TO_PERFORM, >+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS}, >+ "userAccountControl-a2d-computer": >+ {"attr": "userAccountControl", >+ "value": str(UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION|UF_WORKSTATION_TRUST_ACCOUNT), >+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ "only-1": "computer"}, >+ "userAccountControl-DC": >+ {"attr": "userAccountControl", >+ "value": str(UF_SERVER_TRUST_ACCOUNT), >+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ "only-2": "computer"}, >+ "userAccountControl-RODC": >+ {"attr": "userAccountControl", >+ "value": str(UF_PARTIAL_SECRETS_ACCOUNT|UF_WORKSTATION_TRUST_ACCOUNT), >+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ "only-1": "computer"}, >+ "msDS-SecondaryKrbTgtNumber": >+ {"value": "65536", >+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS}, >+ "primaryGroupID": >+ {"value": str(security.DOMAIN_RID_ADMINS), >+ "priv-error": ldb.ERR_UNWILLING_TO_PERFORM, >+ "unpriv-add-error": ldb.ERR_UNWILLING_TO_PERFORM, >+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS} >+ } >+ >+ >+ >+@DynamicTestCase >+class PrivAttrsTests(samba.tests.TestCase): >+ >+ def get_creds(self, target_username, target_password): >+ creds_tmp = Credentials() >+ creds_tmp.set_username(target_username) >+ creds_tmp.set_password(target_password) >+ creds_tmp.set_domain(creds.get_domain()) >+ creds_tmp.set_realm(creds.get_realm()) >+ creds_tmp.set_workstation(creds.get_workstation()) >+ creds_tmp.set_gensec_features(creds_tmp.get_gensec_features() >+ | gensec.FEATURE_SEAL) >+ creds_tmp.set_kerberos_state(DONT_USE_KERBEROS) # kinit is too expensive to use in a tight loop >+ return creds_tmp >+ >+ def assertGotLdbError(self, got, wanted): >+ if not self.strict_checking: >+ self.assertNotEqual(got, ldb.SUCCESS) >+ else: >+ self.assertEqual(got, wanted) >+ >+ def setUp(self): >+ super().setUp() >+ >+ strict_checking = samba.tests.env_get_var_value('STRICT_CHECKING', allow_missing=True) >+ if strict_checking is None: >+ strict_checking = '1' >+ self.strict_checking = bool(int(strict_checking)) >+ >+ self.admin_creds = creds >+ self.admin_samdb = SamDB(url=ldaphost, credentials=self.admin_creds, lp=lp) >+ self.domain_sid = security.dom_sid(self.admin_samdb.get_domain_sid()) >+ self.base_dn = self.admin_samdb.domain_dn() >+ >+ self.unpriv_user = "testuser1" >+ self.unpriv_user_pw = "samba123@" >+ self.unpriv_creds = self.get_creds(self.unpriv_user, self.unpriv_user_pw) >+ >+ self.admin_sd_utils = sd_utils.SDUtils(self.admin_samdb) >+ >+ self.test_ou_name = "OU=test_priv_attrs" >+ self.test_ou = self.test_ou_name + "," + self.base_dn >+ >+ delete_force(self.admin_samdb, self.test_ou, controls=["tree_delete:0"]) >+ >+ self.admin_samdb.create_ou(self.test_ou) >+ >+ expected_user_dn = f"CN={self.unpriv_user},{self.test_ou_name},{self.base_dn}" >+ >+ self.admin_samdb.newuser(self.unpriv_user, self.unpriv_user_pw, userou=self.test_ou_name) >+ res = self.admin_samdb.search(expected_user_dn, >+ scope=SCOPE_BASE, >+ attrs=["objectSid"]) >+ >+ self.assertEqual(1, len(res)) >+ >+ self.unpriv_user_dn = res[0].dn >+ self.addCleanup(delete_force, self.admin_samdb, self.unpriv_user_dn, controls=["tree_delete:0"]) >+ >+ self.unpriv_user_sid = self.admin_sd_utils.get_object_sid(self.unpriv_user_dn) >+ >+ self.unpriv_samdb = SamDB(url=ldaphost, credentials=self.unpriv_creds, lp=lp) >+ >+ @classmethod >+ def setUpDynamicTestCases(cls): >+ for test_name in attrs.keys(): >+ for add_or_mod in ["add", "mod-del-add", "mod-replace"]: >+ for permission in ["admin-add", "CC"]: >+ for sd in ["default", "WP"]: >+ for objectclass in ["computer", "user"]: >+ tname = f"{test_name}_{add_or_mod}_{permission}_{sd}_{objectclass}" >+ targs = (test_name, >+ add_or_mod, >+ permission, >+ sd, >+ objectclass) >+ cls.generate_dynamic_test("test_priv_attr", >+ tname, >+ *targs) >+ >+ def add_computer_ldap(self, computername, others=None, samdb=None): >+ dn = "CN=%s,%s" % (computername, self.test_ou) >+ domainname = ldb.Dn(samdb, samdb.domain_dn()).canonical_str().replace("/", "") >+ samaccountname = "%s$" % computername >+ dnshostname = "%s.%s" % (computername, domainname) >+ msg_dict = { >+ "dn": dn, >+ "objectclass": "computer"} >+ if others is not None: >+ msg_dict = dict(list(msg_dict.items()) + list(others.items())) >+ >+ msg = ldb.Message.from_dict(samdb, msg_dict) >+ msg["sAMAccountName"] = samaccountname >+ >+ print("Adding computer account %s" % computername) >+ try: >+ samdb.add(msg) >+ except ldb.LdbError: >+ print(msg) >+ raise >+ return msg.dn >+ >+ def add_user_ldap(self, username, others=None, samdb=None): >+ dn = "CN=%s,%s" % (username, self.test_ou) >+ domainname = ldb.Dn(samdb, samdb.domain_dn()).canonical_str().replace("/", "") >+ samaccountname = "%s$" % username >+ msg_dict = { >+ "dn": dn, >+ "objectclass": "user"} >+ if others is not None: >+ msg_dict = dict(list(msg_dict.items()) + list(others.items())) >+ >+ msg = ldb.Message.from_dict(samdb, msg_dict) >+ msg["sAMAccountName"] = samaccountname >+ >+ print("Adding user account %s" % username) >+ try: >+ samdb.add(msg) >+ except ldb.LdbError: >+ print(msg) >+ raise >+ return msg.dn >+ >+ def add_thing_ldap(self, user, others, samdb, objectclass): >+ if objectclass == "user": >+ dn = self.add_user_ldap(user, others, samdb=samdb) >+ elif objectclass == "computer": >+ dn = self.add_computer_ldap(user, others, samdb=samdb) >+ return dn >+ >+ def _test_priv_attr_with_args(self, test_name, add_or_mod, permission, sd, objectclass): >+ user="privattrs" >+ if "attr" in attrs[test_name]: >+ attr = attrs[test_name]["attr"] >+ else: >+ attr = test_name >+ if add_or_mod == "add": >+ others = {attr: attrs[test_name]["value"]} >+ else: >+ others = {} >+ >+ if permission == "CC": >+ samdb = self.unpriv_samdb >+ # Set CC on container to allow user add >+ mod = "(OA;CI;CC;bf967aba-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.unpriv_user_sid) >+ self.admin_sd_utils.dacl_add_ace(self.test_ou, mod) >+ mod = "(OA;CI;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.unpriv_user_sid) >+ self.admin_sd_utils.dacl_add_ace(self.test_ou, mod) >+ >+ else: >+ samdb = self.admin_samdb >+ >+ if sd == "WP": >+ # Set SD to WP to the target user as part of add >+ sd = "O:%sG:DUD:(OA;CIID;RPWP;;;%s)(OA;;CR;00299570-246d-11d0-a768-00aa006e0529;;%s)" % (self.unpriv_user_sid, self.unpriv_user_sid, self.unpriv_user_sid) >+ tmp_desc = security.descriptor.from_sddl(sd, self.domain_sid) >+ others["ntSecurityDescriptor"] = ndr_pack(tmp_desc) >+ >+ if add_or_mod == "add": >+ >+ # only-1 and only-2 are due to windows behaviour >+ >+ if "only-1" in attrs[test_name] and \ >+ attrs[test_name]["only-1"] != objectclass: >+ try: >+ dn = self.add_thing_ldap(user, others, samdb, objectclass) >+ self.fail(f"{test_name}: Unexpectedly able to set {attr} on new {objectclass} as ADMIN (should fail LDAP_OBJECT_CLASS_VIOLATION)") >+ except LdbError as e5: >+ (enum, estr) = e5.args >+ self.assertGotLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION, enum) >+ elif permission == "CC": >+ try: >+ dn = self.add_thing_ldap(user, others, samdb, objectclass) >+ self.fail(f"{test_name}: Unexpectedly able to set {attr} on new {objectclass}") >+ except LdbError as e5: >+ (enum, estr) = e5.args >+ if "unpriv-add-error" in attrs[test_name]: >+ self.assertGotLdbError(attrs[test_name]["unpriv-add-error"], \ >+ enum) >+ else: >+ self.assertGotLdbError(attrs[test_name]["unpriv-error"], \ >+ enum) >+ elif "only-2" in attrs[test_name] and \ >+ attrs[test_name]["only-2"] != objectclass: >+ try: >+ dn = self.add_thing_ldap(user, others, samdb, objectclass) >+ self.fail(f"{test_name}: Unexpectedly able to set {attr} on new {objectclass} as ADMIN (should fail LDAP_OBJECT_CLASS_VIOLATION)") >+ except LdbError as e5: >+ (enum, estr) = e5.args >+ self.assertGotLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION, enum) >+ elif "priv-error" in attrs[test_name]: >+ try: >+ dn = self.add_thing_ldap(user, others, samdb, objectclass) >+ self.fail(f"{test_name}: Unexpectedly able to set {attr} on new {objectclass} as ADMIN") >+ except LdbError as e5: >+ (enum, estr) = e5.args >+ self.assertGotLdbError(attrs[test_name]["priv-error"], enum) >+ else: >+ try: >+ dn = self.add_thing_ldap(user, others, samdb, objectclass) >+ except LdbError as e5: >+ (enum, estr) = e5.args >+ self.fail(f"Failed to add account {user} as objectclass {objectclass}") >+ else: >+ try: >+ dn = self.add_thing_ldap(user, others, samdb, objectclass) >+ except LdbError as e5: >+ (enum, estr) = e5.args >+ self.fail(f"Failed to add account {user} as objectclass {objectclass}") >+ >+ if add_or_mod == "add": >+ return >+ >+ m = ldb.Message() >+ m.dn = dn >+ >+ # Do modify >+ if add_or_mod == "mod-del-add": >+ m["0"] = ldb.MessageElement([], >+ ldb.FLAG_MOD_DELETE, >+ attr) >+ m["1"] = ldb.MessageElement(attrs[test_name]["value"], >+ ldb.FLAG_MOD_ADD, >+ attr) >+ else: >+ m["0"] = ldb.MessageElement(attrs[test_name]["value"], >+ ldb.FLAG_MOD_REPLACE, >+ attr) >+ >+ try: >+ self.unpriv_samdb.modify(m) >+ self.fail(f"{test_name}: Unexpectedly able to set {attr} on {m.dn}") >+ except LdbError as e5: >+ (enum, estr) = e5.args >+ if attr == "userAccountControl" and sd == "default": >+ # We get a different error if we try and swap between >+ # being a computer back to being a user when created with "Create child" permissions >+ if (int(attrs[test_name]["value"]) & UF_NORMAL_ACCOUNT) \ >+ and objectclass == "computer" and permission == "CC": >+ self.assertGotLdbError(ldb.ERR_UNWILLING_TO_PERFORM, enum) >+ return >+ self.assertGotLdbError(attrs[test_name]["unpriv-error"], enum) >+ >+ >+ >+ >+runner = SubunitTestRunner() >+rc = 0 >+if not runner.run(unittest.makeSuite(PrivAttrsTests)).wasSuccessful(): >+ rc = 1 >+sys.exit(rc) >diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py >index 0703e5ceddf3..640b085a9221 100755 >--- a/source4/selftest/tests.py >+++ b/source4/selftest/tests.py >@@ -1037,6 +1037,8 @@ plantestsuite("samba4.sam.python(fl2008r2dc)", "fl2008r2dc", [python, os.path.jo > plantestsuite("samba4.sam.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN']) > plantestsuite("samba4.asq.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "asq.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN']) > plantestsuite("samba4.user_account_control.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "user_account_control.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN']) >+plantestsuite("samba4.priv_attrs.python(ad_dc_default)", "ad_dc_default", ["STRICT_CHECKING=0", python, os.path.join(DSDB_PYTEST_DIR, "priv_attrs.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN']) >+plantestsuite("samba4.priv_attrs.strict.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "priv_attrs.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN']) > > for env in ['ad_dc_default:local', 'schema_dc:local']: > planoldpythontestsuite(env, "dsdb_schema_info", >-- >2.25.1 > > >From 8f105b75bd8691e1db7fd4d3d1d186022763ed8a Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 12 Aug 2021 11:10:09 +1200 >Subject: [PATCH 074/262] CVE-2020-25722 dsdb: Move krbtgt password setup after > the point of checking if any passwords are changed > >This allows the add of an RODC, before setting the password, to avoid >this module, which helps isolate testing of security around the >msDS-SecondaryKrbTgtNumber attribute. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14703 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/priv_attr | 12 +- > .../dsdb/samdb/ldb_modules/password_hash.c | 106 +++++++++--------- > 2 files changed, 57 insertions(+), 61 deletions(-) > >diff --git a/selftest/knownfail.d/priv_attr b/selftest/knownfail.d/priv_attr >index 31b9cb23b442..ab6db192aae7 100644 >--- a/selftest/knownfail.d/priv_attr >+++ b/selftest/knownfail.d/priv_attr >@@ -14,14 +14,10 @@ samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccoun > samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_user > samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_computer > samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_user >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_WP_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_WP_user >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_default_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_default_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_WP_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_WP_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_default_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_admin-add_default_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_WP_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_WP_user >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_default_computer >+samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_default_user > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_WP_computer > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_WP_user > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_default_computer >diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c >index 82d9e8ebd2ef..bb437a3b9826 100644 >--- a/source4/dsdb/samdb/ldb_modules/password_hash.c >+++ b/source4/dsdb/samdb/ldb_modules/password_hash.c >@@ -2476,6 +2476,59 @@ static int setup_password_fields(struct setup_password_fields_io *io) > return LDB_SUCCESS; > } > >+ if (io->u.is_krbtgt) { >+ size_t min = 196; >+ size_t max = 255; >+ size_t diff = max - min; >+ size_t len = max; >+ struct ldb_val *krbtgt_utf16 = NULL; >+ >+ if (!io->ac->pwd_reset) { >+ return dsdb_module_werror(io->ac->module, >+ LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS, >+ WERR_DS_ATT_ALREADY_EXISTS, >+ "Password change on krbtgt not permitted!"); >+ } >+ >+ if (io->n.cleartext_utf16 == NULL) { >+ return dsdb_module_werror(io->ac->module, >+ LDB_ERR_UNWILLING_TO_PERFORM, >+ WERR_DS_INVALID_ATTRIBUTE_SYNTAX, >+ "Password reset on krbtgt requires UTF16!"); >+ } >+ >+ /* >+ * Instead of taking the callers value, >+ * we just generate a new random value here. >+ * >+ * Include null termination in the array. >+ */ >+ if (diff > 0) { >+ size_t tmp; >+ >+ generate_random_buffer((uint8_t *)&tmp, sizeof(tmp)); >+ >+ tmp %= diff; >+ >+ len = min + tmp; >+ } >+ >+ krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val); >+ if (krbtgt_utf16 == NULL) { >+ return ldb_oom(ldb); >+ } >+ >+ *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16, >+ (len+1)*2); >+ if (krbtgt_utf16->data == NULL) { >+ return ldb_oom(ldb); >+ } >+ krbtgt_utf16->length = len * 2; >+ generate_secret_buffer(krbtgt_utf16->data, >+ krbtgt_utf16->length); >+ io->n.cleartext_utf16 = krbtgt_utf16; >+ } >+ > /* transform the old password (for password changes) */ > ret = setup_given_passwords(io, &io->og); > if (ret != LDB_SUCCESS) { >@@ -3653,59 +3706,6 @@ static int setup_io(struct ph_context *ac, > return ldb_operr(ldb); > } > >- if (io->u.is_krbtgt) { >- size_t min = 196; >- size_t max = 255; >- size_t diff = max - min; >- size_t len = max; >- struct ldb_val *krbtgt_utf16 = NULL; >- >- if (!ac->pwd_reset) { >- return dsdb_module_werror(ac->module, >- LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS, >- WERR_DS_ATT_ALREADY_EXISTS, >- "Password change on krbtgt not permitted!"); >- } >- >- if (io->n.cleartext_utf16 == NULL) { >- return dsdb_module_werror(ac->module, >- LDB_ERR_UNWILLING_TO_PERFORM, >- WERR_DS_INVALID_ATTRIBUTE_SYNTAX, >- "Password reset on krbtgt requires UTF16!"); >- } >- >- /* >- * Instead of taking the callers value, >- * we just generate a new random value here. >- * >- * Include null termination in the array. >- */ >- if (diff > 0) { >- size_t tmp; >- >- generate_random_buffer((uint8_t *)&tmp, sizeof(tmp)); >- >- tmp %= diff; >- >- len = min + tmp; >- } >- >- krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val); >- if (krbtgt_utf16 == NULL) { >- return ldb_oom(ldb); >- } >- >- *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16, >- (len+1)*2); >- if (krbtgt_utf16->data == NULL) { >- return ldb_oom(ldb); >- } >- krbtgt_utf16->length = len * 2; >- generate_secret_buffer(krbtgt_utf16->data, >- krbtgt_utf16->length); >- io->n.cleartext_utf16 = krbtgt_utf16; >- } >- > if (existing_msg != NULL) { > NTSTATUS status; > >-- >2.25.1 > > >From f29f8bc2e42365ce29cc314e1cb7535679f8d2a5 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Fri, 13 Aug 2021 17:42:23 +1200 >Subject: [PATCH 075/262] CVE-2020-25722 dsdb: Restrict the setting of > privileged attributes during LDAP add/modify > >The remaining failures in the priv_attrs (not the strict one) test are >due to missing objectclass constraints on the administrator which should >be addressed, but are not a security issue. > >A better test for confirming constraints between objectclass and >userAccountControl UF_NORMAL_ACCONT/UF_WORKSTATION_TRUST values would >be user_account_control.py. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14703 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14778 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14775 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/priv_attr | 24 ---- > source4/dsdb/samdb/ldb_modules/samldb.c | 148 +++++++++++++++++++++--- > 2 files changed, 129 insertions(+), 43 deletions(-) > >diff --git a/selftest/knownfail.d/priv_attr b/selftest/knownfail.d/priv_attr >index ab6db192aae7..c3a779010d9e 100644 >--- a/selftest/knownfail.d/priv_attr >+++ b/selftest/knownfail.d/priv_attr >@@ -1,31 +1,7 @@ >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_WP_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_WP_user >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_default_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_default_user >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_user >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_user >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_WP_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_WP_user >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_default_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_default_user > samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_computer > samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_user > samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_computer > samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_user >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_WP_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_WP_user >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_default_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_default_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_WP_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_WP_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_default_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-AllowedToDelegateTo_add_CC_default_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_WP_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_WP_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_default_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_msDS-SecondaryKrbTgtNumber_add_CC_default_user > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_computer > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_user > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_computer >diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c >index 4da8564c77ab..cb5fda324a4d 100644 >--- a/source4/dsdb/samdb/ldb_modules/samldb.c >+++ b/source4/dsdb/samdb/ldb_modules/samldb.c >@@ -1976,6 +1976,29 @@ static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac, > return ret; > } > >+static int samldb_get_domain_secdesc(struct samldb_ctx *ac, >+ struct security_descriptor **domain_sd) >+{ >+ const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL}; >+ struct ldb_result *res; >+ struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); >+ int ret = dsdb_module_search_dn(ac->module, ac, &res, >+ domain_dn, >+ sd_attrs, >+ DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, >+ ac->req); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ if (res->count != 1) { >+ return ldb_module_operr(ac->module); >+ } >+ >+ return dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(ac->module), >+ ac, res->msgs[0], domain_sd); >+ >+} >+ > /** > * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured > * >@@ -1987,12 +2010,8 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, > { > int i, ret = 0; > bool need_acl_check = false; >- struct ldb_result *res; >- const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL}; > struct security_token *user_token; > struct security_descriptor *domain_sd; >- struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); >- struct ldb_context *ldb = ldb_module_get_ctx(ac->module); > const struct uac_to_guid { > uint32_t uac; > uint32_t priv_to_change_from; >@@ -2078,21 +2097,7 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, > return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; > } > >- ret = dsdb_module_search_dn(ac->module, ac, &res, >- domain_dn, >- sd_attrs, >- DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, >- ac->req); >- if (ret != LDB_SUCCESS) { >- return ret; >- } >- if (res->count != 1) { >- return ldb_module_operr(ac->module); >- } >- >- ret = dsdb_get_sd_from_ldb_message(ldb, >- ac, res->msgs[0], &domain_sd); >- >+ ret = samldb_get_domain_secdesc(ac, &domain_sd); > if (ret != LDB_SUCCESS) { > return ret; > } >@@ -2154,6 +2159,8 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, > return ldb_module_operr(ac->module); > } > if (map[i].guid) { >+ struct ldb_dn *domain_dn >+ = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); > dsdb_acl_debug(domain_sd, acl_user_token(ac->module), > domain_dn, > true, >@@ -3486,7 +3493,98 @@ static char *refer_if_rodc(struct ldb_context *ldb, struct ldb_request *req, > return NULL; > } > >+/* >+ * Restrict all access to sensitive attributes. >+ * >+ * We don't want to even inspect the values, so we can use the same >+ * routine for ADD and MODIFY. >+ * >+ */ >+ >+static int samldb_check_sensitive_attributes(struct samldb_ctx *ac) >+{ >+ struct ldb_message_element *el = NULL; >+ struct security_token *user_token = NULL; >+ int ret; >+ >+ if (dsdb_module_am_system(ac->module)) { >+ return LDB_SUCCESS; >+ } >+ >+ user_token = acl_user_token(ac->module); >+ if (user_token == NULL) { >+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; >+ } >+ >+ el = ldb_msg_find_element(ac->msg, "sidHistory"); >+ if (el) { >+ /* >+ * sidHistory is restricted to the (not implemented >+ * yet in Samba) DsAddSidHistory call (direct LDB access is >+ * as SYSTEM so will bypass this). >+ * >+ * If you want to modify this, say to merge domains, >+ * directly modify the sam.ldb as root. >+ */ >+ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module), >+ "sidHistory " >+ "(entry %s) cannot be created " >+ "or changed over LDAP!", >+ ldb_dn_get_linearized(ac->msg->dn)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } > >+ el = ldb_msg_find_element(ac->msg, "msDS-SecondaryKrbTgtNumber"); >+ if (el) { >+ struct security_descriptor *domain_sd; >+ /* >+ * msDS-SecondaryKrbTgtNumber allows the creator to >+ * become an RODC, this is trusted as an RODC >+ * account >+ */ >+ ret = samldb_get_domain_secdesc(ac, &domain_sd); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ ret = acl_check_extended_right(ac, domain_sd, >+ user_token, >+ GUID_DRS_DS_INSTALL_REPLICA, >+ SEC_ADS_CONTROL_ACCESS, >+ NULL); >+ if (ret != LDB_SUCCESS) { >+ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module), >+ "msDS-SecondaryKrbTgtNumber " >+ "(entry %s) cannot be created " >+ "or changed without " >+ "DS-Install-Replica extended right!", >+ ldb_dn_get_linearized(ac->msg->dn)); >+ return ret; >+ } >+ } >+ >+ el = ldb_msg_find_element(ac->msg, "msDS-AllowedToDelegateTo"); >+ if (el) { >+ /* >+ * msDS-AllowedToDelegateTo is incredibly powerful, >+ * given that it allows a server to become ANY USER on >+ * the target server only listed by SPN so needs to be >+ * protected just as the userAccountControl >+ * UF_TRUSTED_FOR_DELEGATION is. >+ */ >+ >+ bool have_priv = security_token_has_privilege(user_token, >+ SEC_PRIV_ENABLE_DELEGATION); >+ if (have_priv == false) { >+ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module), >+ "msDS-AllowedToDelegateTo " >+ "(entry %s) cannot be created " >+ "or changed without SePrivEnableDelegation!", >+ ldb_dn_get_linearized(ac->msg->dn)); >+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; >+ } >+ } >+ return LDB_SUCCESS; >+} > /* add */ > static int samldb_add(struct ldb_module *module, struct ldb_request *req) > { >@@ -3533,6 +3631,12 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) > return ldb_operr(ldb); > } > >+ ret = samldb_check_sensitive_attributes(ac); >+ if (ret != LDB_SUCCESS) { >+ talloc_free(ac); >+ return ret; >+ } >+ > el = ldb_msg_find_element(ac->msg, "fSMORoleOwner"); > if (el != NULL) { > ret = samldb_fsmo_role_owner_check(ac); >@@ -3740,6 +3844,12 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) > return ldb_operr(ldb); > } > >+ ret = samldb_check_sensitive_attributes(ac); >+ if (ret != LDB_SUCCESS) { >+ talloc_free(ac); >+ return ret; >+ } >+ > if (is_undelete == NULL) { > el = ldb_msg_find_element(ac->msg, "primaryGroupID"); > if (el != NULL) { >-- >2.25.1 > > >From 3116ad1d82e07bde93af165dbbe62ec6bf31a190 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 13 Sep 2021 20:34:54 +1200 >Subject: [PATCH 076/262] CVE-2020-25722 selftest: Extend priv_attrs test - > work around UF_NORMAL_ACCOUNT rules on Windows 2019 (requires > |UF_PASSWD_NOTREQD or a password) - extend to also cover the sensitive > UF_TRUSTED_FOR_DELEGATION > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14703 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14778 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14775 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/priv_attr | 16 ++-------- > source4/dsdb/tests/python/priv_attrs.py | 40 +++++++++++++++---------- > 2 files changed, 27 insertions(+), 29 deletions(-) > >diff --git a/selftest/knownfail.d/priv_attr b/selftest/knownfail.d/priv_attr >index c3a779010d9e..4b85a8690892 100644 >--- a/selftest/knownfail.d/priv_attr >+++ b/selftest/knownfail.d/priv_attr >@@ -1,7 +1,3 @@ >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_user >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_computer >-samba4.priv_attrs.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_user > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_computer > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_user > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_computer >@@ -14,13 +10,5 @@ samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_use > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-RODC_add_CC_default_user > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-computer_add_CC_WP_user > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-computer_add_CC_default_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_WP_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_WP_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_default_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_default_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_WP_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_admin-add_default_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_mod-del-add_CC_default_computer >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_mod-replace_CC_default_computer >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-computer_add_CC_WP_user >+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-computer_add_CC_default_user >diff --git a/source4/dsdb/tests/python/priv_attrs.py b/source4/dsdb/tests/python/priv_attrs.py >index ec2b13045e5a..aa35dcc1317d 100644 >--- a/source4/dsdb/tests/python/priv_attrs.py >+++ b/source4/dsdb/tests/python/priv_attrs.py >@@ -99,30 +99,47 @@ attrs = {"sidHistory": > {"value": ndr_pack(security.dom_sid(security.SID_BUILTIN_ADMINISTRATORS)), > "priv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, > "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS}, >- "msDS-AllowedToDelegateTo": >+ >+ "msDS-AllowedToDelegateTo": > {"value": f"host/{host}", > "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS}, >- "userAccountControl-a2d-user": >+ >+ "userAccountControl-a2d-user": > {"attr": "userAccountControl", >- "value": str(UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION|UF_NORMAL_ACCOUNT), >- "priv-error": ldb.ERR_UNWILLING_TO_PERFORM, >- "unpriv-add-error": ldb.ERR_UNWILLING_TO_PERFORM, >+ "value": str(UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION|UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD), > "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS}, >- "userAccountControl-a2d-computer": >+ >+ "userAccountControl-a2d-computer": > {"attr": "userAccountControl", > "value": str(UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION|UF_WORKSTATION_TRUST_ACCOUNT), > "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, > "only-1": "computer"}, >- "userAccountControl-DC": >+ >+ # This flag makes many legitimate authenticated clients >+ # send a forwardable ticket-granting-ticket to the server >+ "userAccountControl-t4d-user": >+ {"attr": "userAccountControl", >+ "value": str(UF_TRUSTED_FOR_DELEGATION|UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD), >+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS}, >+ >+ "userAccountControl-t4d-computer": >+ {"attr": "userAccountControl", >+ "value": str(UF_TRUSTED_FOR_DELEGATION|UF_WORKSTATION_TRUST_ACCOUNT), >+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ "only-1": "computer"}, >+ >+ "userAccountControl-DC": > {"attr": "userAccountControl", > "value": str(UF_SERVER_TRUST_ACCOUNT), > "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, > "only-2": "computer"}, >- "userAccountControl-RODC": >+ >+ "userAccountControl-RODC": > {"attr": "userAccountControl", > "value": str(UF_PARTIAL_SECRETS_ACCOUNT|UF_WORKSTATION_TRUST_ACCOUNT), > "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, > "only-1": "computer"}, >+ > "msDS-SecondaryKrbTgtNumber": > {"value": "65536", > "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS}, >@@ -369,13 +386,6 @@ class PrivAttrsTests(samba.tests.TestCase): > self.fail(f"{test_name}: Unexpectedly able to set {attr} on {m.dn}") > except LdbError as e5: > (enum, estr) = e5.args >- if attr == "userAccountControl" and sd == "default": >- # We get a different error if we try and swap between >- # being a computer back to being a user when created with "Create child" permissions >- if (int(attrs[test_name]["value"]) & UF_NORMAL_ACCOUNT) \ >- and objectclass == "computer" and permission == "CC": >- self.assertGotLdbError(ldb.ERR_UNWILLING_TO_PERFORM, enum) >- return > self.assertGotLdbError(attrs[test_name]["unpriv-error"], enum) > > >-- >2.25.1 > > >From 84598dbc899667718c3d227c2f808bc71a653365 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 13 Sep 2021 10:21:03 +1200 >Subject: [PATCH 077/262] CVE-2020-25722 selftest: Test combinations of account > type and objectclass for creating a user > >The idea here is to split out the restrictions seen on Windows 2019 >at the schema level, as seen when acting as an administrator. > >These pass against Windows 2019 except for the account type swapping >which is not wanted. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > .../user_account_control-uac_mod_lock | 11 ++ > .../dsdb/tests/python/user_account_control.py | 165 ++++++++++++++++++ > 2 files changed, 176 insertions(+) > create mode 100644 selftest/knownfail.d/user_account_control-uac_mod_lock > >diff --git a/selftest/knownfail.d/user_account_control-uac_mod_lock b/selftest/knownfail.d/user_account_control-uac_mod_lock >new file mode 100644 >index 000000000000..a70534506f37 >--- /dev/null >+++ b/selftest/knownfail.d/user_account_control-uac_mod_lock >@@ -0,0 +1,11 @@ >+# We do not want user account control account type swapping, so we mark these as knownfail >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_computer_replace >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_user_replace >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_SERVER_TRUST_ACCOUNT_computer_replace >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_replace >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_WORKSTATION_TRUST_ACCOUNT_deladd >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_WORKSTATION_TRUST_ACCOUNT_replace >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_SERVER_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_deladd >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_SERVER_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_replace >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_deladd >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_replace >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index c9b50b83e9da..442fe7412200 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -91,6 +91,41 @@ account_types = set([UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_ > class UserAccountControlTests(samba.tests.TestCase): > @classmethod > def setUpDynamicTestCases(cls): >+ for account_type in [UF_NORMAL_ACCOUNT, >+ UF_WORKSTATION_TRUST_ACCOUNT, >+ UF_SERVER_TRUST_ACCOUNT]: >+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type) >+ for objectclass in ["computer", "user"]: >+ test_name = f"{account_type_str}_{objectclass}" >+ cls.generate_dynamic_test("test_objectclass_uac_lock", >+ test_name, >+ account_type, >+ objectclass) >+ >+ for account_type in [UF_NORMAL_ACCOUNT, >+ UF_WORKSTATION_TRUST_ACCOUNT, >+ UF_SERVER_TRUST_ACCOUNT]: >+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type) >+ for account_type2 in [UF_NORMAL_ACCOUNT, >+ UF_WORKSTATION_TRUST_ACCOUNT, >+ UF_SERVER_TRUST_ACCOUNT]: >+ for how in ["replace", "deladd"]: >+ account_type2_str = dsdb.user_account_control_flag_bit_to_string(account_type2) >+ test_name = f"{account_type_str}_{account_type2_str}_{how}" >+ cls.generate_dynamic_test("test_objectclass_uac_mod_lock", >+ test_name, >+ account_type, >+ account_type2, >+ how) >+ for objectclass in ["user", "computer"]: >+ for how in ["replace", "deladd"]: >+ test_name = f"{account_type_str}_{objectclass}_{how}" >+ cls.generate_dynamic_test("test_objectclass_mod_lock", >+ test_name, >+ account_type, >+ objectclass, >+ how) >+ > for account_type in [UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT]: > account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type) > cls.generate_dynamic_test("test_uac_bits_unrelated_modify", >@@ -844,6 +879,136 @@ class UserAccountControlTests(samba.tests.TestCase): > "primaryGroupID") > self.admin_samdb.modify(m) > >+ def _test_objectclass_uac_lock_with_args(self, >+ account_type, >+ objectclass): >+ name = "oc_uac_lock$" >+ dn = "CN=%s,%s" % (name, self.OU) >+ msg_dict = { >+ "dn": dn, >+ "objectclass": objectclass, >+ "samAccountName": name, >+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)} >+ >+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type) >+ >+ print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}") >+ >+ if (objectclass == "user" \ >+ and account_type == UF_NORMAL_ACCOUNT): >+ self.admin_samdb.add(msg_dict) >+ elif objectclass == "computer": >+ self.admin_samdb.add(msg_dict) >+ else: >+ self.assertRaisesLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION, >+ "Should have been unable to {account_type_str} on {objectclass}", >+ self.admin_samdb.add, msg_dict) >+ >+ def _test_objectclass_uac_mod_lock_with_args(self, >+ account_type, >+ account_type2, >+ how): >+ name = "uac_mod_lock$" >+ dn = "CN=%s,%s" % (name, self.OU) >+ if account_type == UF_NORMAL_ACCOUNT: >+ objectclass = "user" >+ else: >+ objectclass = "computer" >+ >+ msg_dict = { >+ "dn": dn, >+ "objectclass": objectclass, >+ "samAccountName": name, >+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)} >+ >+ account_type_str \ >+ = dsdb.user_account_control_flag_bit_to_string(account_type) >+ account_type2_str \ >+ = dsdb.user_account_control_flag_bit_to_string(account_type2) >+ >+ print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}") >+ >+ self.admin_samdb.add(msg_dict) >+ >+ m = ldb.Message() >+ m.dn = ldb.Dn(self.admin_samdb, dn) >+ if how == "replace": >+ m["userAccountControl"] = ldb.MessageElement(str(account_type2 | UF_PASSWD_NOTREQD), >+ ldb.FLAG_MOD_REPLACE, "userAccountControl") >+ elif how == "deladd": >+ m["0userAccountControl"] = ldb.MessageElement([], >+ ldb.FLAG_MOD_DELETE, "userAccountControl") >+ m["1userAccountControl"] = ldb.MessageElement(str(account_type2 | UF_PASSWD_NOTREQD), >+ ldb.FLAG_MOD_ADD, "userAccountControl") >+ else: >+ raise ValueError(f"{how} was not a valid argument") >+ >+ if (account_type in [UF_SERVER_TRUST_ACCOUNT, >+ UF_WORKSTATION_TRUST_ACCOUNT]) and \ >+ (account_type2 in [UF_SERVER_TRUST_ACCOUNT, >+ UF_WORKSTATION_TRUST_ACCOUNT]): >+ self.admin_samdb.modify(m) >+ elif (account_type == account_type2): >+ self.admin_samdb.modify(m) >+ else: >+ self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM, >+ f"Should have been unable to change {account_type_str} to {account_type2_str}", >+ self.admin_samdb.modify, m) >+ >+ def _test_objectclass_mod_lock_with_args(self, >+ account_type, >+ objectclass, >+ how): >+ name = "uac_mod_lock$" >+ dn = "CN=%s,%s" % (name, self.OU) >+ if objectclass == "computer": >+ new_objectclass = ["top", >+ "person", >+ "organizationalPerson", >+ "user"] >+ elif objectclass == "user": >+ new_objectclass = ["top", >+ "person", >+ "organizationalPerson", >+ "user", >+ "computer"] >+ >+ msg_dict = { >+ "dn": dn, >+ "objectclass": objectclass, >+ "samAccountName": name, >+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)} >+ >+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type) >+ >+ print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}") >+ >+ try: >+ self.admin_samdb.add(msg_dict) >+ if (objectclass == "user" \ >+ and account_type != UF_NORMAL_ACCOUNT): >+ self.fail("Able to create {account_type_str} on {objectclass}") >+ except LdbError as e: >+ (enum, estr) = e.args >+ self.assertEqual(enum, ldb.ERR_OBJECT_CLASS_VIOLATION) >+ >+ if objectclass == "user" and account_type != UF_NORMAL_ACCOUNT: >+ return >+ >+ m = ldb.Message() >+ m.dn = ldb.Dn(self.admin_samdb, dn) >+ if how == "replace": >+ m["objectclass"] = ldb.MessageElement(new_objectclass, >+ ldb.FLAG_MOD_REPLACE, "objectclass") >+ elif how == "adddel": >+ m["0objectclass"] = ldb.MessageElement([], >+ ldb.FLAG_MOD_DELETE, "objectclass") >+ m["1objectclass"] = ldb.MessageElement(new_objectclass, >+ ldb.FLAG_MOD_ADD, "objectclass") >+ >+ self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM, >+ "Should have been unable Able to change objectclass of a {objectclass}", >+ self.admin_samdb.modify, m) > > runner = SubunitTestRunner() > rc = 0 >-- >2.25.1 > > >From 4a364f37e1c565fed93805e08aba420636d2a518 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 20 Sep 2021 12:35:51 +1200 >Subject: [PATCH 078/262] CVE-2020-25722 selftest: allow for future failures in > BindTests.test_virtual_email_account_style_bind > >This allows for any failures here to be handled via the knownfail system. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > auth/credentials/tests/bind.py | 13 +++++++++++-- > 1 file changed, 11 insertions(+), 2 deletions(-) > >diff --git a/auth/credentials/tests/bind.py b/auth/credentials/tests/bind.py >index 8bee6f96c62a..b6b65a56c757 100755 >--- a/auth/credentials/tests/bind.py >+++ b/auth/credentials/tests/bind.py >@@ -90,7 +90,8 @@ class BindTests(samba.tests.TestCase): > # this test to detect when the LDAP DN is being double-parsed > # but must be in the user@realm style to allow the account to > # be created >- self.ldb.add_ldif(""" >+ try: >+ self.ldb.add_ldif(""" > dn: """ + self.virtual_user_dn + """ > cn: frednurk@""" + self.realm + """ > displayName: Fred Nurk >@@ -103,13 +104,21 @@ objectClass: person > objectClass: top > objectClass: user > """) >+ except LdbError as e: >+ (num, msg) = e.args >+ self.fail(f"Failed to create e-mail user: {msg}") >+ > self.addCleanup(delete_force, self.ldb, self.virtual_user_dn) >- self.ldb.modify_ldif(""" >+ try: >+ self.ldb.modify_ldif(""" > dn: """ + self.virtual_user_dn + """ > changetype: modify > replace: unicodePwd > unicodePwd:: """ + base64.b64encode(u"\"P@ssw0rd\"".encode('utf-16-le')).decode('utf8') + """ > """) >+ except LdbError as e: >+ (num, msg) = e.args >+ self.fail(f"Failed to set password on e-mail user: {msg}") > > self.ldb.enable_account('distinguishedName=%s' % self.virtual_user_dn) > >-- >2.25.1 > > >From 254680d76deb15dc82c61c1a2236f41db2bccfa8 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 20 Sep 2021 14:54:03 +1200 >Subject: [PATCH 079/262] CVE-2020-25722 selftest: Catch possible errors in > PasswordSettingsTestCase.test_pso_none_applied() > >This allows future patches to restrict changing the account type >without triggering an error. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > .../dsdb/tests/python/password_settings.py | 30 ++++++++++++------- > 1 file changed, 19 insertions(+), 11 deletions(-) > >diff --git a/source4/dsdb/tests/python/password_settings.py b/source4/dsdb/tests/python/password_settings.py >index fcb671690c34..e1c49d7bffb2 100644 >--- a/source4/dsdb/tests/python/password_settings.py >+++ b/source4/dsdb/tests/python/password_settings.py >@@ -594,19 +594,27 @@ class PasswordSettingsTestCase(PasswordTestCase): > dummy_pso.apply_to(user.dn) > self.assertTrue(user.get_resultant_PSO() == dummy_pso.dn) > >- # now clear the ADS_UF_NORMAL_ACCOUNT flag for the user, which should >- # mean a resultant PSO is no longer returned (we're essentially turning >- # the user into a DC here, which is a little overkill but tests >- # behaviour as per the Windows specification) >- self.set_attribute(user.dn, "userAccountControl", >- str(dsdb.UF_WORKSTATION_TRUST_ACCOUNT), >- operation=FLAG_MOD_REPLACE) >+ try: >+ # now clear the ADS_UF_NORMAL_ACCOUNT flag for the user, which should >+ # mean a resultant PSO is no longer returned (we're essentially turning >+ # the user into a DC here, which is a little overkill but tests >+ # behaviour as per the Windows specification) >+ self.set_attribute(user.dn, "userAccountControl", >+ str(dsdb.UF_WORKSTATION_TRUST_ACCOUNT), >+ operation=FLAG_MOD_REPLACE) >+ except ldb.LdbError as e: >+ (num, msg) = e.args >+ self.fail("Failed to change user into a workstation: {msg}") > self.assertIsNone(user.get_resultant_PSO()) > >- # reset it back to a normal user account >- self.set_attribute(user.dn, "userAccountControl", >- str(dsdb.UF_NORMAL_ACCOUNT), >- operation=FLAG_MOD_REPLACE) >+ try: >+ # reset it back to a normal user account >+ self.set_attribute(user.dn, "userAccountControl", >+ str(dsdb.UF_NORMAL_ACCOUNT), >+ operation=FLAG_MOD_REPLACE) >+ except ldb.LdbError as e: >+ (num, msg) = e.args >+ self.fail("Failed to change user back into a user: {msg}") > self.assertTrue(user.get_resultant_PSO() == dummy_pso.dn) > > # no PSO should be returned if RID is equal to DOMAIN_USER_RID_KRBTGT >-- >2.25.1 > > >From b9f226672807587870b0f6e485eab599beb455ec Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Fri, 17 Sep 2021 13:41:40 +1200 >Subject: [PATCH 080/262] CVE-2020-25722 selftest: Catch errors from > samdb.modify() in user_account_control tests > >This will allow these to be listed in a knownfail shortly. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > .../dsdb/tests/python/user_account_control.py | 31 ++++++++++++++++--- > 1 file changed, 26 insertions(+), 5 deletions(-) > >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index 442fe7412200..a22a72f12daa 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -306,7 +306,11 @@ class UserAccountControlTests(samba.tests.TestCase): > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- self.samdb.modify(m) >+ try: >+ self.samdb.modify(m) >+ except LdbError as e: >+ (enum, estr) = e.args >+ self.fail(f"got {estr} setting userAccountControl to UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD") > > m = ldb.Message() > m.dn = res[0].dn >@@ -361,7 +365,11 @@ class UserAccountControlTests(samba.tests.TestCase): > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- self.samdb.modify(m) >+ try: >+ self.samdb.modify(m) >+ except LdbError as e: >+ (enum, estr) = e.args >+ self.fail(f"got {estr} setting userAccountControl to UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD") > > m = ldb.Message() > m.dn = res[0].dn >@@ -458,7 +466,11 @@ class UserAccountControlTests(samba.tests.TestCase): > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(UF_ACCOUNTDISABLE), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- self.admin_samdb.modify(m) >+ try: >+ self.admin_samdb.modify(m) >+ except LdbError as e: >+ (enum, estr) = e.args >+ self.fail(f"got {estr} setting userAccountControl to UF_ACCOUNTDISABLE (as admin)") > > res = self.admin_samdb.search("%s" % self.base_dn, > expression="(&(objectClass=computer)(samAccountName=%s$))" % computername, >@@ -579,7 +591,11 @@ class UserAccountControlTests(samba.tests.TestCase): > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(orig_uac), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- self.admin_samdb.modify(m) >+ try: >+ self.admin_samdb.modify(m) >+ except LdbError as e: >+ (enum, estr) = e.args >+ self.fail(f"got {estr} resetting userAccountControl to initial value {orig_uac:#08x}") > > res = self.admin_samdb.search("%s" % self.base_dn, > expression="(&(objectClass=computer)(samAccountName=%s$))" % computername, >@@ -898,7 +914,12 @@ class UserAccountControlTests(samba.tests.TestCase): > and account_type == UF_NORMAL_ACCOUNT): > self.admin_samdb.add(msg_dict) > elif objectclass == "computer": >- self.admin_samdb.add(msg_dict) >+ try: >+ self.admin_samdb.add(msg_dict) >+ except ldb.LdbError as e: >+ (num, msg) = e.args >+ self.fail("Failed to create {objectclass} account " >+ "with {account_type_string}") > else: > self.assertRaisesLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION, > "Should have been unable to {account_type_str} on {objectclass}", >-- >2.25.1 > > >From ccd92433614b529d3836e07922efd8a43ba10d79 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 16 Sep 2021 08:46:42 +1200 >Subject: [PATCH 081/262] CVE-2020-25722 dsdb: objectclass computer becomes > UF_WORKSTATION_TRUST by default > >There are a lot of knownfail entries added with this commit. These >all need to be addressed and removed in subsequent commits which >will restructure the tests to pass within this new reality. > >This default applies even to users with administrator rights, >as changing the default based on permissions would break >to many assumptions. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_objectclass_restrict | 42 +++++++++++++++++++ > source4/dsdb/samdb/ldb_modules/samldb.c | 27 +++++++++--- > 2 files changed, 64 insertions(+), 5 deletions(-) > create mode 100644 selftest/knownfail.d/uac_objectclass_restrict > >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >new file mode 100644 >index 000000000000..a076f9cfedb9 >--- /dev/null >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -0,0 +1,42 @@ >+# Knownfail entries due to restricting the creation of computer/user >+# accounts (in terms of userAccountControl) that do not match the objectclass >+# >+# All these tests need to be fixed and the entries here removed >+ >+^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_isCriticalSystemObject\(fl2008r2dc\) >+^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_userAccountControl\(fl2008r2dc\) >+^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_users_groups\(fl2008r2dc\) >+^samba4.ldap.python\(ad_dc_default\).__main__.BasicTests.test_all\(ad_dc_default\) >+^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_isCriticalSystemObject\(ad_dc_default\) >+^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_userAccountControl\(ad_dc_default\) >+^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_users_groups\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_add_computer_sd_cc\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_admin_mod_uac\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_computer_cc\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x10000000\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x20000000\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x40000000\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x80000000\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00000004\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00000400\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00004000\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00008000\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_ACCOUNTDISABLE\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_DONT_EXPIRE_PASSWD\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_DONT_REQUIRE_PREAUTH\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_HOMEDIR_REQUIRED\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_LOCKOUT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_MNS_LOGON_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_NORMAL_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_NOT_DELEGATED\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_NO_AUTH_DATA_REQUIRED\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_PASSWD_CANT_CHANGE\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_PASSWD_NOTREQD\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_PASSWORD_EXPIRED\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_SCRIPT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_SMARTCARD_REQUIRED\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_USE_AES_KEYS\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_USE_DES_KEY_ONLY\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_NORMAL_ACCOUNT\(ad_dc_default\) >diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c >index cb5fda324a4d..8df86f29883b 100644 >--- a/source4/dsdb/samdb/ldb_modules/samldb.c >+++ b/source4/dsdb/samdb/ldb_modules/samldb.c >@@ -1413,19 +1413,33 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) > > switch(ac->type) { > case SAMLDB_TYPE_USER: { >+ bool is_computer_objectclass; > bool uac_generated = false, uac_add_flags = false; >- >+ uint32_t default_user_account_control = UF_NORMAL_ACCOUNT; > /* Step 1.2: Default values */ > ret = dsdb_user_obj_set_defaults(ldb, ac->msg, ac->req); > if (ret != LDB_SUCCESS) return ret; > >+ is_computer_objectclass >+ = (samdb_find_attribute(ldb, >+ ac->msg, >+ "objectclass", >+ "computer") >+ != NULL); >+ >+ if (is_computer_objectclass) { >+ default_user_account_control >+ = UF_WORKSTATION_TRUST_ACCOUNT; >+ } >+ >+ > /* On add operations we might need to generate a > * "userAccountControl" (if it isn't specified). */ > el = ldb_msg_find_element(ac->msg, "userAccountControl"); > if ((el == NULL) && (ac->req->operation == LDB_ADD)) { > ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg, > "userAccountControl", >- UF_NORMAL_ACCOUNT); >+ default_user_account_control); > if (ret != LDB_SUCCESS) { > return ret; > } >@@ -1444,11 +1458,14 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) > raw_uac = user_account_control; > /* > * "userAccountControl" = 0 or missing one of >- * the types means "UF_NORMAL_ACCOUNT". See >- * MS-SAMR 3.1.1.8.10 point 8 >+ * the types means "UF_NORMAL_ACCOUNT" >+ * or "UF_WORKSTATION_TRUST_ACCOUNT" (if a computer). >+ * See MS-SAMR 3.1.1.8.10 point 8 > */ > if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) { >- user_account_control = UF_NORMAL_ACCOUNT | user_account_control; >+ user_account_control >+ = default_user_account_control >+ | user_account_control; > uac_generated = true; > } > >-- >2.25.1 > > >From f45b8e78dde98bd6edd48052fdaac9d996ec7908 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Fri, 22 Oct 2021 15:42:08 +1300 >Subject: [PATCH 082/262] CVE-2020-25722 dsdb: Improve privileged and > unprivileged tests for objectclass/doller/UAC > >This helps ensure we cover off all the cases that matter >for objectclass/trailing-doller/userAccountControl > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_dollar_lock | 1 + > selftest/knownfail.d/uac_objectclass_restrict | 18 +- > .../user_account_control-uac_mod_lock | 11 -- > .../dsdb/tests/python/user_account_control.py | 172 +++++++++++++----- > 4 files changed, 142 insertions(+), 60 deletions(-) > create mode 100644 selftest/knownfail.d/uac_dollar_lock > delete mode 100644 selftest/knownfail.d/user_account_control-uac_mod_lock > >diff --git a/selftest/knownfail.d/uac_dollar_lock b/selftest/knownfail.d/uac_dollar_lock >new file mode 100644 >index 000000000000..8c70c859fa4a >--- /dev/null >+++ b/selftest/knownfail.d/uac_dollar_lock >@@ -0,0 +1 @@ >+^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_dollar_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_cc_plain >\ No newline at end of file >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index a076f9cfedb9..bb0787c1a48b 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -13,6 +13,22 @@ > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_add_computer_sd_cc\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_admin_mod_uac\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_computer_cc\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_computer_replace\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_user_replace\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_SERVER_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_NORMAL_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_dollar_lock_UF_NORMAL_ACCOUNT_computer_cc_plain\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_dollar_lock_UF_NORMAL_ACCOUNT_computer_cc_withdollar\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_dollar_lock_UF_SERVER_TRUST_ACCOUNT_user_cc_plain\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_dollar_lock_UF_SERVER_TRUST_ACCOUNT_user_cc_withdollar\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_WORKSTATION_TRUST_ACCOUNT_deladd_wp\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_WORKSTATION_TRUST_ACCOUNT_replace_wp\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_SERVER_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_deladd_wp\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_SERVER_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_replace_wp\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_deladd_wp\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_replace_wp\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x10000000\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x20000000\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x40000000\(ad_dc_default\) >@@ -38,5 +54,3 @@ > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_SMARTCARD_REQUIRED\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_USE_AES_KEYS\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_USE_DES_KEY_ONLY\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_NORMAL_ACCOUNT\(ad_dc_default\) >diff --git a/selftest/knownfail.d/user_account_control-uac_mod_lock b/selftest/knownfail.d/user_account_control-uac_mod_lock >deleted file mode 100644 >index a70534506f37..000000000000 >--- a/selftest/knownfail.d/user_account_control-uac_mod_lock >+++ /dev/null >@@ -1,11 +0,0 @@ >-# We do not want user account control account type swapping, so we mark these as knownfail >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_computer_replace >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_user_replace >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_SERVER_TRUST_ACCOUNT_computer_replace >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_replace >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_WORKSTATION_TRUST_ACCOUNT_deladd >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_WORKSTATION_TRUST_ACCOUNT_replace >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_SERVER_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_deladd >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_SERVER_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_replace >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_deladd >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_replace >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index a22a72f12daa..dabbac6373a5 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -91,32 +91,43 @@ account_types = set([UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_ > class UserAccountControlTests(samba.tests.TestCase): > @classmethod > def setUpDynamicTestCases(cls): >+ for priv in [(True, "priv"), (False, "cc")]: >+ for account_type in [UF_NORMAL_ACCOUNT, >+ UF_WORKSTATION_TRUST_ACCOUNT, >+ UF_SERVER_TRUST_ACCOUNT]: >+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type) >+ for objectclass in ["computer", "user"]: >+ for name in [("oc_uac_lock$", "withdollar"), \ >+ ("oc_uac_lock", "plain")]: >+ test_name = f"{account_type_str}_{objectclass}_{priv[1]}_{name[1]}" >+ cls.generate_dynamic_test("test_objectclass_uac_dollar_lock", >+ test_name, >+ account_type, >+ objectclass, >+ name[0], >+ priv[0]) >+ >+ for priv in [(True, "priv"), (False, "wp")]: >+ for account_type in [UF_NORMAL_ACCOUNT, >+ UF_WORKSTATION_TRUST_ACCOUNT, >+ UF_SERVER_TRUST_ACCOUNT]: >+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type) >+ for account_type2 in [UF_NORMAL_ACCOUNT, >+ UF_WORKSTATION_TRUST_ACCOUNT, >+ UF_SERVER_TRUST_ACCOUNT]: >+ for how in ["replace", "deladd"]: >+ account_type2_str = dsdb.user_account_control_flag_bit_to_string(account_type2) >+ test_name = f"{account_type_str}_{account_type2_str}_{how}_{priv[1]}" >+ cls.generate_dynamic_test("test_objectclass_uac_mod_lock", >+ test_name, >+ account_type, >+ account_type2, >+ how, >+ priv[0]) > for account_type in [UF_NORMAL_ACCOUNT, > UF_WORKSTATION_TRUST_ACCOUNT, > UF_SERVER_TRUST_ACCOUNT]: > account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type) >- for objectclass in ["computer", "user"]: >- test_name = f"{account_type_str}_{objectclass}" >- cls.generate_dynamic_test("test_objectclass_uac_lock", >- test_name, >- account_type, >- objectclass) >- >- for account_type in [UF_NORMAL_ACCOUNT, >- UF_WORKSTATION_TRUST_ACCOUNT, >- UF_SERVER_TRUST_ACCOUNT]: >- account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type) >- for account_type2 in [UF_NORMAL_ACCOUNT, >- UF_WORKSTATION_TRUST_ACCOUNT, >- UF_SERVER_TRUST_ACCOUNT]: >- for how in ["replace", "deladd"]: >- account_type2_str = dsdb.user_account_control_flag_bit_to_string(account_type2) >- test_name = f"{account_type_str}_{account_type2_str}_{how}" >- cls.generate_dynamic_test("test_objectclass_uac_mod_lock", >- test_name, >- account_type, >- account_type2, >- how) > for objectclass in ["user", "computer"]: > for how in ["replace", "deladd"]: > test_name = f"{account_type_str}_{objectclass}_{how}" >@@ -895,10 +906,11 @@ class UserAccountControlTests(samba.tests.TestCase): > "primaryGroupID") > self.admin_samdb.modify(m) > >- def _test_objectclass_uac_lock_with_args(self, >- account_type, >- objectclass): >- name = "oc_uac_lock$" >+ def _test_objectclass_uac_dollar_lock_with_args(self, >+ account_type, >+ objectclass, >+ name, >+ priv): > dn = "CN=%s,%s" % (name, self.OU) > msg_dict = { > "dn": dn, >@@ -910,25 +922,57 @@ class UserAccountControlTests(samba.tests.TestCase): > > print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}") > >- if (objectclass == "user" \ >- and account_type == UF_NORMAL_ACCOUNT): >- self.admin_samdb.add(msg_dict) >- elif objectclass == "computer": >- try: >- self.admin_samdb.add(msg_dict) >- except ldb.LdbError as e: >- (num, msg) = e.args >- self.fail("Failed to create {objectclass} account " >- "with {account_type_string}") >+ if priv: >+ samdb = self.admin_samdb > else: >- self.assertRaisesLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION, >- "Should have been unable to {account_type_str} on {objectclass}", >- self.admin_samdb.add, msg_dict) >+ user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) >+ mod = "(OA;;CC;;;%s)" % str(user_sid) >+ >+ self.sd_utils.dacl_add_ace(self.OU, mod) >+ samdb = self.samdb >+ >+ enum = ldb.SUCCESS >+ try: >+ samdb.add(msg_dict) >+ except ldb.LdbError as e: >+ (enum, msg) = e.args >+ >+ if (account_type == UF_SERVER_TRUST_ACCOUNT >+ and objectclass != "computer"): >+ self.assertEqual(enum, ldb.ERR_OBJECT_CLASS_VIOLATION) >+ return >+ >+ if priv == False and account_type == UF_SERVER_TRUST_ACCOUNT: >+ self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) >+ return >+ >+ if (objectclass == "user" >+ and account_type != UF_NORMAL_ACCOUNT): >+ self.assertEqual(enum, ldb.ERR_OBJECT_CLASS_VIOLATION) >+ return >+ >+ if (not priv and objectclass == "computer" >+ and account_type == UF_NORMAL_ACCOUNT): >+ self.assertEqual(enum, ldb.ERR_OBJECT_CLASS_VIOLATION) >+ return >+ >+ if priv and account_type == UF_NORMAL_ACCOUNT: >+ self.assertEqual(enum, 0) >+ return >+ >+ if (priv == False and >+ account_type != UF_NORMAL_ACCOUNT and >+ name[-1] != '$'): >+ self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM) >+ return >+ >+ self.assertEqual(enum, 0) > > def _test_objectclass_uac_mod_lock_with_args(self, > account_type, > account_type2, >- how): >+ how, >+ priv): > name = "uac_mod_lock$" > dn = "CN=%s,%s" % (name, self.OU) > if account_type == UF_NORMAL_ACCOUNT: >@@ -949,10 +993,25 @@ class UserAccountControlTests(samba.tests.TestCase): > > print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}") > >+ if priv: >+ samdb = self.admin_samdb >+ else: >+ samdb = self.samdb >+ >+ user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) >+ >+ # Create the object as admin > self.admin_samdb.add(msg_dict) > >+ # We want to test what the underlying rules for non-admins >+ # regardless of security descriptors are, so set this very, >+ # dangerously, broadly >+ mod = "(OA;;WP;;;%s)" % str(user_sid) >+ >+ self.sd_utils.dacl_add_ace(dn, mod) >+ > m = ldb.Message() >- m.dn = ldb.Dn(self.admin_samdb, dn) >+ m.dn = ldb.Dn(samdb, dn) > if how == "replace": > m["userAccountControl"] = ldb.MessageElement(str(account_type2 | UF_PASSWD_NOTREQD), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >@@ -964,17 +1023,36 @@ class UserAccountControlTests(samba.tests.TestCase): > else: > raise ValueError(f"{how} was not a valid argument") > >- if (account_type in [UF_SERVER_TRUST_ACCOUNT, >- UF_WORKSTATION_TRUST_ACCOUNT]) and \ >+ if (account_type == account_type2): >+ samdb.modify(m) >+ elif (account_type == UF_NORMAL_ACCOUNT) and \ >+ (account_type2 == UF_SERVER_TRUST_ACCOUNT) and not priv: >+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ f"Should have been unable to change {account_type_str} to {account_type2_str}", >+ samdb.modify, m) >+ elif (account_type == UF_NORMAL_ACCOUNT) and \ >+ (account_type2 == UF_SERVER_TRUST_ACCOUNT) and priv: >+ self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM, >+ f"Should have been unable to change {account_type_str} to {account_type2_str}", >+ samdb.modify, m) >+ elif (account_type == UF_WORKSTATION_TRUST_ACCOUNT) and \ >+ (account_type2 == UF_SERVER_TRUST_ACCOUNT) and not priv: >+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ f"Should have been unable to change {account_type_str} to {account_type2_str}", >+ samdb.modify, m) >+ elif priv: >+ samdb.modify(m) >+ elif (account_type in [UF_SERVER_TRUST_ACCOUNT, >+ UF_WORKSTATION_TRUST_ACCOUNT]) and \ > (account_type2 in [UF_SERVER_TRUST_ACCOUNT, > UF_WORKSTATION_TRUST_ACCOUNT]): >- self.admin_samdb.modify(m) >+ samdb.modify(m) > elif (account_type == account_type2): >- self.admin_samdb.modify(m) >+ samdb.modify(m) > else: >- self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM, >+ self.assertRaisesLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION, > f"Should have been unable to change {account_type_str} to {account_type2_str}", >- self.admin_samdb.modify, m) >+ samdb.modify, m) > > def _test_objectclass_mod_lock_with_args(self, > account_type, >-- >2.25.1 > > >From 0f7094af785cd6c09205f1d2eb5a12762ca5f09d Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Fri, 29 Oct 2021 23:33:32 +1300 >Subject: [PATCH 083/262] CVE-2020-25722 dsdb: Add tests for modifying > objectClass, userAccountControl and sAMAccountName > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14889 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > selftest/knownfail.d/uac_mod_lock | 46 ++++++ > .../dsdb/tests/python/user_account_control.py | 150 ++++++++++++++++++ > 2 files changed, 196 insertions(+) > create mode 100644 selftest/knownfail.d/uac_mod_lock > >diff --git a/selftest/knownfail.d/uac_mod_lock b/selftest/knownfail.d/uac_mod_lock >new file mode 100644 >index 000000000000..6f45fa505546 >--- /dev/null >+++ b/selftest/knownfail.d/uac_mod_lock >@@ -0,0 +1,46 @@ >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_NORMAL_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_NORMAL_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_NORMAL_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_NORMAL_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_NORMAL_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_NORMAL_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_user_UF_NORMAL_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_user_UF_NORMAL_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_user_UF_NORMAL_ACCOUNT_to_computer_UF_WORKSTATION_TRUST_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_user_UF_NORMAL_ACCOUNT_to_computer_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_None_UF_NORMAL_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_None_UF_NORMAL_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_None_UF_NORMAL_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_None_UF_SERVER_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_None_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_computer_UF_SERVER_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_computer_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_None_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_computer_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_user_UF_NORMAL_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_keep_dollar >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_user_UF_NORMAL_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_remove_dollar >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index dabbac6373a5..1633998ada42 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -124,6 +124,46 @@ class UserAccountControlTests(samba.tests.TestCase): > account_type2, > how, > priv[0]) >+ >+ for objectclass in ["computer", "user"]: >+ account_types = [UF_NORMAL_ACCOUNT] >+ if objectclass == "computer": >+ account_types.append(UF_WORKSTATION_TRUST_ACCOUNT) >+ account_types.append(UF_SERVER_TRUST_ACCOUNT) >+ >+ for account_type in account_types: >+ account_type_str = ( >+ dsdb.user_account_control_flag_bit_to_string( >+ account_type)) >+ for account_type2 in [UF_NORMAL_ACCOUNT, >+ UF_WORKSTATION_TRUST_ACCOUNT, >+ UF_SERVER_TRUST_ACCOUNT, >+ UF_PARTIAL_SECRETS_ACCOUNT, >+ None]: >+ if account_type2 is None: >+ account_type2_str = None >+ else: >+ account_type2_str = ( >+ dsdb.user_account_control_flag_bit_to_string( >+ account_type2)) >+ >+ for objectclass2 in ["computer", "user", None]: >+ for name2 in [("oc_uac_lock", "remove_dollar"), >+ (None, "keep_dollar")]: >+ test_name = (f"{priv[1]}_{objectclass}_" >+ f"{account_type_str}_to_" >+ f"{objectclass2}_" >+ f"{account_type2_str}_" >+ f"{name2[1]}") >+ cls.generate_dynamic_test("test_mod_lock", >+ test_name, >+ objectclass, >+ objectclass2, >+ account_type, >+ account_type2, >+ name2[0], >+ priv[0]) >+ > for account_type in [UF_NORMAL_ACCOUNT, > UF_WORKSTATION_TRUST_ACCOUNT, > UF_SERVER_TRUST_ACCOUNT]: >@@ -968,6 +1008,116 @@ class UserAccountControlTests(samba.tests.TestCase): > > self.assertEqual(enum, 0) > >+ def _test_mod_lock_with_args(self, >+ objectclass, >+ objectclass2, >+ account_type, >+ account_type2, >+ name2, >+ priv): >+ name = "oc_uac_lock$" >+ >+ dn = "CN=%s,%s" % (name, self.OU) >+ msg_dict = { >+ "dn": dn, >+ "objectclass": objectclass, >+ "samAccountName": name, >+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)} >+ >+ account_type_str = dsdb.user_account_control_flag_bit_to_string( >+ account_type) >+ >+ print(f"Adding account {name} as {account_type_str} " >+ f"with objectclass {objectclass}") >+ >+ # Create the object as admin >+ self.admin_samdb.add(msg_dict) >+ >+ if priv: >+ samdb = self.admin_samdb >+ else: >+ samdb = self.samdb >+ >+ user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) >+ >+ # We want to test what the underlying rules for non-admins regardless >+ # of security descriptors are, so set this very, dangerously, broadly >+ mod = f"(OA;;WP;;;{user_sid})" >+ >+ self.sd_utils.dacl_add_ace(dn, mod) >+ >+ msg = "Modifying account" >+ if name2 is not None: >+ msg += f" to {name2}" >+ if account_type2 is not None: >+ account_type2_str = dsdb.user_account_control_flag_bit_to_string( >+ account_type2) >+ msg += f" as {account_type2_str}" >+ else: >+ account_type2_str = None >+ if objectclass2 is not None: >+ msg += f" with objectClass {objectclass2}" >+ print(msg) >+ >+ msg = ldb.Message(ldb.Dn(samdb, dn)) >+ if objectclass2 is not None: >+ msg["objectClass"] = ldb.MessageElement(objectclass2, >+ ldb.FLAG_MOD_REPLACE, >+ "objectClass") >+ if name2 is not None: >+ msg["sAMAccountName"] = ldb.MessageElement(name2, >+ ldb.FLAG_MOD_REPLACE, >+ "sAMAccountName") >+ if account_type2 is not None: >+ msg["userAccountControl"] = ldb.MessageElement( >+ str(account_type2 | UF_PASSWD_NOTREQD), >+ ldb.FLAG_MOD_REPLACE, >+ "userAccountControl") >+ enum = ldb.SUCCESS >+ try: >+ samdb.modify(msg) >+ except ldb.LdbError as e: >+ enum, _ = e.args >+ >+ # Setting userAccountControl to be an RODC is not allowed. >+ if account_type2 == UF_PARTIAL_SECRETS_ACCOUNT: >+ self.assertEqual(enum, ldb.ERR_OTHER) >+ return >+ >+ # Unprivileged users cannot change userAccountControl. The exception is >+ # changing a non-normal account to UF_WORKSTATION_TRUST_ACCOUNT, which >+ # is allowed. >+ if (not priv >+ and account_type2 is not None >+ and account_type != account_type2 >+ and (account_type == UF_NORMAL_ACCOUNT >+ or account_type2 != UF_WORKSTATION_TRUST_ACCOUNT)): >+ self.assertIn(enum, [ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ ldb.ERR_OBJECT_CLASS_VIOLATION]) >+ return >+ >+ # A non-computer account cannot have UF_SERVER_TRUST_ACCOUNT. >+ if objectclass == "user" and account_type2 == UF_SERVER_TRUST_ACCOUNT: >+ self.assertIn(enum, [ldb.ERR_UNWILLING_TO_PERFORM, >+ ldb.ERR_OBJECT_CLASS_VIOLATION]) >+ return >+ >+ # The objectClass is not allowed to change. >+ if objectclass2 is not None and objectclass != objectclass2: >+ self.assertIn(enum, [ldb.ERR_OBJECT_CLASS_VIOLATION, >+ ldb.ERR_UNWILLING_TO_PERFORM]) >+ return >+ >+ # Unprivileged users cannot remove the trailing dollar from a computer >+ # account. >+ if not priv and objectclass == "computer" and ( >+ name2 is not None and name2[-1] != "$"): >+ self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM) >+ return >+ >+ self.assertEqual(enum, 0) >+ return >+ > def _test_objectclass_uac_mod_lock_with_args(self, > account_type, > account_type2, >-- >2.25.1 > > >From 2950f7ff856be3343801f8aa1c302e406f58be3f Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Fri, 22 Oct 2021 16:07:46 +1300 >Subject: [PATCH 084/262] CVE-2020-25722 dsdb: Prohibit mismatch between UF_ > account types and objectclass. > >There are a lot of knownfail entries added with this commit. These >all need to be addressed and removed in subsequent commits which >will restructure the tests to pass within this new reality. > >The restriction is not applied to users with administrator rights, >as this breaks a lot of tests and provides no security benefit. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/priv_attr | 6 - > selftest/knownfail.d/uac_mod_lock | 6 - > selftest/knownfail.d/uac_objectclass_restrict | 35 ++-- > source4/dsdb/samdb/ldb_modules/samldb.c | 153 ++++++++++++++---- > 4 files changed, 145 insertions(+), 55 deletions(-) > >diff --git a/selftest/knownfail.d/priv_attr b/selftest/knownfail.d/priv_attr >index 4b85a8690892..e0d6104cec9c 100644 >--- a/selftest/knownfail.d/priv_attr >+++ b/selftest/knownfail.d/priv_attr >@@ -6,9 +6,3 @@ samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sid > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_WP_user > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_default_computer > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_default_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-RODC_add_CC_WP_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-RODC_add_CC_default_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-computer_add_CC_WP_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-computer_add_CC_default_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-computer_add_CC_WP_user >-samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-computer_add_CC_default_user >diff --git a/selftest/knownfail.d/uac_mod_lock b/selftest/knownfail.d/uac_mod_lock >index 6f45fa505546..a84a236c355b 100644 >--- a/selftest/knownfail.d/uac_mod_lock >+++ b/selftest/knownfail.d/uac_mod_lock >@@ -24,16 +24,10 @@ > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_keep_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_None_UF_NORMAL_ACCOUNT_keep_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_None_UF_NORMAL_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_None_UF_SERVER_TRUST_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_None_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_keep_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_computer_UF_SERVER_TRUST_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_computer_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_keep_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_keep_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_keep_dollar >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index bb0787c1a48b..040c4eb219d7 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -10,6 +10,16 @@ > ^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_isCriticalSystemObject\(ad_dc_default\) > ^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_userAccountControl\(ad_dc_default\) > ^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_users_groups\(ad_dc_default\) >+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-DC_add_CC_WP_user\(ad_dc_default\) >+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-DC_add_CC_default_user\(ad_dc_default\) >+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_WP_computer\(ad_dc_default\) >+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_default_computer\(ad_dc_default\) >+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_mod-del-add_CC_default_computer\(ad_dc_default\) >+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_mod-replace_CC_default_computer\(ad_dc_default\) >+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-user_add_CC_WP_computer\(ad_dc_default\) >+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-user_add_CC_default_computer\(ad_dc_default\) >+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-user_mod-del-add_CC_default_computer\(ad_dc_default\) >+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-user_mod-replace_CC_default_computer\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_add_computer_sd_cc\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_admin_mod_uac\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_computer_cc\(ad_dc_default\) >@@ -17,18 +27,6 @@ > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_user_replace\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_SERVER_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_NORMAL_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_dollar_lock_UF_NORMAL_ACCOUNT_computer_cc_plain\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_dollar_lock_UF_NORMAL_ACCOUNT_computer_cc_withdollar\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_dollar_lock_UF_SERVER_TRUST_ACCOUNT_user_cc_plain\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_dollar_lock_UF_SERVER_TRUST_ACCOUNT_user_cc_withdollar\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_WORKSTATION_TRUST_ACCOUNT_deladd_wp\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_WORKSTATION_TRUST_ACCOUNT_replace_wp\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_SERVER_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_deladd_wp\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_SERVER_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_replace_wp\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_deladd_wp\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_UF_NORMAL_ACCOUNT_replace_wp\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x10000000\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x20000000\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x40000000\(ad_dc_default\) >@@ -54,3 +52,16 @@ > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_SMARTCARD_REQUIRED\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_USE_AES_KEYS\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_USE_DES_KEY_ONLY\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_NORMAL_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_SERVER_TRUST_ACCOUNT_deladd_priv\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_SERVER_TRUST_ACCOUNT_deladd_wp\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_SERVER_TRUST_ACCOUNT_replace_priv\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_SERVER_TRUST_ACCOUNT_replace_wp\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_INTERDOMAIN_TRUST_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_NORMAL_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_NORMAL_ACCOUNT_UF_PASSWD_NOTREQD\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_INTERDOMAIN_TRUST_ACCOUNT\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_TRUSTED_FOR_DELEGATION\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION\(ad_dc_default\) >diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c >index 8df86f29883b..15459abcbca0 100644 >--- a/source4/dsdb/samdb/ldb_modules/samldb.c >+++ b/source4/dsdb/samdb/ldb_modules/samldb.c >@@ -1365,7 +1365,8 @@ static int samldb_check_user_account_control_rules(struct samldb_ctx *ac, > struct dom_sid *sid, > uint32_t req_uac, > uint32_t user_account_control, >- uint32_t user_account_control_old); >+ uint32_t user_account_control_old, >+ bool is_computer_objectclass); > > /* > * "Objectclass" trigger (MS-SAMR 3.1.1.8.1) >@@ -1484,21 +1485,12 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) > ret = samldb_check_user_account_control_rules(ac, NULL, > raw_uac, > user_account_control, >- 0); >+ 0, >+ is_computer_objectclass); > if (ret != LDB_SUCCESS) { > return ret; > } > >- /* Workstation and (read-only) DC objects do need objectclass "computer" */ >- if ((samdb_find_attribute(ldb, ac->msg, >- "objectclass", "computer") == NULL) && >- (user_account_control & >- (UF_SERVER_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT))) { >- ldb_set_errstring(ldb, >- "samldb: Requested account type does need objectclass 'computer'!"); >- return LDB_ERR_OBJECT_CLASS_VIOLATION; >- } >- > /* add "sAMAccountType" attribute */ > ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL); > if (ret != LDB_SUCCESS) { >@@ -1993,6 +1985,106 @@ static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac, > return ret; > } > >+/* >+ * It would be best if these rules apply, always, but for now they >+ * apply only to non-admins >+ */ >+static int samldb_check_user_account_control_objectclass_invariants( >+ struct samldb_ctx *ac, >+ uint32_t user_account_control, >+ uint32_t user_account_control_old, >+ bool is_computer_objectclass) >+{ >+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); >+ >+ uint32_t old_ufa = user_account_control_old & UF_ACCOUNT_TYPE_MASK; >+ uint32_t new_ufa = user_account_control & UF_ACCOUNT_TYPE_MASK; >+ >+ uint32_t old_rodc = user_account_control_old & UF_PARTIAL_SECRETS_ACCOUNT; >+ uint32_t new_rodc = user_account_control & UF_PARTIAL_SECRETS_ACCOUNT; >+ >+ bool is_admin; >+ struct security_token *user_token >+ = acl_user_token(ac->module); >+ if (user_token == NULL) { >+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; >+ } >+ >+ is_admin >+ = security_token_has_builtin_administrators(user_token); >+ >+ >+ /* >+ * We want to allow changes to (eg) disable an account >+ * that was created wrong, only checking the >+ * objectclass if the account type changes. >+ */ >+ if (old_ufa == new_ufa && old_rodc == new_rodc) { >+ return LDB_SUCCESS; >+ } >+ >+ switch (new_ufa) { >+ case UF_NORMAL_ACCOUNT: >+ if (is_computer_objectclass && !is_admin) { >+ ldb_asprintf_errstring(ldb, >+ "%08X: samldb: UF_NORMAL_ACCOUNT " >+ "requires objectclass 'user' not 'computer'!", >+ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); >+ return LDB_ERR_OBJECT_CLASS_VIOLATION; >+ } >+ break; >+ >+ case UF_INTERDOMAIN_TRUST_ACCOUNT: >+ if (is_computer_objectclass) { >+ ldb_asprintf_errstring(ldb, >+ "%08X: samldb: UF_INTERDOMAIN_TRUST_ACCOUNT " >+ "requires objectclass 'user' not 'computer'!", >+ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); >+ return LDB_ERR_OBJECT_CLASS_VIOLATION; >+ } >+ break; >+ >+ case UF_WORKSTATION_TRUST_ACCOUNT: >+ if (!is_computer_objectclass) { >+ /* >+ * Modify of a user account account into a >+ * workstation without objectclass computer >+ * as an admin is still permitted, but not >+ * to make an RODC >+ */ >+ if (is_admin >+ && ac->req->operation == LDB_MODIFY >+ && new_rodc == 0) { >+ break; >+ } >+ ldb_asprintf_errstring(ldb, >+ "%08X: samldb: UF_WORKSTATION_TRUST_ACCOUNT " >+ "requires objectclass 'computer'!", >+ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); >+ return LDB_ERR_OBJECT_CLASS_VIOLATION; >+ } >+ break; >+ >+ case UF_SERVER_TRUST_ACCOUNT: >+ if (!is_computer_objectclass) { >+ ldb_asprintf_errstring(ldb, >+ "%08X: samldb: UF_SERVER_TRUST_ACCOUNT " >+ "requires objectclass 'computer'!", >+ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); >+ return LDB_ERR_OBJECT_CLASS_VIOLATION; >+ } >+ break; >+ >+ default: >+ ldb_asprintf_errstring(ldb, >+ "%08X: samldb: invalid userAccountControl[0x%08X]", >+ W_ERROR_V(WERR_INVALID_PARAMETER), >+ user_account_control); >+ return LDB_ERR_OTHER; >+ } >+ return LDB_SUCCESS; >+} >+ > static int samldb_get_domain_secdesc(struct samldb_ctx *ac, > struct security_descriptor **domain_sd) > { >@@ -2191,7 +2283,8 @@ static int samldb_check_user_account_control_rules(struct samldb_ctx *ac, > struct dom_sid *sid, > uint32_t req_uac, > uint32_t user_account_control, >- uint32_t user_account_control_old) >+ uint32_t user_account_control_old, >+ bool is_computer_objectclass) > { > int ret; > struct dsdb_control_password_user_account_control *uac = NULL; >@@ -2200,6 +2293,14 @@ static int samldb_check_user_account_control_rules(struct samldb_ctx *ac, > if (ret != LDB_SUCCESS) { > return ret; > } >+ ret = samldb_check_user_account_control_objectclass_invariants(ac, >+ user_account_control, >+ user_account_control_old, >+ is_computer_objectclass); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ > ret = samldb_check_user_account_control_acl(ac, sid, user_account_control, user_account_control_old); > if (ret != LDB_SUCCESS) { > return ret; >@@ -2261,7 +2362,7 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) > "objectSid", > NULL > }; >- bool is_computer = false; >+ bool is_computer_objectclass = false; > bool old_is_critical = false; > bool new_is_critical = false; > >@@ -2316,7 +2417,10 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) > "lockoutTime", 0); > old_is_critical = ldb_msg_find_attr_as_bool(res->msgs[0], > "isCriticalSystemObject", 0); >- /* When we do not have objectclass "computer" we cannot switch to a (read-only) DC */ >+ /* >+ * When we do not have objectclass "computer" we cannot >+ * switch to a workstation or (RO)DC >+ */ > el = ldb_msg_find_element(res->msgs[0], "objectClass"); > if (el == NULL) { > return ldb_operr(ldb); >@@ -2324,7 +2428,7 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) > computer_val = data_blob_string_const("computer"); > val = ldb_msg_find_val(el, &computer_val); > if (val != NULL) { >- is_computer = true; >+ is_computer_objectclass = true; > } > > old_ufa = old_uac & UF_ACCOUNT_TYPE_MASK; >@@ -2349,7 +2453,8 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) > ret = samldb_check_user_account_control_rules(ac, sid, > raw_uac, > new_uac, >- old_uac); >+ old_uac, >+ is_computer_objectclass); > if (ret != LDB_SUCCESS) { > return ret; > } >@@ -2371,25 +2476,11 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) > case UF_WORKSTATION_TRUST_ACCOUNT: > new_is_critical = false; > if (new_uac & UF_PARTIAL_SECRETS_ACCOUNT) { >- if (!is_computer) { >- ldb_asprintf_errstring(ldb, >- "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT " >- "requires objectclass 'computer'!", >- W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); >- return LDB_ERR_UNWILLING_TO_PERFORM; >- } > new_is_critical = true; > } > break; > > case UF_SERVER_TRUST_ACCOUNT: >- if (!is_computer) { >- ldb_asprintf_errstring(ldb, >- "%08X: samldb: UF_SERVER_TRUST_ACCOUNT " >- "requires objectclass 'computer'!", >- W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); >- return LDB_ERR_UNWILLING_TO_PERFORM; >- } > new_is_critical = true; > break; > >-- >2.25.1 > > >From c1bfef7b015d66d502d7fc4311522e451836082e Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 28 Oct 2021 14:47:30 +1300 >Subject: [PATCH 085/262] CVE-2020-25722 selftest/priv_attrs: Mention that > these knownfails are OK (for now) > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14775 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/priv_attr | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/selftest/knownfail.d/priv_attr b/selftest/knownfail.d/priv_attr >index e0d6104cec9c..5d3713eafe39 100644 >--- a/selftest/knownfail.d/priv_attr >+++ b/selftest/knownfail.d/priv_attr >@@ -1,3 +1,8 @@ >+# These priv_attrs tests would be good to fix, but are not fatal as >+# the testsuite is run twice, once with and once without STRICT_CHECKING=0 >+# >+# These knownfails show that we can improve our error matching against Windows. >+# > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_computer > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_user > samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_computer >-- >2.25.1 > > >From c4cc270f34adf44cb0c1a1c0b47fe7b9db58a015 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Fri, 22 Oct 2021 16:18:51 +1300 >Subject: [PATCH 086/262] CVE-2020-25722 selftest: Adapt selftest to > restriction on swapping account types > >This makes many of our tests pass again. We do not pass against Windows 2019 on all >as this does not have this restriction at this time. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_objectclass_restrict | 29 +--------- > .../dsdb/tests/python/user_account_control.py | 54 +++++++++++++------ > 2 files changed, 39 insertions(+), 44 deletions(-) > >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index 040c4eb219d7..32d8a99f950c 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -27,31 +27,7 @@ > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_user_replace\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_SERVER_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x10000000\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x20000000\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x40000000\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x80000000\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00000004\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00000400\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00004000\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00008000\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_ACCOUNTDISABLE\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_DONT_EXPIRE_PASSWD\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_DONT_REQUIRE_PREAUTH\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_HOMEDIR_REQUIRED\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_LOCKOUT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_MNS_LOGON_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_NORMAL_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_NOT_DELEGATED\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_NO_AUTH_DATA_REQUIRED\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_PASSWD_CANT_CHANGE\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_PASSWD_NOTREQD\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_PASSWORD_EXPIRED\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_SCRIPT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_SMARTCARD_REQUIRED\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_USE_AES_KEYS\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_USE_DES_KEY_ONLY\(ad_dc_default\) >+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_SERVER_TRUST_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_NORMAL_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) >@@ -62,6 +38,3 @@ > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_INTERDOMAIN_TRUST_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_NORMAL_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_NORMAL_ACCOUNT_UF_PASSWD_NOTREQD\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_INTERDOMAIN_TRUST_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_TRUSTED_FOR_DELEGATION\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION\(ad_dc_default\) >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index 1633998ada42..7a7cfd40b72e 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -219,6 +219,23 @@ class UserAccountControlTests(samba.tests.TestCase): > print("Adding computer account %s" % computername) > samdb.add(msg) > >+ def add_user_ldap(self, username, others=None, samdb=None): >+ if samdb is None: >+ samdb = self.samdb >+ dn = "CN=%s,%s" % (username, self.OU) >+ samaccountname = "%s" % username >+ msg_dict = { >+ "dn": dn, >+ "objectclass": "user"} >+ if others is not None: >+ msg_dict = dict(list(msg_dict.items()) + list(others.items())) >+ >+ msg = ldb.Message.from_dict(self.samdb, msg_dict) >+ msg["sAMAccountName"] = samaccountname >+ >+ print("Adding user account %s" % username) >+ samdb.add(msg) >+ > def get_creds(self, target_username, target_password): > creds_tmp = Credentials() > creds_tmp.set_username(target_username) >@@ -532,17 +549,21 @@ class UserAccountControlTests(samba.tests.TestCase): > > def _test_uac_bits_set_with_args(self, bit, bit_str): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) >- mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) >+ # Allow the creation of any children and write to any >+ # attributes (this is not a test of ACLs, this is a test of >+ # non-ACL userAccountControl rules >+ mod = f"(OA;CI;WP;;;{user_sid})(OA;;CC;;;{user_sid})" > > old_sd = self.sd_utils.read_sd_on_dn(self.OU) > > self.sd_utils.dacl_add_ace(self.OU, mod) > >+ # We want to start with UF_NORMAL_ACCOUNT, so we make a user > computername = self.computernames[0] >- self.add_computer_ldap(computername) >+ self.add_user_ldap(computername) > > res = self.admin_samdb.search("%s" % self.base_dn, >- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername, >+ expression="(&(objectClass=user)(cn=%s))" % computername, > scope=SCOPE_SUBTREE, > attrs=[]) > >@@ -588,7 +609,11 @@ class UserAccountControlTests(samba.tests.TestCase): > > def _test_uac_bits_unrelated_modify_with_args(self, account_type): > user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn) >- mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid) >+ >+ # Allow the creation of any children and write to any >+ # attributes (this is not a test of ACLs, this is a test of >+ # non-ACL userAccountControl rules >+ mod = f"(OA;CI;WP;;;{user_sid})(OA;;CC;;;{user_sid})" > > old_sd = self.sd_utils.read_sd_on_dn(self.OU) > >@@ -596,22 +621,19 @@ class UserAccountControlTests(samba.tests.TestCase): > > computername = self.computernames[0] > if account_type == UF_WORKSTATION_TRUST_ACCOUNT: >- self.add_computer_ldap(computername, others={"userAccountControl": [str(account_type)]}) >- else: > self.add_computer_ldap(computername) >+ else: >+ self.add_user_ldap(computername) > > res = self.admin_samdb.search(self.OU, >- expression=f"(cn={computername})", >+ expression=f"(&(objectclass=user)(cn={computername}))", > scope=SCOPE_SUBTREE, > attrs=["userAccountControl"]) > self.assertEqual(len(res), 1) > > orig_uac = int(res[0]["userAccountControl"][0]) >- if account_type == UF_WORKSTATION_TRUST_ACCOUNT: >- self.assertEqual(orig_uac, account_type) >- else: >- self.assertEqual(orig_uac & UF_NORMAL_ACCOUNT, >- account_type) >+ self.assertEqual(orig_uac & account_type, >+ account_type) > > m = ldb.Message() > m.dn = res[0].dn >@@ -649,7 +671,7 @@ class UserAccountControlTests(samba.tests.TestCase): > self.fail(f"got {estr} resetting userAccountControl to initial value {orig_uac:#08x}") > > res = self.admin_samdb.search("%s" % self.base_dn, >- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername, >+ expression="(&(objectClass=user)(cn=%s))" % computername, > scope=SCOPE_SUBTREE, > attrs=["userAccountControl"]) > >@@ -696,7 +718,7 @@ class UserAccountControlTests(samba.tests.TestCase): > self.fail("Unable to set userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr)) > > res = self.admin_samdb.search("%s" % self.base_dn, >- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername, >+ expression="(&(objectClass=user)(cn=%s))" % computername, > scope=SCOPE_SUBTREE, > attrs=["userAccountControl"]) > >@@ -726,7 +748,7 @@ class UserAccountControlTests(samba.tests.TestCase): > self.fail("Unable to set userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr)) > > res = self.admin_samdb.search("%s" % self.base_dn, >- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername, >+ expression="(&(objectClass=user)(cn=%s))" % computername, > scope=SCOPE_SUBTREE, > attrs=["userAccountControl"]) > >@@ -767,7 +789,7 @@ class UserAccountControlTests(samba.tests.TestCase): > self.fail("Unexpectedly unable to remove userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr)) > > res = self.admin_samdb.search("%s" % self.base_dn, >- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername, >+ expression="(&(objectClass=user)(cn=%s))" % computername, > scope=SCOPE_SUBTREE, > attrs=["userAccountControl"]) > >-- >2.25.1 > > >From 34b5f7287085c81b07c8591c631e09489e323cea Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Wed, 22 Sep 2021 11:28:05 +1200 >Subject: [PATCH 087/262] CVE-2020-25722 dsdb: samldb_objectclass_trigger() is > only called on ADD, so remove indentation > >This makes the code less indented and simpler to understand. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > source4/dsdb/samdb/ldb_modules/samldb.c | 187 ++++++++++++------------ > 1 file changed, 93 insertions(+), 94 deletions(-) > >diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c >index 15459abcbca0..e7962cdde422 100644 >--- a/source4/dsdb/samdb/ldb_modules/samldb.c >+++ b/source4/dsdb/samdb/ldb_modules/samldb.c >@@ -1371,9 +1371,9 @@ static int samldb_check_user_account_control_rules(struct samldb_ctx *ac, > /* > * "Objectclass" trigger (MS-SAMR 3.1.1.8.1) > * >- * Has to be invoked on "add" and "modify" operations on "user", "computer" and >+ * Has to be invoked on "add" operations on "user", "computer" and > * "group" objects. >- * ac->msg contains the "add"/"modify" message >+ * ac->msg contains the "add" > * ac->type contains the object type (main objectclass) > */ > static int samldb_objectclass_trigger(struct samldb_ctx *ac) >@@ -1414,6 +1414,8 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) > > switch(ac->type) { > case SAMLDB_TYPE_USER: { >+ uint32_t raw_uac; >+ uint32_t user_account_control; > bool is_computer_objectclass; > bool uac_generated = false, uac_add_flags = false; > uint32_t default_user_account_control = UF_NORMAL_ACCOUNT; >@@ -1437,7 +1439,7 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) > /* On add operations we might need to generate a > * "userAccountControl" (if it isn't specified). */ > el = ldb_msg_find_element(ac->msg, "userAccountControl"); >- if ((el == NULL) && (ac->req->operation == LDB_ADD)) { >+ if (el == NULL) { > ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg, > "userAccountControl", > default_user_account_control); >@@ -1449,114 +1451,111 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) > } > > el = ldb_msg_find_element(ac->msg, "userAccountControl"); >- if (el != NULL) { >- uint32_t raw_uac; >- uint32_t user_account_control; >- /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */ >- user_account_control = ldb_msg_find_attr_as_uint(ac->msg, >- "userAccountControl", >- 0); >- raw_uac = user_account_control; >- /* >- * "userAccountControl" = 0 or missing one of >- * the types means "UF_NORMAL_ACCOUNT" >- * or "UF_WORKSTATION_TRUST_ACCOUNT" (if a computer). >- * See MS-SAMR 3.1.1.8.10 point 8 >- */ >- if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) { >- user_account_control >- = default_user_account_control >- | user_account_control; >- uac_generated = true; >- } >+ SMB_ASSERT(el != NULL); > >- /* >- * As per MS-SAMR 3.1.1.8.10 these flags have not to be set >- */ >- if ((user_account_control & UF_LOCKOUT) != 0) { >- user_account_control &= ~UF_LOCKOUT; >- uac_generated = true; >- } >- if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) { >- user_account_control &= ~UF_PASSWORD_EXPIRED; >- uac_generated = true; >- } >+ /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */ >+ user_account_control = ldb_msg_find_attr_as_uint(ac->msg, >+ "userAccountControl", >+ 0); >+ raw_uac = user_account_control; >+ /* >+ * "userAccountControl" = 0 or missing one of >+ * the types means "UF_NORMAL_ACCOUNT" >+ * or "UF_WORKSTATION_TRUST_ACCOUNT" (if a computer). >+ * See MS-SAMR 3.1.1.8.10 point 8 >+ */ >+ if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) { >+ user_account_control >+ = default_user_account_control >+ | user_account_control; >+ uac_generated = true; >+ } >+ >+ /* >+ * As per MS-SAMR 3.1.1.8.10 these flags have not to be set >+ */ >+ if ((user_account_control & UF_LOCKOUT) != 0) { >+ user_account_control &= ~UF_LOCKOUT; >+ uac_generated = true; >+ } >+ if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) { >+ user_account_control &= ~UF_PASSWORD_EXPIRED; >+ uac_generated = true; >+ } > >- ret = samldb_check_user_account_control_rules(ac, NULL, >- raw_uac, >- user_account_control, >- 0, >- is_computer_objectclass); >+ ret = samldb_check_user_account_control_rules(ac, NULL, >+ raw_uac, >+ user_account_control, >+ 0, >+ is_computer_objectclass); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ >+ /* add "sAMAccountType" attribute */ >+ ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ >+ /* "isCriticalSystemObject" might be set */ >+ if (user_account_control & >+ (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) { >+ ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject", >+ "TRUE"); > if (ret != LDB_SUCCESS) { > return ret; > } >- >- /* add "sAMAccountType" attribute */ >- ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL); >+ el2 = ldb_msg_find_element(ac->msg, >+ "isCriticalSystemObject"); >+ el2->flags = LDB_FLAG_MOD_REPLACE; >+ } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) { >+ ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject", >+ "FALSE"); > if (ret != LDB_SUCCESS) { > return ret; > } >+ el2 = ldb_msg_find_element(ac->msg, >+ "isCriticalSystemObject"); >+ el2->flags = LDB_FLAG_MOD_REPLACE; >+ } > >- /* "isCriticalSystemObject" might be set */ >- if (user_account_control & >- (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) { >- ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject", >- "TRUE"); >- if (ret != LDB_SUCCESS) { >- return ret; >- } >- el2 = ldb_msg_find_element(ac->msg, >- "isCriticalSystemObject"); >- el2->flags = LDB_FLAG_MOD_REPLACE; >- } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) { >- ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject", >- "FALSE"); >- if (ret != LDB_SUCCESS) { >- return ret; >- } >- el2 = ldb_msg_find_element(ac->msg, >- "isCriticalSystemObject"); >- el2->flags = LDB_FLAG_MOD_REPLACE; >- } >- >- /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */ >- if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) { >- uint32_t rid; >+ /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */ >+ if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) { >+ uint32_t rid; > >- ret = dsdb_user_obj_set_primary_group_id(ldb, ac->msg, user_account_control, &rid); >+ ret = dsdb_user_obj_set_primary_group_id(ldb, ac->msg, user_account_control, &rid); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ /* >+ * Older AD deployments don't know about the >+ * RODC group >+ */ >+ if (rid == DOMAIN_RID_READONLY_DCS) { >+ ret = samldb_prim_group_tester(ac, rid); > if (ret != LDB_SUCCESS) { > return ret; > } >- /* >- * Older AD deployments don't know about the >- * RODC group >- */ >- if (rid == DOMAIN_RID_READONLY_DCS) { >- ret = samldb_prim_group_tester(ac, rid); >- if (ret != LDB_SUCCESS) { >- return ret; >- } >- } > } >+ } > >- /* Step 1.5: Add additional flags when needed */ >- /* Obviously this is done when the "userAccountControl" >- * has been generated here (tested against Windows >- * Server) */ >- if (uac_generated) { >- if (uac_add_flags) { >- user_account_control |= UF_ACCOUNTDISABLE; >- user_account_control |= UF_PASSWD_NOTREQD; >- } >- >- ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg, >- "userAccountControl", >- user_account_control); >- if (ret != LDB_SUCCESS) { >- return ret; >- } >+ /* Step 1.5: Add additional flags when needed */ >+ /* Obviously this is done when the "userAccountControl" >+ * has been generated here (tested against Windows >+ * Server) */ >+ if (uac_generated) { >+ if (uac_add_flags) { >+ user_account_control |= UF_ACCOUNTDISABLE; >+ user_account_control |= UF_PASSWD_NOTREQD; > } > >+ ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg, >+ "userAccountControl", >+ user_account_control); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } > } > break; > } >-- >2.25.1 > > >From 0edcd5f21be4a4165dadce331ddb359dbc8d5f9e Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Wed, 22 Sep 2021 11:29:02 +1200 >Subject: [PATCH 088/262] CVE-2020-25722 dsdb: Add restrictions on computer > accounts without a trailing $ > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_dollar_lock | 1 - > selftest/knownfail.d/uac_mod_lock | 12 -- > source4/dsdb/samdb/ldb_modules/samldb.c | 171 +++++++++++++++++++++--- > 3 files changed, 154 insertions(+), 30 deletions(-) > delete mode 100644 selftest/knownfail.d/uac_dollar_lock > >diff --git a/selftest/knownfail.d/uac_dollar_lock b/selftest/knownfail.d/uac_dollar_lock >deleted file mode 100644 >index 8c70c859fa4a..000000000000 >--- a/selftest/knownfail.d/uac_dollar_lock >+++ /dev/null >@@ -1 +0,0 @@ >-^samba4.user_account_control.python\(.*\).__main__.UserAccountControlTests.test_objectclass_uac_dollar_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_cc_plain >\ No newline at end of file >diff --git a/selftest/knownfail.d/uac_mod_lock b/selftest/knownfail.d/uac_mod_lock >index a84a236c355b..068a47c6e616 100644 >--- a/selftest/knownfail.d/uac_mod_lock >+++ b/selftest/knownfail.d/uac_mod_lock >@@ -20,21 +20,9 @@ > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_user_UF_NORMAL_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_user_UF_NORMAL_ACCOUNT_to_computer_UF_WORKSTATION_TRUST_ACCOUNT_keep_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_priv_user_UF_NORMAL_ACCOUNT_to_computer_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_None_UF_NORMAL_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_keep_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_NORMAL_ACCOUNT_to_user_UF_NORMAL_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_None_UF_SERVER_TRUST_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_None_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_computer_UF_SERVER_TRUST_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_computer_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_keep_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_SERVER_TRUST_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_keep_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_SERVER_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_None_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_computer_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_keep_dollar >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_computer_UF_WORKSTATION_TRUST_ACCOUNT_to_user_UF_WORKSTATION_TRUST_ACCOUNT_remove_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_user_UF_NORMAL_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_keep_dollar > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_lock_wp_user_UF_NORMAL_ACCOUNT_to_computer_UF_NORMAL_ACCOUNT_remove_dollar >diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c >index e7962cdde422..aeef663d2f0c 100644 >--- a/source4/dsdb/samdb/ldb_modules/samldb.c >+++ b/source4/dsdb/samdb/ldb_modules/samldb.c >@@ -68,6 +68,13 @@ struct samldb_ctx { > /* used for add operations */ > enum samldb_add_type type; > >+ /* >+ * should we apply the need_trailing_dollar restriction to >+ * samAccountName >+ */ >+ >+ bool need_trailing_dollar; >+ > /* the resulting message */ > struct ldb_message *msg; > >@@ -232,12 +239,86 @@ static int samldb_unique_attr_check(struct samldb_ctx *ac, const char *attr, > > static int samldb_sam_accountname_valid_check(struct samldb_ctx *ac) > { >- int ret = samldb_unique_attr_check(ac, "samAccountName", NULL, >- ldb_get_default_basedn( >- ldb_module_get_ctx(ac->module))); >- if (ret == LDB_ERR_OBJECT_CLASS_VIOLATION) { >+ int ret = 0; >+ bool is_admin; >+ struct security_token *user_token = NULL; >+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); >+ struct ldb_message_element *el = dsdb_get_single_valued_attr(ac->msg, "samAccountName", >+ ac->req->operation); >+ if (el == NULL || el->num_values == 0) { >+ ldb_asprintf_errstring(ldb, >+ "%08X: samldb: 'samAccountName' can't be deleted/empty!", >+ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION)); >+ if (ac->req->operation == LDB_ADD) { >+ return LDB_ERR_CONSTRAINT_VIOLATION; >+ } else { >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ } >+ >+ ret = samldb_unique_attr_check(ac, "samAccountName", NULL, >+ ldb_get_default_basedn( >+ ldb_module_get_ctx(ac->module))); >+ >+ /* >+ * Error code munging to try and match what must be some quite >+ * strange code-paths in Windows >+ */ >+ if (ret == LDB_ERR_CONSTRAINT_VIOLATION >+ && ac->req->operation == LDB_MODIFY) { >+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; >+ } else if (ret == LDB_ERR_OBJECT_CLASS_VIOLATION) { > ret = LDB_ERR_CONSTRAINT_VIOLATION; > } >+ >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ >+ if (!ac->need_trailing_dollar) { >+ return LDB_SUCCESS; >+ } >+ >+ /* This does not permit a single $ */ >+ if (el->values[0].length < 2) { >+ ldb_asprintf_errstring(ldb, >+ "%08X: samldb: 'samAccountName' " >+ "can't just be one character!", >+ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ >+ user_token = acl_user_token(ac->module); >+ if (user_token == NULL) { >+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; >+ } >+ >+ is_admin >+ = security_token_has_builtin_administrators(user_token); >+ >+ if (is_admin) { >+ /* >+ * Administrators are allowed to select strange names. >+ * This is poor practice but not prevented. >+ */ >+ return false; >+ } >+ >+ if (el->values[0].data[el->values[0].length - 1] != '$') { >+ ldb_asprintf_errstring(ldb, >+ "%08X: samldb: 'samAccountName' " >+ "must have a trailing $!", >+ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ if (el->values[0].data[el->values[0].length - 2] == '$') { >+ ldb_asprintf_errstring(ldb, >+ "%08X: samldb: 'samAccountName' " >+ "must not have a double trailing $!", >+ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ > return ret; > } > >@@ -554,17 +635,31 @@ static int samldb_schema_add_handle_mapiid(struct samldb_ctx *ac) > } > > /* sAMAccountName handling */ >-static int samldb_generate_sAMAccountName(struct ldb_context *ldb, >+static int samldb_generate_sAMAccountName(struct samldb_ctx *ac, > struct ldb_message *msg) > { >+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); > char *name; > >- /* Format: $000000-000000000000 */ >+ /* >+ * This is currently a Samba-only behaviour, to add a trailing >+ * $ even for the generated accounts. >+ */ >+ >+ if (ac->need_trailing_dollar) { >+ /* Format: $000000-00000000000$ */ >+ name = talloc_asprintf(msg, "$%.6X-%.6X%.5X$", >+ (unsigned int)generate_random(), >+ (unsigned int)generate_random(), >+ (unsigned int)generate_random()); >+ } else { >+ /* Format: $000000-000000000000 */ > >- name = talloc_asprintf(msg, "$%.6X-%.6X%.6X", >- (unsigned int)generate_random(), >- (unsigned int)generate_random(), >- (unsigned int)generate_random()); >+ name = talloc_asprintf(msg, "$%.6X-%.6X%.6X", >+ (unsigned int)generate_random(), >+ (unsigned int)generate_random(), >+ (unsigned int)generate_random()); >+ } > if (name == NULL) { > return ldb_oom(ldb); > } >@@ -573,11 +668,10 @@ static int samldb_generate_sAMAccountName(struct ldb_context *ldb, > > static int samldb_check_sAMAccountName(struct samldb_ctx *ac) > { >- struct ldb_context *ldb = ldb_module_get_ctx(ac->module); > int ret; > > if (ldb_msg_find_element(ac->msg, "sAMAccountName") == NULL) { >- ret = samldb_generate_sAMAccountName(ldb, ac->msg); >+ ret = samldb_generate_sAMAccountName(ac, ac->msg); > if (ret != LDB_SUCCESS) { > return ret; > } >@@ -1492,6 +1586,20 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) > return ret; > } > >+ /* >+ * Require, for non-admin modifications, a trailing $ >+ * for either objectclass=computer or a trust account >+ * type in userAccountControl >+ */ >+ if ((user_account_control >+ & UF_TRUST_ACCOUNT_MASK) != 0) { >+ ac->need_trailing_dollar = true; >+ } >+ >+ if (is_computer_objectclass) { >+ ac->need_trailing_dollar = true; >+ } >+ > /* add "sAMAccountType" attribute */ > ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL); > if (ret != LDB_SUCCESS) { >@@ -4005,12 +4113,41 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) > > el = ldb_msg_find_element(ac->msg, "sAMAccountName"); > if (el != NULL) { >+ uint32_t user_account_control; >+ struct ldb_result *res = NULL; >+ const char * const attrs[] = { "userAccountControl", >+ "objectclass", >+ NULL }; >+ ret = dsdb_module_search_dn(ac->module, >+ ac, >+ &res, >+ ac->msg->dn, >+ attrs, >+ DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, >+ ac->req); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ >+ user_account_control >+ = ldb_msg_find_attr_as_uint(res->msgs[0], >+ "userAccountControl", >+ 0); >+ >+ if ((user_account_control >+ & UF_TRUST_ACCOUNT_MASK) != 0) { >+ ac->need_trailing_dollar = true; >+ >+ } else if (samdb_find_attribute(ldb, >+ res->msgs[0], >+ "objectclass", >+ "computer") >+ != NULL) { >+ ac->need_trailing_dollar = true; >+ } >+ > ret = samldb_sam_accountname_valid_check(ac); >- /* >- * Other errors are checked for elsewhere, we just >- * want to prevent duplicates >- */ >- if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { >+ if (ret != LDB_SUCCESS) { > return ret; > } > } >-- >2.25.1 > > >From bfd555f6f3da7678fe027eed0133eb832f60bd41 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 21 Oct 2021 11:57:22 +1300 >Subject: [PATCH 089/262] CVE-2020-25722 selftest: Adapt sam.py > test_isCriticalSystemObject to new UF_WORKSTATION_TRUST_ACCOUNT default > >Objects with objectclass computer now have UF_WORKSTATION_TRUST_ACCOUNT >by default and so this test must adapt. > >The changes to this test passes against Windows 2019 except for >the new behaviour around the UF_WORKSTATION_TRUST_ACCOUNT default. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > .../knownfail.d/sam-isCriticalSystemObject | 1 + > selftest/knownfail.d/uac_objectclass_restrict | 2 -- > source4/dsdb/tests/python/sam.py | 36 ++++++++++++++++++- > 3 files changed, 36 insertions(+), 3 deletions(-) > create mode 100644 selftest/knownfail.d/sam-isCriticalSystemObject > >diff --git a/selftest/knownfail.d/sam-isCriticalSystemObject b/selftest/knownfail.d/sam-isCriticalSystemObject >new file mode 100644 >index 000000000000..a6351a81907b >--- /dev/null >+++ b/selftest/knownfail.d/sam-isCriticalSystemObject >@@ -0,0 +1 @@ >+^samba4.sam.python\(.*\).__main__.SamTests.test_isCriticalSystemObject_user >\ No newline at end of file >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index 32d8a99f950c..d093c631bd37 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -3,11 +3,9 @@ > # > # All these tests need to be fixed and the entries here removed > >-^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_isCriticalSystemObject\(fl2008r2dc\) > ^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_userAccountControl\(fl2008r2dc\) > ^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_users_groups\(fl2008r2dc\) > ^samba4.ldap.python\(ad_dc_default\).__main__.BasicTests.test_all\(ad_dc_default\) >-^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_isCriticalSystemObject\(ad_dc_default\) > ^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_userAccountControl\(ad_dc_default\) > ^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_users_groups\(ad_dc_default\) > ^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-DC_add_CC_WP_user\(ad_dc_default\) >diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py >index 8220cf8b44f5..67e2f7b23c3e 100755 >--- a/source4/dsdb/tests/python/sam.py >+++ b/source4/dsdb/tests/python/sam.py >@@ -2926,6 +2926,39 @@ class SamTests(samba.tests.TestCase): > > delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) > >+ def test_isCriticalSystemObject_user(self): >+ """Test the isCriticalSystemObject behaviour""" >+ print("Testing isCriticalSystemObject behaviour\n") >+ >+ # Add tests (of a user) >+ >+ ldb.add({ >+ "dn": "cn=ldaptestuser,cn=users," + self.base_dn, >+ "objectclass": "user"}) >+ >+ res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn, >+ scope=SCOPE_BASE, >+ attrs=["isCriticalSystemObject"]) >+ self.assertTrue(len(res1) == 1) >+ self.assertTrue("isCriticalSystemObject" not in res1[0]) >+ >+ # Modification tests >+ m = Message() >+ >+ m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn) >+ m["userAccountControl"] = MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT), >+ FLAG_MOD_REPLACE, "userAccountControl") >+ ldb.modify(m) >+ >+ res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn, >+ scope=SCOPE_BASE, >+ attrs=["isCriticalSystemObject"]) >+ self.assertTrue(len(res1) == 1) >+ self.assertTrue("isCriticalSystemObject" in res1[0]) >+ self.assertEqual(str(res1[0]["isCriticalSystemObject"][0]), "FALSE") >+ >+ delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) >+ > def test_isCriticalSystemObject(self): > """Test the isCriticalSystemObject behaviour""" > print("Testing isCriticalSystemObject behaviour\n") >@@ -2940,7 +2973,8 @@ class SamTests(samba.tests.TestCase): > scope=SCOPE_BASE, > attrs=["isCriticalSystemObject"]) > self.assertTrue(len(res1) == 1) >- self.assertTrue("isCriticalSystemObject" not in res1[0]) >+ self.assertTrue("isCriticalSystemObject" in res1[0]) >+ self.assertEqual(str(res1[0]["isCriticalSystemObject"][0]), "FALSE") > > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) > >-- >2.25.1 > > >From f17578b36d11af6d935c074b3f066d561f95a9ec Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 21 Oct 2021 13:02:42 +1300 >Subject: [PATCH 090/262] CVE-2020-25722 samdb: Fill in isCriticalSystemObject > on any account type change > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/sam-isCriticalSystemObject | 1 - > source4/dsdb/samdb/ldb_modules/samldb.c | 10 ++++++++-- > 2 files changed, 8 insertions(+), 3 deletions(-) > delete mode 100644 selftest/knownfail.d/sam-isCriticalSystemObject > >diff --git a/selftest/knownfail.d/sam-isCriticalSystemObject b/selftest/knownfail.d/sam-isCriticalSystemObject >deleted file mode 100644 >index a6351a81907b..000000000000 >--- a/selftest/knownfail.d/sam-isCriticalSystemObject >+++ /dev/null >@@ -1 +0,0 @@ >-^samba4.sam.python\(.*\).__main__.SamTests.test_isCriticalSystemObject_user >\ No newline at end of file >diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c >index aeef663d2f0c..5352af1099f7 100644 >--- a/source4/dsdb/samdb/ldb_modules/samldb.c >+++ b/source4/dsdb/samdb/ldb_modules/samldb.c >@@ -2621,8 +2621,14 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) > el->flags = LDB_FLAG_MOD_REPLACE; > } > >- /* "isCriticalSystemObject" might be set/changed */ >- if (old_is_critical != new_is_critical) { >+ /* >+ * "isCriticalSystemObject" might be set/changed >+ * >+ * Even a change from UF_NORMAL_ACCOUNT (implicitly FALSE) to >+ * UF_WORKSTATION_TRUST_ACCOUNT (actually FALSE) triggers >+ * creating the attribute. >+ */ >+ if (old_is_critical != new_is_critical || old_atype != new_atype) { > ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject", > new_is_critical ? "TRUE": "FALSE"); > if (ret != LDB_SUCCESS) { >-- >2.25.1 > > >From 20accb9b4301200622187de287e5248eb1dab7cc Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 21 Oct 2021 14:03:05 +1300 >Subject: [PATCH 091/262] CVE-2020-25722 selftest: Split > test_userAccountControl into unit tests > >The parts that create and delete a single object can be >safely split out into an individual test. > >At this point the parts that fail against Windows 2019 are: > >error: __main__.SamTests.test_userAccountControl_computer_add_normal [ >_ldb.LdbError: (53, 'LDAP error 53 LDAP_UNWILLING_TO_PERFORM - <0000052D: SvcErr: DSID-031A1236, problem 5003 (WILL_NOT_PERFORM), data 0\n> <>') >error: __main__.SamTests.test_userAccountControl_computer_modify [ >_ldb.LdbError: (53, 'LDAP error 53 LDAP_UNWILLING_TO_PERFORM - <0000052D: SvcErr: DSID-031A1236, problem 5003 (WILL_NOT_PERFORM), data 0\n> <>') >error: __main__.SamTests.test_userAccountControl_user_add_0_uac [ >_ldb.LdbError: (53, 'LDAP error 53 LDAP_UNWILLING_TO_PERFORM - <0000052D: SvcErr: DSID-031A1236, problem 5003 (WILL_NOT_PERFORM), data 0\n> <>') >error: __main__.SamTests.test_userAccountControl_user_add_normal [ >_ldb.LdbError: (53, 'LDAP error 53 LDAP_UNWILLING_TO_PERFORM - <0000052D: SvcErr: DSID-031A1236, problem 5003 (WILL_NOT_PERFORM), data 0\n> <>') >error: __main__.SamTests.test_userAccountControl_user_modify [ >_ldb.LdbError: (53, 'LDAP error 53 LDAP_UNWILLING_TO_PERFORM - <0000052D: SvcErr: DSID-031A1236, problem 5003 (WILL_NOT_PERFORM), data 0\n> <>') > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_objectclass_restrict | 6 ++++-- > source4/dsdb/tests/python/sam.py | 21 ++++++++++++++++++- > 2 files changed, 24 insertions(+), 3 deletions(-) > >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index d093c631bd37..ac7befffb1b4 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -3,10 +3,12 @@ > # > # All these tests need to be fixed and the entries here removed > >-^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_userAccountControl\(fl2008r2dc\) >+^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_computer_add_0_uac >+^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_computer_add_trust >+^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_computer_modify >+^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_user_modify > ^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_users_groups\(fl2008r2dc\) > ^samba4.ldap.python\(ad_dc_default\).__main__.BasicTests.test_all\(ad_dc_default\) >-^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_userAccountControl\(ad_dc_default\) > ^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_users_groups\(ad_dc_default\) > ^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-DC_add_CC_WP_user\(ad_dc_default\) > ^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-DC_add_CC_default_user\(ad_dc_default\) >diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py >index 67e2f7b23c3e..077a1a86e90b 100755 >--- a/source4/dsdb/tests/python/sam.py >+++ b/source4/dsdb/tests/python/sam.py >@@ -1885,7 +1885,7 @@ class SamTests(samba.tests.TestCase): > > delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) > >- def test_userAccountControl(self): >+ def test_userAccountControl_user_add_0_uac(self): > """Test the userAccountControl behaviour""" > print("Testing userAccountControl behaviour\n") > >@@ -1913,12 +1913,15 @@ class SamTests(samba.tests.TestCase): > self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_PASSWD_NOTREQD == 0) > delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) > >+ def test_userAccountControl_user_add_normal(self): >+ """Test the userAccountControl behaviour""" > ldb.add({ > "dn": "cn=ldaptestuser,cn=users," + self.base_dn, > "objectclass": "user", > "userAccountControl": str(UF_NORMAL_ACCOUNT)}) > delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) > >+ def test_userAccountControl_user_add_normal_pwnotreq(self): > ldb.add({ > "dn": "cn=ldaptestuser,cn=users," + self.base_dn, > "objectclass": "user", >@@ -1933,6 +1936,7 @@ class SamTests(samba.tests.TestCase): > self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0) > delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) > >+ def test_userAccountControl_user_add_normal_pwnotreq_lockout_expired(self): > ldb.add({ > "dn": "cn=ldaptestuser,cn=users," + self.base_dn, > "objectclass": "user", >@@ -1952,6 +1956,7 @@ class SamTests(samba.tests.TestCase): > self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0) > delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) > >+ def test_userAccountControl_user_add_temp_dup(self): > try: > ldb.add({ > "dn": "cn=ldaptestuser,cn=users," + self.base_dn, >@@ -1963,6 +1968,7 @@ class SamTests(samba.tests.TestCase): > self.assertEqual(num, ERR_OTHER) > delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) > >+ def test_userAccountControl_user_add_server(self): > try: > ldb.add({ > "dn": "cn=ldaptestuser,cn=users," + self.base_dn, >@@ -1974,6 +1980,7 @@ class SamTests(samba.tests.TestCase): > self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION) > delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) > >+ def test_userAccountControl_user_add_workstation(self): > try: > ldb.add({ > "dn": "cn=ldaptestuser,cn=users," + self.base_dn, >@@ -1984,6 +1991,7 @@ class SamTests(samba.tests.TestCase): > self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION) > delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) > >+ def test_userAccountControl_user_add_rodc(self): > try: > ldb.add({ > "dn": "cn=ldaptestuser,cn=users," + self.base_dn, >@@ -1994,6 +2002,7 @@ class SamTests(samba.tests.TestCase): > self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION) > delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn) > >+ def test_userAccountControl_user_add_trust(self): > try: > ldb.add({ > "dn": "cn=ldaptestuser,cn=users," + self.base_dn, >@@ -2007,6 +2016,7 @@ class SamTests(samba.tests.TestCase): > > # Modify operation > >+ def test_userAccountControl_user_modify(self): > ldb.add({ > "dn": "cn=ldaptestuser,cn=users," + self.base_dn, > "objectclass": "user"}) >@@ -2177,6 +2187,7 @@ class SamTests(samba.tests.TestCase): > (num, _) = e69.args > self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS) > >+ def test_userAccountControl_computer_add_0_uac(self): > # With a computer object > > # Add operation >@@ -2201,12 +2212,14 @@ class SamTests(samba.tests.TestCase): > self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_PASSWD_NOTREQD == 0) > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) > >+ def test_userAccountControl_computer_add_normal(self): > ldb.add({ > "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn, > "objectclass": "computer", > "userAccountControl": str(UF_NORMAL_ACCOUNT)}) > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) > >+ def test_userAccountControl_computer_add_normal_pwnotreqd(self): > ldb.add({ > "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn, > "objectclass": "computer", >@@ -2221,6 +2234,7 @@ class SamTests(samba.tests.TestCase): > self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0) > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) > >+ def test_userAccountControl_computer_add_normal_pwnotreqd_lockout_expired(self): > ldb.add({ > "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn, > "objectclass": "computer", >@@ -2240,6 +2254,7 @@ class SamTests(samba.tests.TestCase): > self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0) > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) > >+ def test_userAccountControl_computer_add_temp_dup(self): > try: > ldb.add({ > "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn, >@@ -2251,6 +2266,7 @@ class SamTests(samba.tests.TestCase): > self.assertEqual(num, ERR_OTHER) > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) > >+ def test_userAccountControl_computer_add_server(self): > ldb.add({ > "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn, > "objectclass": "computer", >@@ -2263,6 +2279,7 @@ class SamTests(samba.tests.TestCase): > ATYPE_WORKSTATION_TRUST) > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) > >+ def test_userAccountControl_computer_add_workstation(self): > try: > ldb.add({ > "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn, >@@ -2273,6 +2290,7 @@ class SamTests(samba.tests.TestCase): > self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION) > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) > >+ def test_userAccountControl_computer_add_trust(self): > try: > ldb.add({ > "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn, >@@ -2284,6 +2302,7 @@ class SamTests(samba.tests.TestCase): > self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS) > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) > >+ def test_userAccountControl_computer_modify(self): > # Modify operation > > ldb.add({ >-- >2.25.1 > > >From adf7754ad2ee72ec19a40b3e9c5840e76796098c Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 21 Oct 2021 15:06:14 +1300 >Subject: [PATCH 092/262] CVE-2020-25722 selftest: Adjust sam.py > test_userAccountControl_computer_add_trust to new reality > >We now enforce that a trust account must be a user. > >These can not be added over LDAP anyway, and our C >code in the RPC server gets this right in any case. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_objectclass_restrict | 1 - > source4/dsdb/tests/python/sam.py | 2 +- > 2 files changed, 1 insertion(+), 2 deletions(-) > >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index ac7befffb1b4..0fc2f4d47a21 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -4,7 +4,6 @@ > # All these tests need to be fixed and the entries here removed > > ^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_computer_add_0_uac >-^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_computer_add_trust > ^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_computer_modify > ^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_user_modify > ^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_users_groups\(fl2008r2dc\) >diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py >index 077a1a86e90b..ae83a136785f 100755 >--- a/source4/dsdb/tests/python/sam.py >+++ b/source4/dsdb/tests/python/sam.py >@@ -2299,7 +2299,7 @@ class SamTests(samba.tests.TestCase): > self.fail() > except LdbError as e72: > (num, _) = e72.args >- self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS) >+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION) > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) > > def test_userAccountControl_computer_modify(self): >-- >2.25.1 > > >From bac51df835f3125bc35c89ccb217de4858c3bd36 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 21 Oct 2021 15:14:28 +1300 >Subject: [PATCH 093/262] CVE-2020-25722 selftest: New objects of > objectclass=computer are workstations by default now > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_objectclass_restrict | 1 - > source4/dsdb/tests/python/sam.py | 4 ++-- > 2 files changed, 2 insertions(+), 3 deletions(-) > >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index 0fc2f4d47a21..295818d6a1bf 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -3,7 +3,6 @@ > # > # All these tests need to be fixed and the entries here removed > >-^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_computer_add_0_uac > ^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_computer_modify > ^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_user_modify > ^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_users_groups\(fl2008r2dc\) >diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py >index ae83a136785f..7ac2319dd49c 100755 >--- a/source4/dsdb/tests/python/sam.py >+++ b/source4/dsdb/tests/python/sam.py >@@ -2207,7 +2207,7 @@ class SamTests(samba.tests.TestCase): > attrs=["sAMAccountType", "userAccountControl"]) > self.assertTrue(len(res1) == 1) > self.assertEqual(int(res1[0]["sAMAccountType"][0]), >- ATYPE_NORMAL_ACCOUNT) >+ ATYPE_WORKSTATION_TRUST) > self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0) > self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_PASSWD_NOTREQD == 0) > delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) >@@ -2315,7 +2315,7 @@ class SamTests(samba.tests.TestCase): > attrs=["sAMAccountType", "userAccountControl"]) > self.assertTrue(len(res1) == 1) > self.assertEqual(int(res1[0]["sAMAccountType"][0]), >- ATYPE_NORMAL_ACCOUNT) >+ ATYPE_WORKSTATION_TRUST) > self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE != 0) > > # As computer you can switch from a normal account to a workstation >-- >2.25.1 > > >From 95ecfbf60226c719a881106e8228bc809c88ec15 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 21 Oct 2021 15:19:19 +1300 >Subject: [PATCH 094/262] CVE-2020-25722 selftest: Adapt sam.py test to > userAccountControl/objectclass restrictions > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_objectclass_restrict | 2 -- > source4/dsdb/tests/python/sam.py | 6 +++--- > 2 files changed, 3 insertions(+), 5 deletions(-) > >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index 295818d6a1bf..0971c13c2f03 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -3,8 +3,6 @@ > # > # All these tests need to be fixed and the entries here removed > >-^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_computer_modify >-^samba4.sam.python\(.*\).__main__.SamTests.test_userAccountControl_user_modify > ^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_users_groups\(fl2008r2dc\) > ^samba4.ldap.python\(ad_dc_default\).__main__.BasicTests.test_all\(ad_dc_default\) > ^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_users_groups\(ad_dc_default\) >diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py >index 7ac2319dd49c..e50e25adbe37 100755 >--- a/source4/dsdb/tests/python/sam.py >+++ b/source4/dsdb/tests/python/sam.py >@@ -2135,7 +2135,7 @@ class SamTests(samba.tests.TestCase): > self.fail() > except LdbError as e67: > (num, _) = e67.args >- self.assertEqual(num, ERR_UNWILLING_TO_PERFORM) >+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION) > > m = Message() > m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn) >@@ -2154,7 +2154,7 @@ class SamTests(samba.tests.TestCase): > self.fail() > except LdbError as e68: > (num, _) = e68.args >- self.assertEqual(num, ERR_UNWILLING_TO_PERFORM) >+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION) > > res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn, > scope=SCOPE_BASE, attrs=["sAMAccountType"]) >@@ -2502,7 +2502,7 @@ class SamTests(samba.tests.TestCase): > self.fail() > except LdbError as e76: > (num, _) = e76.args >- self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS) >+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION) > > # "primaryGroupID" does not change if account type remains the same > >-- >2.25.1 > > >From 603e6e3e564d237997565f6a813307baf0221a84 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 21 Oct 2021 15:42:46 +1300 >Subject: [PATCH 095/262] CVE-2020-25722 selftest: adapt ldap.py/sam.py > test_all tests to new default computer behaviour > >Objects of objectclass computer are computers by default now and this changes >the sAMAccountType and primaryGroupID as well as userAccountControl > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_objectclass_restrict | 3 --- > source4/dsdb/tests/python/ldap.py | 13 +++++++------ > source4/dsdb/tests/python/sam.py | 4 +++- > 3 files changed, 10 insertions(+), 10 deletions(-) > >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index 0971c13c2f03..7328ca17d808 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -3,9 +3,6 @@ > # > # All these tests need to be fixed and the entries here removed > >-^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_users_groups\(fl2008r2dc\) >-^samba4.ldap.python\(ad_dc_default\).__main__.BasicTests.test_all\(ad_dc_default\) >-^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_users_groups\(ad_dc_default\) > ^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-DC_add_CC_WP_user\(ad_dc_default\) > ^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-DC_add_CC_default_user\(ad_dc_default\) > ^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_WP_computer\(ad_dc_default\) >diff --git a/source4/dsdb/tests/python/ldap.py b/source4/dsdb/tests/python/ldap.py >index a90bf367b1bc..bd30faeb1d9c 100755 >--- a/source4/dsdb/tests/python/ldap.py >+++ b/source4/dsdb/tests/python/ldap.py >@@ -48,6 +48,7 @@ from samba.dsdb import (UF_NORMAL_ACCOUNT, > ATYPE_WORKSTATION_TRUST, SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE, > SYSTEM_FLAG_CONFIG_ALLOW_RENAME, SYSTEM_FLAG_CONFIG_ALLOW_MOVE, > SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE) >+from samba.dcerpc.security import DOMAIN_RID_DOMAIN_MEMBERS > > from samba.ndr import ndr_pack, ndr_unpack > from samba.dcerpc import security, lsa >@@ -2018,9 +2019,9 @@ delete: description > self.assertTrue("objectGUID" in res[0]) > self.assertTrue("whenCreated" in res[0]) > self.assertEqual(str(res[0]["objectCategory"][0]), ("CN=Computer,%s" % ldb.get_schema_basedn())) >- self.assertEqual(int(res[0]["primaryGroupID"][0]), 513) >- self.assertEqual(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT) >- self.assertEqual(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE) >+ self.assertEqual(int(res[0]["primaryGroupID"][0]), DOMAIN_RID_DOMAIN_MEMBERS) >+ self.assertEqual(int(res[0]["sAMAccountType"][0]), ATYPE_WORKSTATION_TRUST) >+ self.assertEqual(int(res[0]["userAccountControl"][0]), UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE) > > delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn) > >@@ -2499,9 +2500,9 @@ member: cn=ldaptestuser2,cn=users,""" + self.base_dn + """ > self.assertTrue("objectGUID" in res[0]) > self.assertTrue("whenCreated" in res[0]) > self.assertEqual(str(res[0]["objectCategory"]), ("CN=Computer,%s" % ldb.get_schema_basedn())) >- self.assertEqual(int(res[0]["primaryGroupID"][0]), 513) >- self.assertEqual(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT) >- self.assertEqual(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE) >+ self.assertEqual(int(res[0]["primaryGroupID"][0]), DOMAIN_RID_DOMAIN_MEMBERS) >+ self.assertEqual(int(res[0]["sAMAccountType"][0]), ATYPE_WORKSTATION_TRUST) >+ self.assertEqual(int(res[0]["userAccountControl"][0]), UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE) > self.assertEqual(str(res[0]["memberOf"][0]).upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper()) > self.assertEqual(len(res[0]["memberOf"]), 1) > >diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py >index e50e25adbe37..faa882e12878 100755 >--- a/source4/dsdb/tests/python/sam.py >+++ b/source4/dsdb/tests/python/sam.py >@@ -291,7 +291,9 @@ class SamTests(samba.tests.TestCase): > > ldb.add({ > "dn": "cn=ldaptestuser,cn=users," + self.base_dn, >- "objectclass": "computer"}) >+ "objectclass": "computer", >+ "userAccountControl": str(UF_NORMAL_ACCOUNT | >+ UF_PASSWD_NOTREQD)}) > > res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn, > scope=SCOPE_BASE, attrs=["primaryGroupID"]) >-- >2.25.1 > > >From d45e8c55e717f2f84ee77f6f4c9e3645b980641e Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Fri, 22 Oct 2021 22:40:06 +1300 >Subject: [PATCH 096/262] CVE-2020-25722 selftest: Allow > self.assertRaisesLdbError() to take a list of errors to match with > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > python/samba/tests/__init__.py | 30 ++++++++++++------- > selftest/knownfail.d/uac_objectclass_restrict | 2 -- > .../dsdb/tests/python/user_account_control.py | 5 ++++ > 3 files changed, 25 insertions(+), 12 deletions(-) > >diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py >index f47455196174..14924528b0f9 100644 >--- a/python/samba/tests/__init__.py >+++ b/python/samba/tests/__init__.py >@@ -21,6 +21,7 @@ from __future__ import print_function > import os > import tempfile > import warnings >+import collections > import ldb > import samba > from samba import param >@@ -304,23 +305,32 @@ class TestCase(unittest.TestCase): > f(*args, **kwargs) > except ldb.LdbError as e: > (num, msg) = e.args >- if num != errcode: >+ if isinstance(errcode, collections.abc.Container): >+ found = num in errcode >+ else: >+ found = num == errcode >+ if not found: > lut = {v: k for k, v in vars(ldb).items() > if k.startswith('ERR_') and isinstance(v, int)} >- self.fail("%s, expected " >- "LdbError %s, (%d) " >- "got %s (%d) " >- "%s" % (message, >- lut.get(errcode), errcode, >- lut.get(num), num, >- msg)) >+ if isinstance(errcode, collections.abc.Container): >+ errcode_name = ' '.join(lut.get(x) for x in errcode) >+ else: >+ errcode_name = lut.get(errcode) >+ self.fail(f"{message}, expected " >+ f"LdbError {errcode_name}, {errcode} " >+ f"got {lut.get(num)} ({num}) " >+ f"{msg}") > else: > lut = {v: k for k, v in vars(ldb).items() > if k.startswith('ERR_') and isinstance(v, int)} >+ if isinstance(errcode, collections.abc.Container): >+ errcode_name = ' '.join(lut.get(x) for x in errcode) >+ else: >+ errcode_name = lut.get(errcode) > self.fail("%s, expected " >- "LdbError %s, (%d) " >+ "LdbError %s, (%s) " > "but we got success" % (message, >- lut.get(errcode), >+ errcode_name, > errcode)) > > >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index 7328ca17d808..ac6f4857bf49 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -20,8 +20,6 @@ > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_user_replace\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_SERVER_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_SERVER_TRUST_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_NORMAL_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_SERVER_TRUST_ACCOUNT_deladd_priv\(ad_dc_default\) >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index 7a7cfd40b72e..ed68a683e69f 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -594,6 +594,9 @@ class UserAccountControlTests(samba.tests.TestCase): > if (bit in priv_bits): > self.fail("Unexpectedly able to set userAccountControl bit 0x%08X (%s), on %s" > % (bit, bit_str, m.dn)) >+ if (bit in account_types and bit != UF_NORMAL_ACCOUNT): >+ self.fail("Unexpectedly able to set userAccountControl bit 0x%08X (%s), on %s" >+ % (bit, bit_str, m.dn)) > except LdbError as e: > (enum, estr) = e.args > if bit in invalid_bits: >@@ -601,6 +604,8 @@ class UserAccountControlTests(samba.tests.TestCase): > ldb.ERR_OTHER, > "was not able to set 0x%08X (%s) on %s" > % (bit, bit_str, m.dn)) >+ elif (bit in account_types): >+ self.assertIn(enum, [ldb.ERR_OBJECT_CLASS_VIOLATION, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS]) > elif (bit in priv_bits): > self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum) > else: >-- >2.25.1 > > >From 04afa8e54b6771fff2ca26da6996898f1aadc958 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Fri, 22 Oct 2021 22:54:52 +1300 >Subject: [PATCH 097/262] CVE-2020-25722 selftest/user_account_control: Allow a > broader set of possible errors > >This favors a test that confirms we got an error over getting exactly >the right error, at least for now. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_objectclass_restrict | 4 ---- > selftest/knownfail.d/user_account_control | 1 - > source4/dsdb/tests/python/user_account_control.py | 12 ++++++++---- > 3 files changed, 8 insertions(+), 9 deletions(-) > delete mode 100644 selftest/knownfail.d/user_account_control > >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index ac6f4857bf49..1d72442f8a8e 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -22,10 +22,6 @@ > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_NORMAL_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_SERVER_TRUST_ACCOUNT_deladd_priv\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_SERVER_TRUST_ACCOUNT_deladd_wp\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_SERVER_TRUST_ACCOUNT_replace_priv\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_uac_mod_lock_UF_NORMAL_ACCOUNT_UF_SERVER_TRUST_ACCOUNT_replace_wp\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_INTERDOMAIN_TRUST_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_NORMAL_ACCOUNT\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_NORMAL_ACCOUNT_UF_PASSWD_NOTREQD\(ad_dc_default\) >diff --git a/selftest/knownfail.d/user_account_control b/selftest/knownfail.d/user_account_control >deleted file mode 100644 >index ad3af6787080..000000000000 >--- a/selftest/knownfail.d/user_account_control >+++ /dev/null >@@ -1 +0,0 @@ >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_add_computer_cc_normal_bare.ad_dc_default >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index ed68a683e69f..f99f370679b8 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -484,7 +484,8 @@ class UserAccountControlTests(samba.tests.TestCase): > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM, >+ self.assertRaisesLdbError([ldb.ERR_OBJECT_CLASS_VIOLATION, >+ ldb.ERR_UNWILLING_TO_PERFORM], > f"Unexpectedly able to set userAccountControl to be an Normal " > "account without |UF_PASSWD_NOTREQD Unexpectedly able to " > "set userAccountControl to be a workstation on {m.dn}", >@@ -1204,12 +1205,14 @@ class UserAccountControlTests(samba.tests.TestCase): > samdb.modify(m) > elif (account_type == UF_NORMAL_ACCOUNT) and \ > (account_type2 == UF_SERVER_TRUST_ACCOUNT) and not priv: >- self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ self.assertRaisesLdbError([ldb.ERR_OBJECT_CLASS_VIOLATION, >+ ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS], > f"Should have been unable to change {account_type_str} to {account_type2_str}", > samdb.modify, m) > elif (account_type == UF_NORMAL_ACCOUNT) and \ > (account_type2 == UF_SERVER_TRUST_ACCOUNT) and priv: >- self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM, >+ self.assertRaisesLdbError([ldb.ERR_OBJECT_CLASS_VIOLATION, >+ ldb.ERR_UNWILLING_TO_PERFORM], > f"Should have been unable to change {account_type_str} to {account_type2_str}", > samdb.modify, m) > elif (account_type == UF_WORKSTATION_TRUST_ACCOUNT) and \ >@@ -1282,7 +1285,8 @@ class UserAccountControlTests(samba.tests.TestCase): > m["1objectclass"] = ldb.MessageElement(new_objectclass, > ldb.FLAG_MOD_ADD, "objectclass") > >- self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM, >+ self.assertRaisesLdbError([ldb.ERR_OBJECT_CLASS_VIOLATION, >+ ldb.ERR_UNWILLING_TO_PERFORM], > "Should have been unable Able to change objectclass of a {objectclass}", > self.admin_samdb.modify, m) > >-- >2.25.1 > > >From a8e2c4a1854575b33195def146da4a3fa1c7a0c8 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Fri, 22 Oct 2021 23:41:23 +1300 >Subject: [PATCH 098/262] CVE-2020-25722 selftest/user_account_control: more > work to cope with UAC/objectclass defaults and lock > >This new restriction breaks a large number of assumptions in the tests, like >that you can remove some UF_ flags, because it turns out doing so will >make the 'computer' a 'user' again, and this will fail. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >--- > selftest/knownfail.d/uac_objectclass_restrict | 6 --- > .../dsdb/tests/python/user_account_control.py | 46 ++++++++++++------- > 2 files changed, 29 insertions(+), 23 deletions(-) > >diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict >index 1d72442f8a8e..c4d4507c833b 100644 >--- a/selftest/knownfail.d/uac_objectclass_restrict >+++ b/selftest/knownfail.d/uac_objectclass_restrict >@@ -14,14 +14,8 @@ > ^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-user_mod-del-add_CC_default_computer\(ad_dc_default\) > ^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-user_mod-replace_CC_default_computer\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_add_computer_sd_cc\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_admin_mod_uac\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_computer_cc\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_computer_replace\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_NORMAL_ACCOUNT_user_replace\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_SERVER_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) > ^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_objectclass_mod_lock_UF_WORKSTATION_TRUST_ACCOUNT_computer_replace\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_NORMAL_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_INTERDOMAIN_TRUST_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_NORMAL_ACCOUNT\(ad_dc_default\) >-^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_add_UF_NORMAL_ACCOUNT_UF_PASSWD_NOTREQD\(ad_dc_default\) >diff --git a/source4/dsdb/tests/python/user_account_control.py b/source4/dsdb/tests/python/user_account_control.py >index f99f370679b8..6a0ef73b29ad 100755 >--- a/source4/dsdb/tests/python/user_account_control.py >+++ b/source4/dsdb/tests/python/user_account_control.py >@@ -433,11 +433,10 @@ class UserAccountControlTests(samba.tests.TestCase): > m.dn = res[0].dn > m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD), > ldb.FLAG_MOD_REPLACE, "userAccountControl") >- try: >- self.samdb.modify(m) >- except LdbError as e: >- (enum, estr) = e.args >- self.fail(f"got {estr} setting userAccountControl to UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD") >+ >+ self.assertRaisesLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION, >+ f"Unexpectedly able to set userAccountControl as to UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD on {m.dn}", >+ self.samdb.modify, m) > > m = ldb.Message() > m.dn = res[0].dn >@@ -501,7 +500,7 @@ class UserAccountControlTests(samba.tests.TestCase): > scope=SCOPE_SUBTREE, > attrs=["userAccountControl"]) > >- self.assertEqual(int(res[0]["userAccountControl"][0]), (UF_NORMAL_ACCOUNT | >+ self.assertEqual(int(res[0]["userAccountControl"][0]), (UF_WORKSTATION_TRUST_ACCOUNT | > UF_ACCOUNTDISABLE | > UF_PASSWD_NOTREQD)) > >@@ -681,11 +680,9 @@ class UserAccountControlTests(samba.tests.TestCase): > scope=SCOPE_SUBTREE, > attrs=["userAccountControl"]) > >- if account_type == UF_WORKSTATION_TRUST_ACCOUNT: >- self.assertEqual(orig_uac, account_type) >- else: >- self.assertEqual(orig_uac & UF_NORMAL_ACCOUNT, >- account_type) >+ self.assertEqual(len(res), 1) >+ reset_uac = int(res[0]["userAccountControl"][0]) >+ self.assertEqual(orig_uac, reset_uac) > > m = ldb.Message() > m.dn = res[0].dn >@@ -704,14 +701,16 @@ class UserAccountControlTests(samba.tests.TestCase): > # No point going on, try the next bit > continue > elif bit in super_priv_bits: >- self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) >+ self.assertIn(enum, (ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, >+ ldb.ERR_OBJECT_CLASS_VIOLATION)) > # No point going on, try the next bit > continue > > elif (account_type == UF_NORMAL_ACCOUNT) \ > and (bit in account_types) \ > and (bit != account_type): >- self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM) >+ self.assertIn(enum, (ldb.ERR_UNWILLING_TO_PERFORM, >+ ldb.ERR_OBJECT_CLASS_VIOLATION)) > continue > > elif (account_type == UF_WORKSTATION_TRUST_ACCOUNT) \ >@@ -789,7 +788,10 @@ class UserAccountControlTests(samba.tests.TestCase): > > except LdbError as e3: > (enum, estr) = e3.args >- if bit in priv_to_remove_bits: >+ if account_type == UF_WORKSTATION_TRUST_ACCOUNT: >+ # Because removing any bit would change the account back to a user, which is locked by objectclass >+ self.assertIn(enum, (ldb.ERR_OBJECT_CLASS_VIOLATION, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS)) >+ elif bit in priv_to_remove_bits: > self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) > else: > self.fail("Unexpectedly unable to remove userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr)) >@@ -808,7 +810,7 @@ class UserAccountControlTests(samba.tests.TestCase): > self.assertEqual(int(res[0]["userAccountControl"][0]), > bit | UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD, > "bit 0X%08x should not have been removed" % bit) >- else: >+ elif account_type != UF_WORKSTATION_TRUST_ACCOUNT: > self.assertEqual(int(res[0]["userAccountControl"][0]), > UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD, > "bit 0X%08x should have been removed" % bit) >@@ -859,9 +861,19 @@ class UserAccountControlTests(samba.tests.TestCase): > bit_str, > computername)) > elif bit in priv_bits: >- self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) >+ if bit == UF_INTERDOMAIN_TRUST_ACCOUNT: >+ self.assertIn(enum, (ldb.ERR_OBJECT_CLASS_VIOLATION, >+ ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS)) >+ else: >+ self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) > elif bit in unwilling_bits: >- self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM) >+ # This can fail early as user in a computer is not permitted as non-admin >+ self.assertIn(enum, (ldb.ERR_UNWILLING_TO_PERFORM, >+ ldb.ERR_OBJECT_CLASS_VIOLATION)) >+ elif bit & UF_NORMAL_ACCOUNT: >+ # This can fail early as user in a computer is not permitted as non-admin >+ self.assertIn(enum, (ldb.ERR_UNWILLING_TO_PERFORM, >+ ldb.ERR_OBJECT_CLASS_VIOLATION)) > else: > self.fail("Unable to set userAccountControl bit 0x%08X (%s) on %s: %s" > % (bit, >-- >2.25.1 > > >From 19584fd7a6bf5d83b561a184465fdfd5f00c90b4 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 27 Sep 2021 11:20:19 +1300 >Subject: [PATCH 099/262] CVE-2020-25721 krb5pac: Add new buffers for > samAccountName and objectSID > >These appear when PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID is set. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14835 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz> >--- > librpc/idl/krb5pac.idl | 18 ++++++++++++++++-- > librpc/ndr/ndr_krb5pac.c | 4 ++-- > 2 files changed, 18 insertions(+), 4 deletions(-) > >diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl >index 515150ab9cdf..ed488dee4251 100644 >--- a/librpc/idl/krb5pac.idl >+++ b/librpc/idl/krb5pac.idl >@@ -86,15 +86,29 @@ interface krb5pac > } PAC_CONSTRAINED_DELEGATION; > > typedef [bitmap32bit] bitmap { >- PAC_UPN_DNS_FLAG_CONSTRUCTED = 0x00000001 >+ PAC_UPN_DNS_FLAG_CONSTRUCTED = 0x00000001, >+ PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID = 0x00000002 > } PAC_UPN_DNS_FLAGS; > >+ typedef struct { >+ [value(2*strlen_m(samaccountname))] uint16 samaccountname_size; >+ [relative_short,subcontext(0),subcontext_size(samaccountname_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *samaccountname; >+ [value(ndr_size_dom_sid(objectsid, ndr->flags))] uint16 objectsid_size; >+ [relative_short,subcontext(0),subcontext_size(objectsid_size)] dom_sid *objectsid; >+ } PAC_UPN_DNS_INFO_SAM_NAME_AND_SID; >+ >+ typedef [nodiscriminant] union { >+ [case(PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID)] PAC_UPN_DNS_INFO_SAM_NAME_AND_SID sam_name_and_sid; >+ [default]; >+ } PAC_UPN_DNS_INFO_EX; >+ > typedef struct { > [value(2*strlen_m(upn_name))] uint16 upn_name_size; > [relative_short,subcontext(0),subcontext_size(upn_name_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *upn_name; > [value(2*strlen_m(dns_domain_name))] uint16 dns_domain_name_size; > [relative_short,subcontext(0),subcontext_size(dns_domain_name_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *dns_domain_name; > PAC_UPN_DNS_FLAGS flags; >+ [switch_is(flags & PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID)] PAC_UPN_DNS_INFO_EX ex; > } PAC_UPN_DNS_INFO; > > typedef [public] struct { >@@ -142,7 +156,7 @@ interface krb5pac > > typedef [public,nopush,nopull] struct { > PAC_TYPE type; >- [value(_ndr_size_PAC_INFO(info, type, 0))] uint32 _ndr_size; >+ [value(_ndr_size_PAC_INFO(info, type, LIBNDR_FLAG_ALIGN8))] uint32 _ndr_size; > /* > * We need to have two subcontexts to get the padding right, > * the outer subcontext uses NDR_ROUND(_ndr_size, 8), while >diff --git a/librpc/ndr/ndr_krb5pac.c b/librpc/ndr/ndr_krb5pac.c >index a9ae2c4a789c..57b28df9e528 100644 >--- a/librpc/ndr/ndr_krb5pac.c >+++ b/librpc/ndr/ndr_krb5pac.c >@@ -41,7 +41,7 @@ enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const > if (ndr_flags & NDR_SCALARS) { > NDR_CHECK(ndr_push_align(ndr, 4)); > NDR_CHECK(ndr_push_PAC_TYPE(ndr, NDR_SCALARS, r->type)); >- NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,0))); >+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,LIBNDR_FLAG_ALIGN8))); > { > uint32_t _flags_save_PAC_INFO = ndr->flags; > ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8); >@@ -59,7 +59,7 @@ enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const > { > struct ndr_push *_ndr_info_pad; > struct ndr_push *_ndr_info; >- size_t _ndr_size = _ndr_size_PAC_INFO(r->info, r->type, 0); >+ size_t _ndr_size = _ndr_size_PAC_INFO(r->info, r->type, LIBNDR_FLAG_ALIGN8); > NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info_pad, 0, NDR_ROUND(_ndr_size, 8))); > NDR_CHECK(ndr_push_subcontext_start(_ndr_info_pad, &_ndr_info, 0, _ndr_size)); > NDR_CHECK(ndr_push_set_switch_value(_ndr_info, r->info, r->type)); >-- >2.25.1 > > >From 2fe20758705061ad1dc19768e1a0a9efdb69671d Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Wed, 20 Oct 2021 15:48:35 +1300 >Subject: [PATCH 100/262] CVE-2020-25718 tests/krb5: Allow tests accounts to > replicate to RODC > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/rodc_tests.py | 2 ++ > 1 file changed, 2 insertions(+) > >diff --git a/python/samba/tests/krb5/rodc_tests.py b/python/samba/tests/krb5/rodc_tests.py >index 302ae865cf18..0e252d90262f 100755 >--- a/python/samba/tests/krb5/rodc_tests.py >+++ b/python/samba/tests/krb5/rodc_tests.py >@@ -41,11 +41,13 @@ class RodcKerberosTests(KDCBaseTest): > user_creds = self.get_cached_creds( > account_type=self.AccountType.USER, > opts={ >+ 'allowed_replication': True, > 'revealed_to_rodc': True > }) > target_creds = self.get_cached_creds( > account_type=self.AccountType.COMPUTER, > opts={ >+ 'allowed_replication': True, > 'revealed_to_rodc': True > }) > >-- >2.25.1 > > >From 293e24d9483a96cd3d9f6a945cd42a1c8844c7b7 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Mon, 18 Oct 2021 14:59:01 +1300 >Subject: [PATCH 101/262] CVE-2020-25719 CVE-2020-25717 tests/krb5: Modify > get_service_ticket() to use _generic_kdc_exchange() > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14799 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_base_test.py | 54 ++++++++++++------------ > 1 file changed, 27 insertions(+), 27 deletions(-) > >diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py >index 8ae9c24b0fc3..c129883e7cde 100644 >--- a/python/samba/tests/krb5/kdc_base_test.py >+++ b/python/samba/tests/krb5/kdc_base_test.py >@@ -1275,7 +1275,7 @@ class KDCBaseTest(RawKerberosTest): > expected_flags=None, unexpected_flags=None, > fresh=False): > user_name = tgt.cname['name-string'][0] >- target_name = target_creds.get_username() >+ target_name = target_creds.get_username()[:-1] > cache_key = (user_name, target_name, service, to_rodc, kdc_options) > > if not fresh: >@@ -1288,40 +1288,40 @@ class KDCBaseTest(RawKerberosTest): > > if kdc_options is None: > kdc_options = '0' >- kdc_options = krb5_asn1.KDCOptions(kdc_options) >- >- key = tgt.session_key >- ticket = tgt.ticket >+ kdc_options = str(krb5_asn1.KDCOptions(kdc_options)) > >- cname = tgt.cname >- realm = tgt.crealm >- >- target_name = target_creds.get_username()[:-1] > sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, > names=[service, target_name]) >+ srealm = target_creds.get_realm() > >- rep, enc_part = self.tgs_req(cname, sname, realm, ticket, key, etype, >- to_rodc=to_rodc, >- service_creds=target_creds, >- kdc_options=kdc_options, >- expected_flags=expected_flags, >- unexpected_flags=unexpected_flags) >+ authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256) > >- service_ticket = rep['ticket'] >+ decryption_key = self.TicketDecryptionKey_from_creds(target_creds) > >- ticket_etype = service_ticket['enc-part']['etype'] >- target_key = self.TicketDecryptionKey_from_creds(target_creds, >- etype=ticket_etype) >+ kdc_exchange_dict = self.tgs_exchange_dict( >+ expected_crealm=tgt.crealm, >+ expected_cname=tgt.cname, >+ expected_srealm=srealm, >+ expected_sname=sname, >+ expected_supported_etypes=target_creds.tgs_supported_enctypes, >+ expected_flags=expected_flags, >+ unexpected_flags=unexpected_flags, >+ ticket_decryption_key=decryption_key, >+ check_rep_fn=self.generic_check_kdc_rep, >+ check_kdc_private_fn=self.generic_check_kdc_private, >+ tgt=tgt, >+ authenticator_subkey=authenticator_subkey, >+ kdc_options=kdc_options, >+ to_rodc=to_rodc) > >- session_key = self.EncryptionKey_import(enc_part['key']) >+ rep = self._generic_kdc_exchange(kdc_exchange_dict, >+ cname=None, >+ realm=srealm, >+ sname=sname, >+ etypes=etype) >+ self.check_tgs_reply(rep) > >- service_ticket_creds = KerberosTicketCreds(service_ticket, >- session_key, >- crealm=realm, >- cname=cname, >- srealm=realm, >- sname=sname, >- decryption_key=target_key) >+ service_ticket_creds = kdc_exchange_dict['rep_ticket_creds'] > > if to_rodc: > krbtgt_creds = self.get_rodc_krbtgt_creds() >-- >2.25.1 > > >From 69ee99e5148024930a3baf2e8b13b42c7bb5c18d Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Mon, 18 Oct 2021 15:00:38 +1300 >Subject: [PATCH 102/262] CVE-2020-25719 CVE-2020-25717 tests/krb5: Add > pac_request parameter to get_service_ticket() > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14799 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_base_test.py | 8 ++++++-- > 1 file changed, 6 insertions(+), 2 deletions(-) > >diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py >index c129883e7cde..813af767dbd1 100644 >--- a/python/samba/tests/krb5/kdc_base_test.py >+++ b/python/samba/tests/krb5/kdc_base_test.py >@@ -1273,10 +1273,11 @@ class KDCBaseTest(RawKerberosTest): > def get_service_ticket(self, tgt, target_creds, service='host', > to_rodc=False, kdc_options=None, > expected_flags=None, unexpected_flags=None, >- fresh=False): >+ pac_request=True, expect_pac=True, fresh=False): > user_name = tgt.cname['name-string'][0] > target_name = target_creds.get_username()[:-1] >- cache_key = (user_name, target_name, service, to_rodc, kdc_options) >+ cache_key = (user_name, target_name, service, to_rodc, kdc_options, >+ pac_request) > > if not fresh: > ticket = self.tkt_cache.get(cache_key) >@@ -1312,6 +1313,8 @@ class KDCBaseTest(RawKerberosTest): > tgt=tgt, > authenticator_subkey=authenticator_subkey, > kdc_options=kdc_options, >+ pac_request=pac_request, >+ expect_pac=expect_pac, > to_rodc=to_rodc) > > rep = self._generic_kdc_exchange(kdc_exchange_dict, >@@ -1329,6 +1332,7 @@ class KDCBaseTest(RawKerberosTest): > krbtgt_creds = self.get_krbtgt_creds() > krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) > self.verify_ticket(service_ticket_creds, krbtgt_key, >+ expect_pac=expect_pac, > expect_ticket_checksum=self.tkt_sig_support) > > self.tkt_cache[cache_key] = service_ticket_creds >-- >2.25.1 > > >From 24649255b0c5f8da8bd7b3eae38b44326e293451 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Fri, 8 Oct 2021 15:40:09 +1300 >Subject: [PATCH 103/262] CVE-2020-25722 tests/krb5: Allow creating server > accounts > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14776 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_base_test.py | 7 +++++++ > 1 file changed, 7 insertions(+) > >diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py >index 813af767dbd1..a0da89041c4f 100644 >--- a/python/samba/tests/krb5/kdc_base_test.py >+++ b/python/samba/tests/krb5/kdc_base_test.py >@@ -38,12 +38,14 @@ from samba.dsdb import ( > DS_DOMAIN_FUNCTION_2000, > DS_DOMAIN_FUNCTION_2008, > DS_GUID_COMPUTERS_CONTAINER, >+ DS_GUID_DOMAIN_CONTROLLERS_CONTAINER, > DS_GUID_USERS_CONTAINER, > UF_WORKSTATION_TRUST_ACCOUNT, > UF_NO_AUTH_DATA_REQUIRED, > UF_NORMAL_ACCOUNT, > UF_NOT_DELEGATED, > UF_PARTIAL_SECRETS_ACCOUNT, >+ UF_SERVER_TRUST_ACCOUNT, > UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION > ) > from samba.join import DCJoinContext >@@ -94,6 +96,7 @@ class KDCBaseTest(RawKerberosTest): > class AccountType(Enum): > USER = auto() > COMPUTER = auto() >+ SERVER = auto() > > @classmethod > def setUpClass(cls): >@@ -245,6 +248,8 @@ class KDCBaseTest(RawKerberosTest): > if ou is None: > if account_type is account_type.COMPUTER: > guid = DS_GUID_COMPUTERS_CONTAINER >+ elif account_type is account_type.SERVER: >+ guid = DS_GUID_DOMAIN_CONTROLLERS_CONTAINER > else: > guid = DS_GUID_USERS_CONTAINER > >@@ -265,6 +270,8 @@ class KDCBaseTest(RawKerberosTest): > account_name += '$' > if account_type is self.AccountType.COMPUTER: > account_control |= UF_WORKSTATION_TRUST_ACCOUNT >+ elif account_type is self.AccountType.SERVER: >+ account_control |= UF_SERVER_TRUST_ACCOUNT > else: > self.fail() > >-- >2.25.1 > > >From b8d2115e0830a215e633a686268421ef0004850c Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Thu, 30 Sep 2021 16:53:22 +1300 >Subject: [PATCH 104/262] CVE-2020-25719 tests/krb5: Add is_tgt() helper method > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14686 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/raw_testcase.py | 7 +++++-- > 1 file changed, 5 insertions(+), 2 deletions(-) > >diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py >index fdf078ea788e..055209fd09df 100644 >--- a/python/samba/tests/krb5/raw_testcase.py >+++ b/python/samba/tests/krb5/raw_testcase.py >@@ -3086,8 +3086,7 @@ class RawKerberosTest(TestCaseInTempDir): > def verify_ticket(self, ticket, krbtgt_key, expect_pac=True, > expect_ticket_checksum=True): > # Check if the ticket is a TGT. >- sname = ticket.ticket['sname'] >- is_tgt = self.is_tgs(sname) >+ is_tgt = self.is_tgt(ticket) > > # Decrypt the ticket. > >@@ -3506,6 +3505,10 @@ class RawKerberosTest(TestCaseInTempDir): > name = principal['name-string'][0] > return name in ('krbtgt', b'krbtgt') > >+ def is_tgt(self, ticket): >+ sname = ticket.ticket['sname'] >+ return self.is_tgs(sname) >+ > def get_empty_pac(self): > return self.AuthorizationData_create(AD_WIN2K_PAC, bytes(1)) > >-- >2.25.1 > > >From 829421f420dbf0a2893173b518b9d7be79a88043 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Tue, 19 Oct 2021 15:02:10 +1300 >Subject: [PATCH 105/262] CVE-2020-25719 tests/krb5: Add method to get unique > username for test accounts > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14686 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_base_test.py | 9 +++++++-- > 1 file changed, 7 insertions(+), 2 deletions(-) > >diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py >index a0da89041c4f..e85574c51cb5 100644 >--- a/python/samba/tests/krb5/kdc_base_test.py >+++ b/python/samba/tests/krb5/kdc_base_test.py >@@ -711,8 +711,7 @@ class KDCBaseTest(RawKerberosTest): > > rodc_dn = self.get_server_dn(rodc_samdb) > >- user_name = self.account_base + str(self.account_id) >- type(self).account_id += 1 >+ user_name = self.get_new_username() > if name_prefix is not None: > user_name = name_prefix + user_name > if name_suffix is not None: >@@ -821,6 +820,12 @@ class KDCBaseTest(RawKerberosTest): > > return creds > >+ def get_new_username(self): >+ user_name = self.account_base + str(self.account_id) >+ type(self).account_id += 1 >+ >+ return user_name >+ > def get_client_creds(self, > allow_missing_password=False, > allow_missing_keys=True): >-- >2.25.1 > > >From 961b7400bf0ccbe94e610e6095a1140724bea5fc Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Wed, 20 Oct 2021 15:48:20 +1300 >Subject: [PATCH 106/262] MS CVE-2020-17049 tests/krb5: Allow tests to pass if > ticket signature checksum type is wrong > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/raw_testcase.py | 21 +++++++++++++++++++-- > 1 file changed, 19 insertions(+), 2 deletions(-) > >diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py >index 055209fd09df..62e1b9867dd8 100644 >--- a/python/samba/tests/krb5/raw_testcase.py >+++ b/python/samba/tests/krb5/raw_testcase.py >@@ -2375,6 +2375,13 @@ class RawKerberosTest(TestCaseInTempDir): > krbtgt_creds = self.get_krbtgt_creds() > krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) > >+ krbtgt_keys = [krbtgt_key] >+ if not self.strict_checking: >+ krbtgt_key_rc4 = self.TicketDecryptionKey_from_creds( >+ krbtgt_creds, >+ etype=kcrypto.Enctype.RC4) >+ krbtgt_keys.append(krbtgt_key_rc4) >+ > expect_pac = kdc_exchange_dict['expect_pac'] > > ticket_session_key = None >@@ -2522,7 +2529,7 @@ class RawKerberosTest(TestCaseInTempDir): > self.assertIsNotNone(ticket_decryption_key) > > if ticket_decryption_key is not None: >- self.verify_ticket(ticket_creds, krbtgt_key, expect_pac=expect_pac, >+ self.verify_ticket(ticket_creds, krbtgt_keys, expect_pac=expect_pac, > expect_ticket_checksum=expect_ticket_checksum > or self.tkt_sig_support) > >@@ -3083,7 +3090,7 @@ class RawKerberosTest(TestCaseInTempDir): > ticket_blob) > self.assertEqual(expected_checksum, checksum) > >- def verify_ticket(self, ticket, krbtgt_key, expect_pac=True, >+ def verify_ticket(self, ticket, krbtgt_keys, expect_pac=True, > expect_ticket_checksum=True): > # Check if the ticket is a TGT. > is_tgt = self.is_tgt(ticket) >@@ -3171,6 +3178,16 @@ class RawKerberosTest(TestCaseInTempDir): > > kdc_checksum, kdc_ctype = checksums[ > krb5pac.PAC_TYPE_KDC_CHECKSUM] >+ >+ if isinstance(krbtgt_keys, collections.abc.Container): >+ if self.strict_checking: >+ krbtgt_key = krbtgt_keys[0] >+ else: >+ krbtgt_key = next(key for key in krbtgt_keys >+ if key.ctype == kdc_ctype) >+ else: >+ krbtgt_key = krbtgt_keys >+ > krbtgt_key.verify_rodc_checksum(KU_NON_KERB_CKSUM_SALT, > server_checksum, > kdc_ctype, >-- >2.25.1 > > >From 2835860c9c923efc3cb930a3644a254087b18f61 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Thu, 21 Oct 2021 16:46:23 +1300 >Subject: [PATCH 107/262] CVE-2020-25721 tests/krb5: Check PAC buffer types > when STRICT_CHECKING=0 > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14835 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/raw_testcase.py | 23 ++++++++++++++--------- > 1 file changed, 14 insertions(+), 9 deletions(-) > >diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py >index 62e1b9867dd8..8e55790272a7 100644 >--- a/python/samba/tests/krb5/raw_testcase.py >+++ b/python/samba/tests/krb5/raw_testcase.py >@@ -1102,13 +1102,14 @@ class RawKerberosTest(TestCaseInTempDir): > f"unexpected in {v}") > > def assertSequenceElementsEqual(self, expected, got, *, >- require_strict=None): >- if self.strict_checking: >+ require_strict=None, >+ require_ordered=True): >+ if self.strict_checking and require_ordered: > self.assertEqual(expected, got) > else: > fail_msg = f'expected: {expected} got: {got}' > >- if require_strict is not None: >+ if not self.strict_checking and require_strict is not None: > fail_msg += f' (ignoring: {require_strict})' > expected = (x for x in expected if x not in require_strict) > got = (x for x in got if x not in require_strict) >@@ -2569,12 +2570,16 @@ class RawKerberosTest(TestCaseInTempDir): > if not self.is_tgs(expected_sname): > expected_types.append(krb5pac.PAC_TYPE_TICKET_CHECKSUM) > >- if self.strict_checking: >- buffer_types = [pac_buffer.type >- for pac_buffer in pac.buffers] >- self.assertCountEqual(expected_types, buffer_types, >- f'expected: {expected_types} ' >- f'got: {buffer_types}') >+ require_strict = {krb5pac.PAC_TYPE_CLIENT_CLAIMS_INFO} >+ if not self.tkt_sig_support: >+ require_strict.add(krb5pac.PAC_TYPE_TICKET_CHECKSUM) >+ >+ buffer_types = [pac_buffer.type >+ for pac_buffer in pac.buffers] >+ self.assertSequenceElementsEqual( >+ expected_types, buffer_types, >+ require_ordered=False, >+ require_strict=require_strict) > > expected_account_name = kdc_exchange_dict['expected_account_name'] > expected_sid = kdc_exchange_dict['expected_sid'] >-- >2.25.1 > > >From 86a10ab5e3f009be077bec0d151a8d2d449a8bd6 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Fri, 22 Oct 2021 11:37:31 +1300 >Subject: [PATCH 108/262] CVE-2020-25719 CVE-2020-25717 tests/krb5: Refactor > create_ccache_with_user() to take credentials of target service > >This allows us to use get_tgt() and get_service_ticket() to obtain >tickets, which simplifies the logic. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14799 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_base_test.py | 43 ++++++------------------ > python/samba/tests/krb5/test_ccache.py | 2 +- > python/samba/tests/krb5/test_ldap.py | 7 ++-- > python/samba/tests/krb5/test_rpc.py | 7 ++-- > python/samba/tests/krb5/test_smb.py | 7 ++-- > 5 files changed, 27 insertions(+), 39 deletions(-) > >diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py >index e85574c51cb5..e77a940f4117 100644 >--- a/python/samba/tests/krb5/kdc_base_test.py >+++ b/python/samba/tests/krb5/kdc_base_test.py >@@ -1283,11 +1283,13 @@ class KDCBaseTest(RawKerberosTest): > return rep, enc_part > > def get_service_ticket(self, tgt, target_creds, service='host', >+ target_name=None, > to_rodc=False, kdc_options=None, > expected_flags=None, unexpected_flags=None, > pac_request=True, expect_pac=True, fresh=False): > user_name = tgt.cname['name-string'][0] >- target_name = target_creds.get_username()[:-1] >+ if target_name is None: >+ target_name = target_creds.get_username()[:-1] > cache_key = (user_name, target_name, service, to_rodc, kdc_options, > pac_request) > >@@ -1669,51 +1671,28 @@ class KDCBaseTest(RawKerberosTest): > > return cachefile > >- def create_ccache_with_user(self, user_credentials, mach_name, >- service="host"): >+ def create_ccache_with_user(self, user_credentials, mach_credentials, >+ service="host", target_name=None): > # Obtain a service ticket authorising the user and place it into a > # newly created credentials cache file. > > user_name = user_credentials.get_username() > realm = user_credentials.get_realm() > >- # Do the initial AS-REQ, should get a pre-authentication required >- # response >- etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) > cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, > names=[user_name]) >- sname = self.PrincipalName_create(name_type=NT_SRV_HST, >- names=["krbtgt", realm]) >- >- rep = self.as_req(cname, sname, realm, etype) >- self.check_pre_authentication(rep) > >- # Do the next AS-REQ >- padata = self.get_enc_timestamp_pa_data(user_credentials, rep) >- key = self.get_as_rep_key(user_credentials, rep) >- rep = self.as_req(cname, sname, realm, etype, padata=[padata]) >- self.check_as_reply(rep) >+ tgt = self.get_tgt(user_credentials) > > # Request a ticket to the host service on the machine account >- ticket = rep['ticket'] >- enc_part = self.get_as_rep_enc_data(key, rep) >- key = self.EncryptionKey_import(enc_part['key']) >- cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, >- names=[user_name]) >- sname = self.PrincipalName_create(name_type=NT_SRV_HST, >- names=[service, mach_name]) >- >- (rep, enc_part) = self.tgs_req( >- cname, sname, realm, ticket, key, etype) >- self.check_tgs_reply(rep) >- key = self.EncryptionKey_import(enc_part['key']) >- >- # Check the contents of the pac, and the ticket >- ticket = rep['ticket'] >+ ticket = self.get_service_ticket(tgt, mach_credentials, >+ service=service, >+ target_name=target_name) > > # Write the ticket into a credentials cache file that can be ingested > # by the main credentials code. >- cachefile = self.create_ccache(cname, ticket, enc_part) >+ cachefile = self.create_ccache(cname, ticket.ticket, >+ ticket.encpart_private) > > # Create a credentials object to reference the credentials cache. > creds = Credentials() >diff --git a/python/samba/tests/krb5/test_ccache.py b/python/samba/tests/krb5/test_ccache.py >index 6a2b78398ac3..040ae5cc9a1f 100755 >--- a/python/samba/tests/krb5/test_ccache.py >+++ b/python/samba/tests/krb5/test_ccache.py >@@ -67,7 +67,7 @@ class CcacheTests(KDCBaseTest): > # ticket, to ensure that the krbtgt ticket doesn't also need to be > # stored. > (creds, cachefile) = self.create_ccache_with_user(user_credentials, >- mach_name) >+ mach_credentials) > > # Authenticate in-process to the machine account using the user's > # cached credentials. >diff --git a/python/samba/tests/krb5/test_ldap.py b/python/samba/tests/krb5/test_ldap.py >index 95b2d24221a0..7d9ffebe2985 100755 >--- a/python/samba/tests/krb5/test_ldap.py >+++ b/python/samba/tests/krb5/test_ldap.py >@@ -53,13 +53,16 @@ class LdapTests(KDCBaseTest): > # Create the user account. > (user_credentials, _) = self.create_account(samdb, user_name) > >+ mach_credentials = self.get_dc_creds() >+ > # Talk to the KDC to obtain the service ticket, which gets placed into > # the cache. The machine account name has to match the name in the > # ticket, to ensure that the krbtgt ticket doesn't also need to be > # stored. > (creds, cachefile) = self.create_ccache_with_user(user_credentials, >- mach_name, >- service) >+ mach_credentials, >+ service, >+ mach_name) > > # Authenticate in-process to the machine account using the user's > # cached credentials. >diff --git a/python/samba/tests/krb5/test_rpc.py b/python/samba/tests/krb5/test_rpc.py >index 40ac6df7a350..ef8dd4dcbf5b 100755 >--- a/python/samba/tests/krb5/test_rpc.py >+++ b/python/samba/tests/krb5/test_rpc.py >@@ -50,13 +50,16 @@ class RpcTests(KDCBaseTest): > # Create the user account. > (user_credentials, _) = self.create_account(samdb, user_name) > >+ mach_credentials = self.get_dc_creds() >+ > # Talk to the KDC to obtain the service ticket, which gets placed into > # the cache. The machine account name has to match the name in the > # ticket, to ensure that the krbtgt ticket doesn't also need to be > # stored. > (creds, cachefile) = self.create_ccache_with_user(user_credentials, >- mach_name, >- service) >+ mach_credentials, >+ service, >+ mach_name) > > # Authenticate in-process to the machine account using the user's > # cached credentials. >diff --git a/python/samba/tests/krb5/test_smb.py b/python/samba/tests/krb5/test_smb.py >index eebc9a9d4feb..1e70ed322bfc 100755 >--- a/python/samba/tests/krb5/test_smb.py >+++ b/python/samba/tests/krb5/test_smb.py >@@ -55,13 +55,16 @@ class SmbTests(KDCBaseTest): > # Create the user account. > (user_credentials, _) = self.create_account(samdb, user_name) > >+ mach_credentials = self.get_dc_creds() >+ > # Talk to the KDC to obtain the service ticket, which gets placed into > # the cache. The machine account name has to match the name in the > # ticket, to ensure that the krbtgt ticket doesn't also need to be > # stored. > (creds, cachefile) = self.create_ccache_with_user(user_credentials, >- mach_name, >- service) >+ mach_credentials, >+ service, >+ mach_name) > > # Set the Kerberos 5 credentials cache environment variable. This is > # required because the codepath that gets run (gse_krb5) looks for it >-- >2.25.1 > > >From 3da28b4f6fafbac3b7331f5aa432e3b3c835ee7f Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Fri, 22 Oct 2021 11:37:37 +1300 >Subject: [PATCH 109/262] CVE-2020-25719 CVE-2020-25717 tests/krb5: Allow > create_ccache_with_user() to return a ticket without a PAC > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14799 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_base_test.py | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > >diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py >index e77a940f4117..aed4c427ab08 100644 >--- a/python/samba/tests/krb5/kdc_base_test.py >+++ b/python/samba/tests/krb5/kdc_base_test.py >@@ -1672,7 +1672,7 @@ class KDCBaseTest(RawKerberosTest): > return cachefile > > def create_ccache_with_user(self, user_credentials, mach_credentials, >- service="host", target_name=None): >+ service="host", target_name=None, pac=True): > # Obtain a service ticket authorising the user and place it into a > # newly created credentials cache file. > >@@ -1689,6 +1689,9 @@ class KDCBaseTest(RawKerberosTest): > service=service, > target_name=target_name) > >+ if not pac: >+ ticket = self.modified_ticket(ticket, exclude_pac=True) >+ > # Write the ticket into a credentials cache file that can be ingested > # by the main credentials code. > cachefile = self.create_ccache(cname, ticket.ticket, >-- >2.25.1 > > >From fede1bf647ece40656040dc74499b9cc6cad88be Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Thu, 21 Oct 2021 15:45:00 +1300 >Subject: [PATCH 110/262] CVE-2020-25722 tests/krb5: Add KDC tests for 3-part > SPNs > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14776 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_base_test.py | 1 + > python/samba/tests/krb5/spn_tests.py | 212 +++++++++++++++++++++++ > python/samba/tests/usage.py | 1 + > selftest/knownfail_heimdal_kdc | 6 + > selftest/knownfail_mit_kdc | 6 + > source4/selftest/tests.py | 10 ++ > 6 files changed, 236 insertions(+) > create mode 100755 python/samba/tests/krb5/spn_tests.py > >diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py >index aed4c427ab08..cc23484ba2cb 100644 >--- a/python/samba/tests/krb5/kdc_base_test.py >+++ b/python/samba/tests/krb5/kdc_base_test.py >@@ -97,6 +97,7 @@ class KDCBaseTest(RawKerberosTest): > USER = auto() > COMPUTER = auto() > SERVER = auto() >+ RODC = auto() > > @classmethod > def setUpClass(cls): >diff --git a/python/samba/tests/krb5/spn_tests.py b/python/samba/tests/krb5/spn_tests.py >new file mode 100755 >index 000000000000..62d2ea081bca >--- /dev/null >+++ b/python/samba/tests/krb5/spn_tests.py >@@ -0,0 +1,212 @@ >+#!/usr/bin/env python3 >+# Unix SMB/CIFS implementation. >+# Copyright (C) Stefan Metzmacher 2020 >+# Copyright (C) 2020 Catalyst.Net Ltd >+# >+# This program is free software; you can redistribute it and/or modify >+# it under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# This program is distributed in the hope that it will be useful, >+# but WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with this program. If not, see <http://www.gnu.org/licenses/>. >+# >+ >+import os >+import sys >+ >+from samba.tests import DynamicTestCase >+ >+import ldb >+ >+from samba.tests.krb5.kdc_base_test import KDCBaseTest >+from samba.tests.krb5.raw_testcase import KerberosCredentials >+from samba.tests.krb5.rfc4120_constants import ( >+ AES256_CTS_HMAC_SHA1_96, >+ ARCFOUR_HMAC_MD5, >+ KDC_ERR_S_PRINCIPAL_UNKNOWN, >+ NT_PRINCIPAL, >+) >+ >+sys.path.insert(0, "bin/python") >+os.environ["PYTHONUNBUFFERED"] = "1" >+ >+global_asn1_print = False >+global_hexdump = False >+ >+ >+@DynamicTestCase >+class SpnTests(KDCBaseTest): >+ test_account_types = { >+ 'computer': KDCBaseTest.AccountType.COMPUTER, >+ 'server': KDCBaseTest.AccountType.SERVER, >+ 'rodc': KDCBaseTest.AccountType.RODC >+ } >+ test_spns = { >+ '2_part': 'ldap/{{account}}', >+ '3_part_our_domain': 'ldap/{{account}}/{netbios_domain_name}', >+ '3_part_our_realm': 'ldap/{{account}}/{dns_domain_name}', >+ '3_part_not_our_realm': 'ldap/{{account}}/test', >+ '3_part_instance': 'ldap/{{account}}:test/{dns_domain_name}' >+ } >+ >+ @classmethod >+ def setUpClass(cls): >+ super().setUpClass() >+ >+ cls._mock_rodc_creds = None >+ >+ @classmethod >+ def setUpDynamicTestCases(cls): >+ for account_type_name, account_type in cls.test_account_types.items(): >+ for spn_name, spn in cls.test_spns.items(): >+ tname = f'{spn_name}_spn_{account_type_name}' >+ targs = (account_type, spn) >+ cls.generate_dynamic_test('test_spn', tname, *targs) >+ >+ def _test_spn_with_args(self, account_type, spn): >+ target_creds = self._get_creds(account_type) >+ spn = self._format_spn(spn, target_creds) >+ >+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, >+ names=spn.split('/')) >+ >+ client_creds = self.get_client_creds() >+ tgt = self.get_tgt(client_creds) >+ >+ samdb = self.get_samdb() >+ netbios_domain_name = samdb.domain_netbios_name() >+ dns_domain_name = samdb.domain_dns_name() >+ >+ subkey = self.RandomKey(tgt.session_key.etype) >+ >+ etypes = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5,) >+ >+ if account_type is self.AccountType.SERVER: >+ ticket_etype = AES256_CTS_HMAC_SHA1_96 >+ else: >+ ticket_etype = None >+ decryption_key = self.TicketDecryptionKey_from_creds( >+ target_creds, etype=ticket_etype) >+ >+ if (spn.count('/') > 1 >+ and (spn.endswith(netbios_domain_name) >+ or spn.endswith(dns_domain_name)) >+ and account_type is not self.AccountType.SERVER >+ and account_type is not self.AccountType.RODC): >+ expected_error_mode = KDC_ERR_S_PRINCIPAL_UNKNOWN >+ check_error_fn = self.generic_check_kdc_error >+ check_rep_fn = None >+ else: >+ expected_error_mode = 0 >+ check_error_fn = None >+ check_rep_fn = self.generic_check_kdc_rep >+ >+ kdc_exchange_dict = self.tgs_exchange_dict( >+ expected_crealm=tgt.crealm, >+ expected_cname=tgt.cname, >+ expected_srealm=tgt.srealm, >+ expected_sname=sname, >+ ticket_decryption_key=decryption_key, >+ check_rep_fn=check_rep_fn, >+ check_error_fn=check_error_fn, >+ check_kdc_private_fn=self.generic_check_kdc_private, >+ expected_error_mode=expected_error_mode, >+ tgt=tgt, >+ authenticator_subkey=subkey, >+ kdc_options='0', >+ expect_edata=False) >+ >+ self._generic_kdc_exchange(kdc_exchange_dict, >+ cname=None, >+ realm=tgt.srealm, >+ sname=sname, >+ etypes=etypes) >+ >+ def setUp(self): >+ super().setUp() >+ self.do_asn1_print = global_asn1_print >+ self.do_hexdump = global_hexdump >+ >+ def _format_spns(self, spns, creds=None): >+ return map(lambda spn: self._format_spn(spn, creds), spns) >+ >+ def _format_spn(self, spn, creds=None): >+ samdb = self.get_samdb() >+ >+ spn = spn.format(netbios_domain_name=samdb.domain_netbios_name(), >+ dns_domain_name=samdb.domain_dns_name()) >+ >+ if creds is not None: >+ account_name = creds.get_username() >+ spn = spn.format(account=account_name) >+ >+ return spn >+ >+ def _get_creds(self, account_type): >+ spns = self._format_spns(self.test_spns.values()) >+ >+ if account_type is self.AccountType.RODC: >+ creds = self._mock_rodc_creds >+ if creds is None: >+ creds = self._get_mock_rodc_creds(spns) >+ type(self)._mock_rodc_creds = creds >+ else: >+ creds = self.get_cached_creds( >+ account_type=account_type, >+ opts={ >+ 'spn': spns >+ }) >+ >+ return creds >+ >+ def _get_mock_rodc_creds(self, spns): >+ rodc_ctx = self.get_mock_rodc_ctx() >+ >+ for spn in spns: >+ spn = spn.format(account=rodc_ctx.myname) >+ if spn not in rodc_ctx.SPNs: >+ rodc_ctx.SPNs.append(spn) >+ >+ samdb = self.get_samdb() >+ rodc_dn = ldb.Dn(samdb, rodc_ctx.acct_dn) >+ >+ msg = ldb.Message(rodc_dn) >+ msg['servicePrincipalName'] = ldb.MessageElement( >+ rodc_ctx.SPNs, >+ ldb.FLAG_MOD_REPLACE, >+ 'servicePrincipalName') >+ samdb.modify(msg) >+ >+ creds = KerberosCredentials() >+ creds.guess(self.get_lp()) >+ creds.set_realm(rodc_ctx.realm.upper()) >+ creds.set_domain(rodc_ctx.domain_name) >+ creds.set_password(rodc_ctx.acct_pass) >+ creds.set_username(rodc_ctx.myname) >+ creds.set_workstation(rodc_ctx.samname) >+ creds.set_dn(rodc_dn) >+ creds.set_spn(rodc_ctx.SPNs) >+ >+ res = samdb.search(base=rodc_dn, >+ scope=ldb.SCOPE_BASE, >+ attrs=['msDS-KeyVersionNumber']) >+ kvno = int(res[0].get('msDS-KeyVersionNumber', idx=0)) >+ creds.set_kvno(kvno) >+ >+ keys = self.get_keys(samdb, rodc_dn) >+ self.creds_set_keys(creds, keys) >+ >+ return creds >+ >+ >+if __name__ == "__main__": >+ global_asn1_print = False >+ global_hexdump = False >+ import unittest >+ unittest.main() >diff --git a/python/samba/tests/usage.py b/python/samba/tests/usage.py >index 4b68a2b798c2..7d11b6b46179 100644 >--- a/python/samba/tests/usage.py >+++ b/python/samba/tests/usage.py >@@ -104,6 +104,7 @@ EXCLUDE_USAGE = { > 'python/samba/tests/krb5/fast_tests.py', > 'python/samba/tests/krb5/rodc_tests.py', > 'python/samba/tests/krb5/salt_tests.py', >+ 'python/samba/tests/krb5/spn_tests.py', > } > > EXCLUDE_HELP = { >diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc >index b39b11c3c53d..45524d70fa29 100644 >--- a/selftest/knownfail_heimdal_kdc >+++ b/selftest/knownfail_heimdal_kdc >@@ -255,3 +255,9 @@ > ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_auth_data_required > ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_no_auth_data_required_a > ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_no_auth_data_required_b >+# >+# SPN tests >+# >+^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_instance_spn_computer >+^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_our_domain_spn_computer >+^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_our_realm_spn_computer >diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc >index 4fc68ffd854c..c86f9c2c2ea7 100644 >--- a/selftest/knownfail_mit_kdc >+++ b/selftest/knownfail_mit_kdc >@@ -374,3 +374,9 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > ^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2003dc > ^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008dc > ^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008r2dc >+# >+# SPN tests >+# >+^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_instance_spn_computer >+^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_our_domain_spn_computer >+^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_our_realm_spn_computer >diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py >index 640b085a9221..44bb50267c46 100755 >--- a/source4/selftest/tests.py >+++ b/source4/selftest/tests.py >@@ -1468,6 +1468,16 @@ planpythontestsuite( > 'FAST_SUPPORT': have_fast_support, > 'TKT_SIG_SUPPORT': tkt_sig_support > }) >+planpythontestsuite( >+ "ad_dc", >+ "samba.tests.krb5.spn_tests", >+ environ={ >+ 'ADMIN_USERNAME': '$USERNAME', >+ 'ADMIN_PASSWORD': '$PASSWORD', >+ 'STRICT_CHECKING': '0', >+ 'FAST_SUPPORT': have_fast_support, >+ 'TKT_SIG_SUPPORT': tkt_sig_support >+ }) > > for env in [ > 'vampire_dc', >-- >2.25.1 > > >From 8f41e6c6f7d348da14b8f5829028a4867f2b5259 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Wed, 13 Oct 2021 16:07:09 +1300 >Subject: [PATCH 111/262] CVE-2020-25721 ndrdump: Add tests for PAC with > UPN_DNS_INFO > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14835 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/blackbox/ndrdump.py | 35 +++ > .../tests/krb5pac_upn_dns_info_ex.b64.txt | 1 + > .../librpc/tests/krb5pac_upn_dns_info_ex.txt | 220 ++++++++++++++++++ > ...5pac_upn_dns_info_ex_not_supported.b64.txt | 1 + > .../krb5pac_upn_dns_info_ex_not_supported.txt | 213 +++++++++++++++++ > 5 files changed, 470 insertions(+) > create mode 100644 source4/librpc/tests/krb5pac_upn_dns_info_ex.b64.txt > create mode 100644 source4/librpc/tests/krb5pac_upn_dns_info_ex.txt > create mode 100644 source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.b64.txt > create mode 100644 source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.txt > >diff --git a/python/samba/tests/blackbox/ndrdump.py b/python/samba/tests/blackbox/ndrdump.py >index 7833ec981196..9a4e6cabe8b4 100644 >--- a/python/samba/tests/blackbox/ndrdump.py >+++ b/python/samba/tests/blackbox/ndrdump.py >@@ -90,6 +90,41 @@ class NdrDumpTests(BlackboxTestCase): > expected.encode('utf-8')) > self.assertTrue(actual.endswith(b"dump OK\n")) > >+ def test_ndrdump_upn_dns_info_ex(self): >+ with open(self.data_path( >+ 'krb5pac_upn_dns_info_ex.txt')) as f: >+ expected = f.read() >+ data_path = self.data_path( >+ 'krb5pac_upn_dns_info_ex.b64.txt') >+ >+ try: >+ actual = self.check_output( >+ 'ndrdump --debug-stdout -d0 krb5pac PAC_DATA struct ' >+ '--validate --base64-input ' + data_path) >+ except BlackboxProcessError as e: >+ self.fail(e) >+ >+ self.assertEqual(actual, expected.encode('utf-8')) >+ >+ def test_ndrdump_upn_dns_info_ex_not_supported(self): >+ with open(self.data_path( >+ 'krb5pac_upn_dns_info_ex_not_supported.txt')) as f: >+ expected = f.read() >+ data_path = self.data_path( >+ 'krb5pac_upn_dns_info_ex_not_supported.b64.txt') >+ >+ try: >+ # This PAC has been edited to remove the >+ # PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID bit, so that we can >+ # simulate older versions of Samba parsing this structure. >+ actual = self.check_output( >+ 'ndrdump --debug-stdout -d0 krb5pac PAC_DATA struct ' >+ '--validate --base64-input ' + data_path) >+ except BlackboxProcessError as e: >+ self.fail(e) >+ >+ self.assertEqual(actual, expected.encode('utf-8')) >+ > def test_ndrdump_with_binary_struct_number(self): > expected = '''pull returned Success > GUID : 33323130-3534-3736-3839-616263646566 >diff --git a/source4/librpc/tests/krb5pac_upn_dns_info_ex.b64.txt b/source4/librpc/tests/krb5pac_upn_dns_info_ex.b64.txt >new file mode 100644 >index 000000000000..02b570624bc5 >--- /dev/null >+++ b/source4/librpc/tests/krb5pac_upn_dns_info_ex.b64.txt >@@ -0,0 +1 @@ >+BgAAAAAAAAABAAAA0AEAAGgAAAAAAAAACgAAABwAAAA4AgAAAAAAAAwAAACoAAAAWAIAAAAAAAAGAAAAFAAAAAADAAAAAAAABwAAABAAAAAYAwAAAAAAABAAAAAQAAAAKAMAAAAAAAABEAgAzMzMzMABAAAAAAAAAAACAAAAAAAAAAAA/////////3//////////f7pMcCzXv9cBugzaVqDA1wG6zMkh2ODXARIAEgAEAAIAAAAAAAgAAgAAAAAADAACAAAAAAAQAAIAAAAAABQAAgAAAAAAGAACAAAAAACOBAAAAQIAAAEAAAAcAAIAIAAAAAAAAAAAAAAAAAAAAAAAAAAOABAAIAACABYAGAAkAAIAKAACAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAALAACAAAAAAAAAAAAAAAAAAkAAAAAAAAACQAAAHQAcwB0AHQAawB0AHUAcwByAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAECAAAHAAAACAAAAAAAAAAHAAAATABPAEMAQQBMAEQAQwAAAAwAAAAAAAAACwAAAFMAQQBNAEIAQQBEAE8ATQBBAEkATgAAAAQAAAABBAAAAAAABRUAAAC2fvX0wDGiOufKt1QBAAAAMAACAAcAAAABAAAAAQEAAAAAABIBAAAAAAAAAIC3ISzXv9cBEgB0AHMAdAB0AGsAdAB1AHMAcgAAAAAANgAYACIAUAADAAAAEgB4ABwAigAAAAAAdABzAHQAdABrAHQAdQBzAHIAQABzAGEAbQBiAGEALgBlAHgAYQBtAHAAbABlAC4AYwBvAG0AAABTAEEATQBCAEEALgBFAFgAQQBNAFAATABFAC4AQwBPAE0AAAAAAAAAdABzAHQAdABrAHQAdQBzAHIAAQUAAAAAAAUVAAAAtn719MAxojrnyrdUjgQAAAAAdv///ys5aox2KdqNY8CVVxkQbs4AAAAAEAAAAFrUeP0b8Pbct0VlVhAAAAB4SC+IGKoLP+0030o= >diff --git a/source4/librpc/tests/krb5pac_upn_dns_info_ex.txt b/source4/librpc/tests/krb5pac_upn_dns_info_ex.txt >new file mode 100644 >index 000000000000..9747d1b6d3a4 >--- /dev/null >+++ b/source4/librpc/tests/krb5pac_upn_dns_info_ex.txt >@@ -0,0 +1,220 @@ >+pull returned Success >+ PAC_DATA: struct PAC_DATA >+ num_buffers : 0x00000006 (6) >+ version : 0x00000000 (0) >+ buffers: ARRAY(6) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_LOGON_INFO (1) >+ _ndr_size : 0x000001d0 (464) >+ info : * >+ info : union PAC_INFO(case 1) >+ logon_info: struct PAC_LOGON_INFO_CTR >+ info : * >+ info: struct PAC_LOGON_INFO >+ info3: struct netr_SamInfo3 >+ base: struct netr_SamBaseInfo >+ logon_time : NTTIME(0) >+ logoff_time : Thu Sep 14 02:48:05 AM 30828 UTC >+ kickoff_time : Thu Sep 14 02:48:05 AM 30828 UTC >+ last_password_change : Wed Oct 13 02:08:12 AM 2021 UTC >+ allow_password_change : Thu Oct 14 02:08:12 AM 2021 UTC >+ force_password_change : Wed Nov 24 02:08:12 AM 2021 UTC >+ account_name: struct lsa_String >+ length : 0x0012 (18) >+ size : 0x0012 (18) >+ string : * >+ string : 'tsttktusr' >+ full_name: struct lsa_String >+ length : 0x0000 (0) >+ size : 0x0000 (0) >+ string : * >+ string : '' >+ logon_script: struct lsa_String >+ length : 0x0000 (0) >+ size : 0x0000 (0) >+ string : * >+ string : '' >+ profile_path: struct lsa_String >+ length : 0x0000 (0) >+ size : 0x0000 (0) >+ string : * >+ string : '' >+ home_directory: struct lsa_String >+ length : 0x0000 (0) >+ size : 0x0000 (0) >+ string : * >+ string : '' >+ home_drive: struct lsa_String >+ length : 0x0000 (0) >+ size : 0x0000 (0) >+ string : * >+ string : '' >+ logon_count : 0x0000 (0) >+ bad_password_count : 0x0000 (0) >+ rid : 0x0000048e (1166) >+ primary_gid : 0x00000201 (513) >+ groups: struct samr_RidWithAttributeArray >+ count : 0x00000001 (1) >+ rids : * >+ rids: ARRAY(1) >+ rids: struct samr_RidWithAttribute >+ rid : 0x00000201 (513) >+ attributes : 0x00000007 (7) >+ 1: SE_GROUP_MANDATORY >+ 1: SE_GROUP_ENABLED_BY_DEFAULT >+ 1: SE_GROUP_ENABLED >+ 0: SE_GROUP_OWNER >+ 0: SE_GROUP_USE_FOR_DENY_ONLY >+ 0: SE_GROUP_INTEGRITY >+ 0: SE_GROUP_INTEGRITY_ENABLED >+ 0: SE_GROUP_RESOURCE >+ 0x00: SE_GROUP_LOGON_ID (0) >+ user_flags : 0x00000020 (32) >+ 0: NETLOGON_GUEST >+ 0: NETLOGON_NOENCRYPTION >+ 0: NETLOGON_CACHED_ACCOUNT >+ 0: NETLOGON_USED_LM_PASSWORD >+ 1: NETLOGON_EXTRA_SIDS >+ 0: NETLOGON_SUBAUTH_SESSION_KEY >+ 0: NETLOGON_SERVER_TRUST_ACCOUNT >+ 0: NETLOGON_NTLMV2_ENABLED >+ 0: NETLOGON_RESOURCE_GROUPS >+ 0: NETLOGON_PROFILE_PATH_RETURNED >+ 0: NETLOGON_GRACE_LOGON >+ key: struct netr_UserSessionKey >+ key: ARRAY(16): <REDACTED SECRET VALUES> >+ logon_server: struct lsa_StringLarge >+ length : 0x000e (14) >+ size : 0x0010 (16) >+ string : * >+ string : 'LOCALDC' >+ logon_domain: struct lsa_StringLarge >+ length : 0x0016 (22) >+ size : 0x0018 (24) >+ string : * >+ string : 'SAMBADOMAIN' >+ domain_sid : * >+ domain_sid : S-1-5-21-4109729462-983708096-1421331175 >+ LMSessKey: struct netr_LMSessionKey >+ key: ARRAY(8): <REDACTED SECRET VALUES> >+ acct_flags : 0x00000010 (16) >+ 0: ACB_DISABLED >+ 0: ACB_HOMDIRREQ >+ 0: ACB_PWNOTREQ >+ 0: ACB_TEMPDUP >+ 1: ACB_NORMAL >+ 0: ACB_MNS >+ 0: ACB_DOMTRUST >+ 0: ACB_WSTRUST >+ 0: ACB_SVRTRUST >+ 0: ACB_PWNOEXP >+ 0: ACB_AUTOLOCK >+ 0: ACB_ENC_TXT_PWD_ALLOWED >+ 0: ACB_SMARTCARD_REQUIRED >+ 0: ACB_TRUSTED_FOR_DELEGATION >+ 0: ACB_NOT_DELEGATED >+ 0: ACB_USE_DES_KEY_ONLY >+ 0: ACB_DONT_REQUIRE_PREAUTH >+ 0: ACB_PW_EXPIRED >+ 0: ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION >+ 0: ACB_NO_AUTH_DATA_REQD >+ 0: ACB_PARTIAL_SECRETS_ACCOUNT >+ 0: ACB_USE_AES_KEYS >+ sub_auth_status : 0x00000000 (0) >+ last_successful_logon : NTTIME(0) >+ last_failed_logon : NTTIME(0) >+ failed_logon_count : 0x00000000 (0) >+ reserved : 0x00000000 (0) >+ sidcount : 0x00000001 (1) >+ sids : * >+ sids: ARRAY(1) >+ sids: struct netr_SidAttr >+ sid : * >+ sid : S-1-18-1 >+ attributes : 0x00000007 (7) >+ 1: SE_GROUP_MANDATORY >+ 1: SE_GROUP_ENABLED_BY_DEFAULT >+ 1: SE_GROUP_ENABLED >+ 0: SE_GROUP_OWNER >+ 0: SE_GROUP_USE_FOR_DENY_ONLY >+ 0: SE_GROUP_INTEGRITY >+ 0: SE_GROUP_INTEGRITY_ENABLED >+ 0: SE_GROUP_RESOURCE >+ 0x00: SE_GROUP_LOGON_ID (0) >+ resource_groups: struct PAC_DOMAIN_GROUP_MEMBERSHIP >+ domain_sid : NULL >+ groups: struct samr_RidWithAttributeArray >+ count : 0x00000000 (0) >+ rids : NULL >+ _pad : 0x00000000 (0) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_LOGON_NAME (10) >+ _ndr_size : 0x0000001c (28) >+ info : * >+ info : union PAC_INFO(case 10) >+ logon_name: struct PAC_LOGON_NAME >+ logon_time : Wed Oct 13 02:08:11 AM 2021 UTC >+ size : 0x0012 (18) >+ account_name : 'tsttktusr' >+ _pad : 0x00000000 (0) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_UPN_DNS_INFO (12) >+ _ndr_size : 0x000000a8 (168) >+ info : * >+ info : union PAC_INFO(case 12) >+ upn_dns_info: struct PAC_UPN_DNS_INFO >+ upn_name_size : 0x0036 (54) >+ upn_name : * >+ upn_name : 'tsttktusr@samba.example.com' >+ dns_domain_name_size : 0x0022 (34) >+ dns_domain_name : * >+ dns_domain_name : 'SAMBA.EXAMPLE.COM' >+ flags : 0x00000003 (3) >+ 1: PAC_UPN_DNS_FLAG_CONSTRUCTED >+ 1: PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID >+ ex : union PAC_UPN_DNS_INFO_EX(case 2) >+ sam_name_and_sid: struct PAC_UPN_DNS_INFO_SAM_NAME_AND_SID >+ samaccountname_size : 0x0012 (18) >+ samaccountname : * >+ samaccountname : 'tsttktusr' >+ objectsid_size : 0x001c (28) >+ objectsid : * >+ objectsid : S-1-5-21-4109729462-983708096-1421331175-1166 >+ _pad : 0x00000000 (0) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_SRV_CHECKSUM (6) >+ _ndr_size : 0x00000014 (20) >+ info : * >+ info : union PAC_INFO(case 6) >+ srv_cksum: struct PAC_SIGNATURE_DATA >+ type : 0xffffff76 (4294967158) >+ signature : DATA_BLOB length=16 >+[0000] 2B 39 6A 8C 76 29 DA 8D 63 C0 95 57 19 10 6E CE +9j.v).. c..W..n. >+ _pad : 0x00000000 (0) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_KDC_CHECKSUM (7) >+ _ndr_size : 0x00000010 (16) >+ info : * >+ info : union PAC_INFO(case 7) >+ kdc_cksum: struct PAC_SIGNATURE_DATA >+ type : 0x00000010 (16) >+ signature : DATA_BLOB length=12 >+[0000] 5A D4 78 FD 1B F0 F6 DC B7 45 65 56 Z.x..... .EeV >+ _pad : 0x00000000 (0) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_TICKET_CHECKSUM (16) >+ _ndr_size : 0x00000010 (16) >+ info : * >+ info : union PAC_INFO(case 16) >+ ticket_checksum: struct PAC_SIGNATURE_DATA >+ type : 0x00000010 (16) >+ signature : DATA_BLOB length=12 >+[0000] 78 48 2F 88 18 AA 0B 3F ED 34 DF 4A xH/....? .4.J >+ _pad : 0x00000000 (0) >+push returned Success >+pull returned Success >+WARNING! orig bytes:824 validated pushed bytes:832 >+WARNING! orig pulled bytes:824 validated pulled bytes:832 >+WARNING! orig and validated differ at byte 0x2C (44) >+WARNING! orig byte[0x2C] = 0xA8 validated byte[0x2C] = 0xB0 >+dump OK >diff --git a/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.b64.txt b/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.b64.txt >new file mode 100644 >index 000000000000..cd99b9d0b0ad >--- /dev/null >+++ b/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.b64.txt >@@ -0,0 +1 @@ >+BgAAAAAAAAABAAAA0AEAAGgAAAAAAAAACgAAABwAAAA4AgAAAAAAAAwAAACoAAAAWAIAAAAAAAAGAAAAFAAAAAADAAAAAAAABwAAABAAAAAYAwAAAAAAABAAAAAQAAAAKAMAAAAAAAABEAgAzMzMzMABAAAAAAAAAAACAAAAAAAAAAAA/////////3//////////f7pMcCzXv9cBugzaVqDA1wG6zMkh2ODXARIAEgAEAAIAAAAAAAgAAgAAAAAADAACAAAAAAAQAAIAAAAAABQAAgAAAAAAGAACAAAAAACOBAAAAQIAAAEAAAAcAAIAIAAAAAAAAAAAAAAAAAAAAAAAAAAOABAAIAACABYAGAAkAAIAKAACAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAALAACAAAAAAAAAAAAAAAAAAkAAAAAAAAACQAAAHQAcwB0AHQAawB0AHUAcwByAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAECAAAHAAAACAAAAAAAAAAHAAAATABPAEMAQQBMAEQAQwAAAAwAAAAAAAAACwAAAFMAQQBNAEIAQQBEAE8ATQBBAEkATgAAAAQAAAABBAAAAAAABRUAAAC2fvX0wDGiOufKt1QBAAAAMAACAAcAAAABAAAAAQEAAAAAABIBAAAAAAAAAIC3ISzXv9cBEgB0AHMAdAB0AGsAdAB1AHMAcgAAAAAANgAYACIAUAABAAAAEgB4ABwAigAAAAAAdABzAHQAdABrAHQAdQBzAHIAQABzAGEAbQBiAGEALgBlAHgAYQBtAHAAbABlAC4AYwBvAG0AAABTAEEATQBCAEEALgBFAFgAQQBNAFAATABFAC4AQwBPAE0AAAAAAAAAdABzAHQAdABrAHQAdQBzAHIAAQUAAAAAAAUVAAAAtn719MAxojrnyrdUjgQAAAAAdv///ys5aox2KdqNY8CVVxkQbs4AAAAAEAAAAFrUeP0b8Pbct0VlVhAAAAB4SC+IGKoLP+0030o= >diff --git a/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.txt b/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.txt >new file mode 100644 >index 000000000000..d29832ede499 >--- /dev/null >+++ b/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.txt >@@ -0,0 +1,213 @@ >+pull returned Success >+ PAC_DATA: struct PAC_DATA >+ num_buffers : 0x00000006 (6) >+ version : 0x00000000 (0) >+ buffers: ARRAY(6) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_LOGON_INFO (1) >+ _ndr_size : 0x000001d0 (464) >+ info : * >+ info : union PAC_INFO(case 1) >+ logon_info: struct PAC_LOGON_INFO_CTR >+ info : * >+ info: struct PAC_LOGON_INFO >+ info3: struct netr_SamInfo3 >+ base: struct netr_SamBaseInfo >+ logon_time : NTTIME(0) >+ logoff_time : Thu Sep 14 02:48:05 AM 30828 UTC >+ kickoff_time : Thu Sep 14 02:48:05 AM 30828 UTC >+ last_password_change : Wed Oct 13 02:08:12 AM 2021 UTC >+ allow_password_change : Thu Oct 14 02:08:12 AM 2021 UTC >+ force_password_change : Wed Nov 24 02:08:12 AM 2021 UTC >+ account_name: struct lsa_String >+ length : 0x0012 (18) >+ size : 0x0012 (18) >+ string : * >+ string : 'tsttktusr' >+ full_name: struct lsa_String >+ length : 0x0000 (0) >+ size : 0x0000 (0) >+ string : * >+ string : '' >+ logon_script: struct lsa_String >+ length : 0x0000 (0) >+ size : 0x0000 (0) >+ string : * >+ string : '' >+ profile_path: struct lsa_String >+ length : 0x0000 (0) >+ size : 0x0000 (0) >+ string : * >+ string : '' >+ home_directory: struct lsa_String >+ length : 0x0000 (0) >+ size : 0x0000 (0) >+ string : * >+ string : '' >+ home_drive: struct lsa_String >+ length : 0x0000 (0) >+ size : 0x0000 (0) >+ string : * >+ string : '' >+ logon_count : 0x0000 (0) >+ bad_password_count : 0x0000 (0) >+ rid : 0x0000048e (1166) >+ primary_gid : 0x00000201 (513) >+ groups: struct samr_RidWithAttributeArray >+ count : 0x00000001 (1) >+ rids : * >+ rids: ARRAY(1) >+ rids: struct samr_RidWithAttribute >+ rid : 0x00000201 (513) >+ attributes : 0x00000007 (7) >+ 1: SE_GROUP_MANDATORY >+ 1: SE_GROUP_ENABLED_BY_DEFAULT >+ 1: SE_GROUP_ENABLED >+ 0: SE_GROUP_OWNER >+ 0: SE_GROUP_USE_FOR_DENY_ONLY >+ 0: SE_GROUP_INTEGRITY >+ 0: SE_GROUP_INTEGRITY_ENABLED >+ 0: SE_GROUP_RESOURCE >+ 0x00: SE_GROUP_LOGON_ID (0) >+ user_flags : 0x00000020 (32) >+ 0: NETLOGON_GUEST >+ 0: NETLOGON_NOENCRYPTION >+ 0: NETLOGON_CACHED_ACCOUNT >+ 0: NETLOGON_USED_LM_PASSWORD >+ 1: NETLOGON_EXTRA_SIDS >+ 0: NETLOGON_SUBAUTH_SESSION_KEY >+ 0: NETLOGON_SERVER_TRUST_ACCOUNT >+ 0: NETLOGON_NTLMV2_ENABLED >+ 0: NETLOGON_RESOURCE_GROUPS >+ 0: NETLOGON_PROFILE_PATH_RETURNED >+ 0: NETLOGON_GRACE_LOGON >+ key: struct netr_UserSessionKey >+ key: ARRAY(16): <REDACTED SECRET VALUES> >+ logon_server: struct lsa_StringLarge >+ length : 0x000e (14) >+ size : 0x0010 (16) >+ string : * >+ string : 'LOCALDC' >+ logon_domain: struct lsa_StringLarge >+ length : 0x0016 (22) >+ size : 0x0018 (24) >+ string : * >+ string : 'SAMBADOMAIN' >+ domain_sid : * >+ domain_sid : S-1-5-21-4109729462-983708096-1421331175 >+ LMSessKey: struct netr_LMSessionKey >+ key: ARRAY(8): <REDACTED SECRET VALUES> >+ acct_flags : 0x00000010 (16) >+ 0: ACB_DISABLED >+ 0: ACB_HOMDIRREQ >+ 0: ACB_PWNOTREQ >+ 0: ACB_TEMPDUP >+ 1: ACB_NORMAL >+ 0: ACB_MNS >+ 0: ACB_DOMTRUST >+ 0: ACB_WSTRUST >+ 0: ACB_SVRTRUST >+ 0: ACB_PWNOEXP >+ 0: ACB_AUTOLOCK >+ 0: ACB_ENC_TXT_PWD_ALLOWED >+ 0: ACB_SMARTCARD_REQUIRED >+ 0: ACB_TRUSTED_FOR_DELEGATION >+ 0: ACB_NOT_DELEGATED >+ 0: ACB_USE_DES_KEY_ONLY >+ 0: ACB_DONT_REQUIRE_PREAUTH >+ 0: ACB_PW_EXPIRED >+ 0: ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION >+ 0: ACB_NO_AUTH_DATA_REQD >+ 0: ACB_PARTIAL_SECRETS_ACCOUNT >+ 0: ACB_USE_AES_KEYS >+ sub_auth_status : 0x00000000 (0) >+ last_successful_logon : NTTIME(0) >+ last_failed_logon : NTTIME(0) >+ failed_logon_count : 0x00000000 (0) >+ reserved : 0x00000000 (0) >+ sidcount : 0x00000001 (1) >+ sids : * >+ sids: ARRAY(1) >+ sids: struct netr_SidAttr >+ sid : * >+ sid : S-1-18-1 >+ attributes : 0x00000007 (7) >+ 1: SE_GROUP_MANDATORY >+ 1: SE_GROUP_ENABLED_BY_DEFAULT >+ 1: SE_GROUP_ENABLED >+ 0: SE_GROUP_OWNER >+ 0: SE_GROUP_USE_FOR_DENY_ONLY >+ 0: SE_GROUP_INTEGRITY >+ 0: SE_GROUP_INTEGRITY_ENABLED >+ 0: SE_GROUP_RESOURCE >+ 0x00: SE_GROUP_LOGON_ID (0) >+ resource_groups: struct PAC_DOMAIN_GROUP_MEMBERSHIP >+ domain_sid : NULL >+ groups: struct samr_RidWithAttributeArray >+ count : 0x00000000 (0) >+ rids : NULL >+ _pad : 0x00000000 (0) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_LOGON_NAME (10) >+ _ndr_size : 0x0000001c (28) >+ info : * >+ info : union PAC_INFO(case 10) >+ logon_name: struct PAC_LOGON_NAME >+ logon_time : Wed Oct 13 02:08:11 AM 2021 UTC >+ size : 0x0012 (18) >+ account_name : 'tsttktusr' >+ _pad : 0x00000000 (0) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_UPN_DNS_INFO (12) >+ _ndr_size : 0x000000a8 (168) >+ info : * >+ info : union PAC_INFO(case 12) >+ upn_dns_info: struct PAC_UPN_DNS_INFO >+ upn_name_size : 0x0036 (54) >+ upn_name : * >+ upn_name : 'tsttktusr@samba.example.com' >+ dns_domain_name_size : 0x0022 (34) >+ dns_domain_name : * >+ dns_domain_name : 'SAMBA.EXAMPLE.COM' >+ flags : 0x00000001 (1) >+ 1: PAC_UPN_DNS_FLAG_CONSTRUCTED >+ 0: PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID >+ ex : union PAC_UPN_DNS_INFO_EX(case 0) >+ _pad : 0x00000000 (0) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_SRV_CHECKSUM (6) >+ _ndr_size : 0x00000014 (20) >+ info : * >+ info : union PAC_INFO(case 6) >+ srv_cksum: struct PAC_SIGNATURE_DATA >+ type : 0xffffff76 (4294967158) >+ signature : DATA_BLOB length=16 >+[0000] 2B 39 6A 8C 76 29 DA 8D 63 C0 95 57 19 10 6E CE +9j.v).. c..W..n. >+ _pad : 0x00000000 (0) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_KDC_CHECKSUM (7) >+ _ndr_size : 0x00000010 (16) >+ info : * >+ info : union PAC_INFO(case 7) >+ kdc_cksum: struct PAC_SIGNATURE_DATA >+ type : 0x00000010 (16) >+ signature : DATA_BLOB length=12 >+[0000] 5A D4 78 FD 1B F0 F6 DC B7 45 65 56 Z.x..... .EeV >+ _pad : 0x00000000 (0) >+ buffers: struct PAC_BUFFER >+ type : PAC_TYPE_TICKET_CHECKSUM (16) >+ _ndr_size : 0x00000010 (16) >+ info : * >+ info : union PAC_INFO(case 16) >+ ticket_checksum: struct PAC_SIGNATURE_DATA >+ type : 0x00000010 (16) >+ signature : DATA_BLOB length=12 >+[0000] 78 48 2F 88 18 AA 0B 3F ED 34 DF 4A xH/....? .4.J >+ _pad : 0x00000000 (0) >+push returned Success >+pull returned Success >+WARNING! orig bytes:824 validated pushed bytes:768 >+WARNING! orig pulled bytes:824 validated pulled bytes:768 >+WARNING! orig and validated differ at byte 0x2C (44) >+WARNING! orig byte[0x2C] = 0xA8 validated byte[0x2C] = 0x70 >+dump OK >-- >2.25.1 > > >From 3a9031799ee5b6a88df13e10943234e86ab9ab31 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Mon, 18 Oct 2021 15:02:39 +1300 >Subject: [PATCH 112/262] CVE-2020-25719 tests/krb5: Add tests for requiring > and issuing a PAC > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_tgs_tests.py | 124 ++++++++++++++++++++--- > selftest/knownfail_heimdal_kdc | 9 ++ > selftest/knownfail_mit_kdc | 6 ++ > 3 files changed, 123 insertions(+), 16 deletions(-) > >diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py >index f36704f998cf..fbeb5fe61fbb 100755 >--- a/python/samba/tests/krb5/kdc_tgs_tests.py >+++ b/python/samba/tests/krb5/kdc_tgs_tests.py >@@ -31,6 +31,7 @@ from samba.tests.krb5.rfc4120_constants import ( > KRB_ERROR, > KRB_TGS_REP, > KDC_ERR_BADMATCH, >+ KDC_ERR_BADOPTION, > NT_PRINCIPAL, > NT_SRV_INST, > ) >@@ -214,7 +215,8 @@ class KdcTgsTests(KDCBaseTest): > "rep = {%s},%s" % (rep, pac_data)) > > def _make_tgs_request(self, client_creds, service_creds, tgt, >- expect_pac=True): >+ pac_request=None, expect_pac=True, >+ expect_error=False): > client_account = client_creds.get_username() > cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, > names=[client_account]) >@@ -241,6 +243,15 @@ class KdcTgsTests(KDCBaseTest): > > authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256) > >+ if expect_error: >+ expected_error_mode = KDC_ERR_BADOPTION >+ check_error_fn = self.generic_check_kdc_error >+ check_rep_fn = None >+ else: >+ expected_error_mode = 0 >+ check_error_fn = None >+ check_rep_fn = self.generic_check_kdc_rep >+ > kdc_exchange_dict = self.tgs_exchange_dict( > expected_crealm=expected_crealm, > expected_cname=expected_cname, >@@ -248,12 +259,14 @@ class KdcTgsTests(KDCBaseTest): > expected_sname=expected_sname, > expected_supported_etypes=expected_supported_etypes, > ticket_decryption_key=target_decryption_key, >- check_rep_fn=self.generic_check_kdc_rep, >+ check_error_fn=check_error_fn, >+ check_rep_fn=check_rep_fn, > check_kdc_private_fn=self.generic_check_kdc_private, >- expected_error_mode=0, >+ expected_error_mode=expected_error_mode, > tgt=tgt, > authenticator_subkey=authenticator_subkey, > kdc_options=kdc_options, >+ pac_request=pac_request, > expect_pac=expect_pac) > > rep = self._generic_kdc_exchange(kdc_exchange_dict, >@@ -261,25 +274,43 @@ class KdcTgsTests(KDCBaseTest): > realm=realm, > sname=sname, > etypes=etypes) >- self.check_reply(rep, KRB_TGS_REP) >+ if expect_error: >+ self.check_error_rep(rep, expected_error_mode) >+ >+ return None >+ else: >+ self.check_reply(rep, KRB_TGS_REP) >+ >+ return kdc_exchange_dict['rep_ticket_creds'] >+ >+ def test_request(self): >+ client_creds = self.get_client_creds() >+ service_creds = self.get_service_creds() >+ >+ tgt = self.get_tgt(client_creds) >+ >+ pac = self.get_ticket_pac(tgt) >+ self.assertIsNotNone(pac) >+ >+ ticket = self._make_tgs_request(client_creds, service_creds, tgt) > >- return kdc_exchange_dict['rep_ticket_creds'] >+ pac = self.get_ticket_pac(ticket) >+ self.assertIsNotNone(pac) > > def test_request_no_pac(self): > client_creds = self.get_client_creds() > service_creds = self.get_service_creds() > >- tgt = self.get_tgt(client_creds, pac_request=False, >- expect_pac=False) >+ tgt = self.get_tgt(client_creds, pac_request=False) > >- pac = self.get_ticket_pac(tgt, expect_pac=False) >- self.assertIsNone(pac) >+ pac = self.get_ticket_pac(tgt) >+ self.assertIsNotNone(pac) > > ticket = self._make_tgs_request(client_creds, service_creds, tgt, >- expect_pac=False) >+ pac_request=False) > >- pac = self.get_ticket_pac(ticket, expect_pac=False) >- self.assertIsNone(pac) >+ pac = self.get_ticket_pac(ticket) >+ self.assertIsNotNone(pac) > > def test_client_no_auth_data_required(self): > client_creds = self.get_cached_creds( >@@ -297,6 +328,23 @@ class KdcTgsTests(KDCBaseTest): > pac = self.get_ticket_pac(ticket) > self.assertIsNotNone(pac) > >+ def test_no_pac_client_no_auth_data_required(self): >+ client_creds = self.get_cached_creds( >+ account_type=self.AccountType.USER, >+ opts={'no_auth_data_required': True}) >+ service_creds = self.get_service_creds() >+ >+ tgt = self.get_tgt(client_creds, pac_request=False) >+ >+ pac = self.get_ticket_pac(tgt) >+ self.assertIsNotNone(pac) >+ >+ ticket = self._make_tgs_request(client_creds, service_creds, tgt, >+ pac_request=False) >+ >+ pac = self.get_ticket_pac(ticket) >+ self.assertIsNotNone(pac) >+ > def test_service_no_auth_data_required(self): > client_creds = self.get_client_creds() > service_creds = self.get_cached_creds( >@@ -314,8 +362,42 @@ class KdcTgsTests(KDCBaseTest): > pac = self.get_ticket_pac(ticket, expect_pac=False) > self.assertIsNone(pac) > >- def test_remove_pac(self): >+ def test_no_pac_service_no_auth_data_required(self): > client_creds = self.get_client_creds() >+ service_creds = self.get_cached_creds( >+ account_type=self.AccountType.COMPUTER, >+ opts={'no_auth_data_required': True}) >+ >+ tgt = self.get_tgt(client_creds, pac_request=False) >+ >+ pac = self.get_ticket_pac(tgt) >+ self.assertIsNotNone(pac) >+ >+ ticket = self._make_tgs_request(client_creds, service_creds, tgt, >+ pac_request=False, expect_pac=False) >+ >+ pac = self.get_ticket_pac(ticket, expect_pac=False) >+ self.assertIsNone(pac) >+ >+ def test_remove_pac_service_no_auth_data_required(self): >+ client_creds = self.get_client_creds() >+ service_creds = self.get_cached_creds( >+ account_type=self.AccountType.COMPUTER, >+ opts={'no_auth_data_required': True}) >+ >+ tgt = self.modified_ticket(self.get_tgt(client_creds), >+ exclude_pac=True) >+ >+ pac = self.get_ticket_pac(tgt, expect_pac=False) >+ self.assertIsNone(pac) >+ >+ self._make_tgs_request(client_creds, service_creds, tgt, >+ expect_pac=False, expect_error=True) >+ >+ def test_remove_pac_client_no_auth_data_required(self): >+ client_creds = self.get_cached_creds( >+ account_type=self.AccountType.USER, >+ opts={'no_auth_data_required': True}) > service_creds = self.get_service_creds() > > tgt = self.modified_ticket(self.get_tgt(client_creds), >@@ -324,12 +406,22 @@ class KdcTgsTests(KDCBaseTest): > pac = self.get_ticket_pac(tgt, expect_pac=False) > self.assertIsNone(pac) > >- ticket = self._make_tgs_request(client_creds, service_creds, tgt, >- expect_pac=False) >+ self._make_tgs_request(client_creds, service_creds, tgt, >+ expect_pac=False, expect_error=True) > >- pac = self.get_ticket_pac(ticket, expect_pac=False) >+ def test_remove_pac(self): >+ client_creds = self.get_client_creds() >+ service_creds = self.get_service_creds() >+ >+ tgt = self.modified_ticket(self.get_tgt(client_creds), >+ exclude_pac=True) >+ >+ pac = self.get_ticket_pac(tgt, expect_pac=False) > self.assertIsNone(pac) > >+ self._make_tgs_request(client_creds, service_creds, tgt, >+ expect_pac=False, expect_error=True) >+ > > if __name__ == "__main__": > global_asn1_print = False >diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc >index 45524d70fa29..410ba83123c8 100644 >--- a/selftest/knownfail_heimdal_kdc >+++ b/selftest/knownfail_heimdal_kdc >@@ -261,3 +261,12 @@ > ^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_instance_spn_computer > ^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_our_domain_spn_computer > ^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_our_realm_spn_computer >+# >+# KDC TGS PAC tests >+# >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_no_pac_client_no_auth_data_required >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_no_pac_service_no_auth_data_required >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_client_no_auth_data_required >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_service_no_auth_data_required >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_request_no_pac >diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc >index c86f9c2c2ea7..8612d05b3da6 100644 >--- a/selftest/knownfail_mit_kdc >+++ b/selftest/knownfail_mit_kdc >@@ -276,7 +276,13 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_ldap_service_ticket\(ad_dc\) > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_get_ticket_for_host_service_of_machine_account\(ad_dc\) > # >+# KDC TGS PAC tests >+# >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_no_pac_client_no_auth_data_required\(ad_dc\) >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_no_pac_service_no_auth_data_required\(ad_dc\) > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac\(ad_dc\) >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_client_no_auth_data_required\(ad_dc\) >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_service_no_auth_data_required\(ad_dc\) > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_request_no_pac\(ad_dc\) > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_service_no_auth_data_required\(ad_dc\) > # >-- >2.25.1 > > >From 25d0d180ba8d53dff8c63e139f14c5cffee60bf6 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Tue, 19 Oct 2021 14:39:36 +1300 >Subject: [PATCH 113/262] CVE-2020-25719 tests/krb5: Add a test for making an > S4U2Self request without a PAC > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14686 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/s4u_tests.py | 37 ++++++++++++++++++++++++++-- > selftest/knownfail_heimdal_kdc | 1 + > 2 files changed, 36 insertions(+), 2 deletions(-) > >diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py >index 593ef94c9103..a80a7b3427e0 100755 >--- a/python/samba/tests/krb5/s4u_tests.py >+++ b/python/samba/tests/krb5/s4u_tests.py >@@ -256,6 +256,17 @@ class S4UKerberosTests(KDCBaseTest): > if unexpected_flags is not None: > unexpected_flags = krb5_asn1.TicketFlags(unexpected_flags) > >+ expected_error_mode = kdc_dict.pop('expected_error_mode', 0) >+ expected_status = kdc_dict.pop('expected_status', None) >+ if expected_error_mode: >+ check_error_fn = self.generic_check_kdc_error >+ check_rep_fn = None >+ else: >+ check_error_fn = None >+ check_rep_fn = self.generic_check_kdc_rep >+ >+ self.assertIsNone(expected_status) >+ > kdc_options = kdc_dict.pop('kdc_options', '0') > kdc_options = krb5_asn1.KDCOptions(kdc_options) > >@@ -290,9 +301,11 @@ class S4UKerberosTests(KDCBaseTest): > ticket_decryption_key=service_decryption_key, > expect_ticket_checksum=True, > generate_padata_fn=generate_s4u2self_padata, >- check_rep_fn=self.generic_check_kdc_rep, >+ check_error_fn=check_error_fn, >+ check_rep_fn=check_rep_fn, > check_kdc_private_fn=self.generic_check_kdc_private, >- expected_error_mode=0, >+ expected_error_mode=expected_error_mode, >+ expected_status=expected_status, > tgt=service_tgt, > authenticator_subkey=authenticator_subkey, > kdc_options=str(kdc_options), >@@ -321,6 +334,26 @@ class S4UKerberosTests(KDCBaseTest): > 'expected_flags': 'forwardable' > }) > >+ # Test performing an S4U2Self operation with a forwardable ticket that does >+ # not contain a PAC. The request should fail. >+ def test_s4u2self_no_pac(self): >+ def forwardable_no_pac(ticket): >+ ticket = self.set_ticket_forwardable(ticket, flag=True) >+ return self.remove_ticket_pac(ticket) >+ >+ self._run_s4u2self_test( >+ { >+ 'expected_error_mode': (KDC_ERR_GENERIC, >+ KDC_ERR_BADOPTION), >+ 'expected_status': ntstatus.NT_STATUS_INVALID_PARAMETER, >+ 'client_opts': { >+ 'not_delegated': False >+ }, >+ 'kdc_options': 'forwardable', >+ 'modify_service_tgt_fn': forwardable_no_pac, >+ 'expected_flags': 'forwardable' >+ }) >+ > # Test performing an S4U2Self operation without requesting a forwardable > # ticket. The resulting ticket should not have the 'forwardable' flag set. > def test_s4u2self_without_forwardable(self): >diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc >index 410ba83123c8..f141efa86e5f 100644 >--- a/selftest/knownfail_heimdal_kdc >+++ b/selftest/knownfail_heimdal_kdc >@@ -243,6 +243,7 @@ > ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_zeroed_client_checksum > ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_zeroed_service_checksum > ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_forwardable >+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_no_pac > ^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_trusted_empty_allowed > # > # The lack of KRB5SignedPath means we no longer return >-- >2.25.1 > > >From a6677e76f11f1b2108b4366cf542a572d26bb865 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Tue, 19 Oct 2021 20:02:45 +1300 >Subject: [PATCH 114/262] CVE-2020-25719 tests/krb5: Add principal aliasing > test > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14686 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/alias_tests.py | 201 +++++++++++++++++++ > python/samba/tests/krb5/rfc4120_constants.py | 1 + > python/samba/tests/usage.py | 1 + > selftest/knownfail_heimdal_kdc | 7 + > selftest/knownfail_mit_kdc | 7 + > source4/selftest/tests.py | 10 + > 6 files changed, 227 insertions(+) > create mode 100755 python/samba/tests/krb5/alias_tests.py > >diff --git a/python/samba/tests/krb5/alias_tests.py b/python/samba/tests/krb5/alias_tests.py >new file mode 100755 >index 000000000000..60213845a443 >--- /dev/null >+++ b/python/samba/tests/krb5/alias_tests.py >@@ -0,0 +1,201 @@ >+#!/usr/bin/env python3 >+# Unix SMB/CIFS implementation. >+# Copyright (C) Stefan Metzmacher 2020 >+# Copyright (C) 2021 Catalyst.Net Ltd >+# >+# This program is free software; you can redistribute it and/or modify >+# it under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# This program is distributed in the hope that it will be useful, >+# but WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with this program. If not, see <http://www.gnu.org/licenses/>. >+# >+ >+import sys >+import os >+ >+import ldb >+ >+from samba.tests import delete_force >+import samba.tests.krb5.kcrypto as kcrypto >+from samba.tests.krb5.kdc_base_test import KDCBaseTest >+from samba.tests.krb5.rfc4120_constants import ( >+ AES256_CTS_HMAC_SHA1_96, >+ ARCFOUR_HMAC_MD5, >+ KDC_ERR_CLIENT_NAME_MISMATCH, >+ NT_PRINCIPAL, >+) >+ >+sys.path.insert(0, 'bin/python') >+os.environ['PYTHONUNBUFFERED'] = '1' >+ >+global_asn1_print = False >+global_hexdump = False >+ >+ >+class AliasTests(KDCBaseTest): >+ def test_dc_alias_rename(self): >+ self._run_dc_alias(action='rename') >+ >+ def test_dc_alias_delete(self): >+ self._run_dc_alias(action='delete') >+ >+ def _run_dc_alias(self, action=None): >+ target_creds = self.get_dc_creds() >+ target_name = target_creds.get_username()[:-1] >+ >+ self._run_alias(target_name, lambda: target_creds, action=action) >+ >+ def test_create_alias_rename(self): >+ self._run_create_alias(action='rename') >+ >+ def test_create_alias_delete(self): >+ self._run_create_alias(action='delete') >+ >+ def _run_create_alias(self, action=None): >+ target_name = self.get_new_username() >+ >+ def create_target(): >+ samdb = self.get_samdb() >+ >+ realm = samdb.domain_dns_name().lower() >+ >+ hostname = f'{target_name}.{realm}' >+ spn = f'ldap/{hostname}' >+ >+ details = { >+ 'dNSHostName': hostname >+ } >+ >+ creds, fn = self.create_account( >+ samdb, >+ target_name, >+ account_type=self.AccountType.COMPUTER, >+ spn=spn, >+ additional_details=details) >+ >+ return creds >+ >+ self._run_alias(target_name, create_target, action=action) >+ >+ def _run_alias(self, target_name, target_creds_fn, action=None): >+ samdb = self.get_samdb() >+ >+ mach_name = self.get_new_username() >+ >+ # Create a machine account. >+ mach_creds, mach_dn = self.create_account( >+ samdb, mach_name, account_type=self.AccountType.COMPUTER) >+ self.addCleanup(delete_force, samdb, mach_dn) >+ >+ mach_sid = self.get_objectSid(samdb, mach_dn) >+ realm = mach_creds.get_realm() >+ >+ # The account salt doesn't change when the account is renamed. >+ old_salt = mach_creds.get_salt() >+ mach_creds.set_forced_salt(old_salt) >+ >+ # Rename the account to alias with the target account. >+ msg = ldb.Message(ldb.Dn(samdb, mach_dn)) >+ msg['sAMAccountName'] = ldb.MessageElement(target_name, >+ ldb.FLAG_MOD_REPLACE, >+ 'sAMAccountName') >+ samdb.modify(msg) >+ mach_creds.set_username(target_name) >+ >+ # Get a TGT for the machine account. >+ tgt = self.get_tgt(mach_creds, kdc_options='0', fresh=True) >+ >+ # Check the PAC. >+ pac_data = self.get_pac_data(tgt.ticket_private['authorization-data']) >+ >+ upn = f'{target_name}@{realm.lower()}' >+ >+ self.assertEqual(target_name, str(pac_data.account_name)) >+ self.assertEqual(mach_sid, pac_data.account_sid) >+ self.assertEqual(target_name, pac_data.logon_name) >+ self.assertEqual(upn, pac_data.upn) >+ self.assertEqual(realm, pac_data.domain_name) >+ >+ # Rename or delete the machine account. >+ if action == 'rename': >+ mach_name2 = self.get_new_username() >+ >+ msg = ldb.Message(ldb.Dn(samdb, mach_dn)) >+ msg['sAMAccountName'] = ldb.MessageElement(mach_name2, >+ ldb.FLAG_MOD_REPLACE, >+ 'sAMAccountName') >+ samdb.modify(msg) >+ elif action == 'delete': >+ samdb.delete(mach_dn) >+ else: >+ self.fail(action) >+ >+ # Get the credentials for the target account. >+ target_creds = target_creds_fn() >+ >+ # Look up the DNS host name of the target account. >+ target_dn = target_creds.get_dn() >+ res = samdb.search(target_dn, >+ scope=ldb.SCOPE_BASE, >+ attrs=['dNSHostName']) >+ target_hostname = str(res[0].get('dNSHostName', idx=0)) >+ >+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, >+ names=['ldap', target_hostname]) >+ target_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, >+ names=[target_name]) >+ >+ target_decryption_key = self.TicketDecryptionKey_from_creds( >+ target_creds) >+ >+ authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256) >+ >+ etypes = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) >+ >+ def generate_s4u2self_padata(_kdc_exchange_dict, >+ _callback_dict, >+ req_body): >+ padata = self.PA_S4U2Self_create(name=target_cname, >+ realm=realm, >+ tgt_session_key=tgt.session_key, >+ ctype=None) >+ return [padata], req_body >+ >+ expected_error_mode = KDC_ERR_CLIENT_NAME_MISMATCH >+ >+ # Make a request using S4U2Self. The request should fail. >+ kdc_exchange_dict = self.tgs_exchange_dict( >+ expected_crealm=realm, >+ expected_cname=target_cname, >+ expected_srealm=realm, >+ expected_sname=sname, >+ ticket_decryption_key=target_decryption_key, >+ generate_padata_fn=generate_s4u2self_padata, >+ expected_error_mode=expected_error_mode, >+ check_error_fn=self.generic_check_kdc_error, >+ check_kdc_private_fn=self.generic_check_kdc_private, >+ tgt=tgt, >+ authenticator_subkey=authenticator_subkey, >+ kdc_options='0', >+ expect_pac=True) >+ >+ rep = self._generic_kdc_exchange(kdc_exchange_dict, >+ cname=None, >+ realm=realm, >+ sname=sname, >+ etypes=etypes) >+ self.check_error_rep(rep, expected_error_mode) >+ >+ >+if __name__ == '__main__': >+ global_asn1_print = False >+ global_hexdump = False >+ import unittest >+ unittest.main() >diff --git a/python/samba/tests/krb5/rfc4120_constants.py b/python/samba/tests/krb5/rfc4120_constants.py >index 39bb2db8e329..b643185f7676 100644 >--- a/python/samba/tests/krb5/rfc4120_constants.py >+++ b/python/samba/tests/krb5/rfc4120_constants.py >@@ -81,6 +81,7 @@ KDC_ERR_SKEW = 37 > KDC_ERR_MODIFIED = 41 > KDC_ERR_INAPP_CKSUM = 50 > KDC_ERR_GENERIC = 60 >+KDC_ERR_CLIENT_NAME_MISMATCH = 75 > KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS = 93 > > # Extended error types >diff --git a/python/samba/tests/usage.py b/python/samba/tests/usage.py >index 7d11b6b46179..5cae74299853 100644 >--- a/python/samba/tests/usage.py >+++ b/python/samba/tests/usage.py >@@ -105,6 +105,7 @@ EXCLUDE_USAGE = { > 'python/samba/tests/krb5/rodc_tests.py', > 'python/samba/tests/krb5/salt_tests.py', > 'python/samba/tests/krb5/spn_tests.py', >+ 'python/samba/tests/krb5/alias_tests.py', > } > > EXCLUDE_HELP = { >diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc >index f141efa86e5f..5e0d958ee595 100644 >--- a/selftest/knownfail_heimdal_kdc >+++ b/selftest/knownfail_heimdal_kdc >@@ -271,3 +271,10 @@ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_client_no_auth_data_required > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_service_no_auth_data_required > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_request_no_pac >+# >+# Alias tests >+# >+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_delete >+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_rename >+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_delete >+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_rename >diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc >index 8612d05b3da6..4441be9d2039 100644 >--- a/selftest/knownfail_mit_kdc >+++ b/selftest/knownfail_mit_kdc >@@ -386,3 +386,10 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > ^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_instance_spn_computer > ^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_our_domain_spn_computer > ^samba.tests.krb5.spn_tests.samba.tests.krb5.spn_tests.SpnTests.test_spn_3_part_our_realm_spn_computer >+# >+# Alias tests >+# >+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_delete >+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_rename >+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_delete >+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_rename >diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py >index 44bb50267c46..53721d1afda6 100755 >--- a/source4/selftest/tests.py >+++ b/source4/selftest/tests.py >@@ -1478,6 +1478,16 @@ planpythontestsuite( > 'FAST_SUPPORT': have_fast_support, > 'TKT_SIG_SUPPORT': tkt_sig_support > }) >+planpythontestsuite( >+ "ad_dc", >+ "samba.tests.krb5.alias_tests", >+ environ={ >+ 'ADMIN_USERNAME': '$USERNAME', >+ 'ADMIN_PASSWORD': '$PASSWORD', >+ 'STRICT_CHECKING': '0', >+ 'FAST_SUPPORT': have_fast_support, >+ 'TKT_SIG_SUPPORT': tkt_sig_support >+ }) > > for env in [ > 'vampire_dc', >-- >2.25.1 > > >From ed192c60d8f5c860f064a8211604e748cacc975e Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Thu, 21 Oct 2021 11:45:23 +1300 >Subject: [PATCH 115/262] CVE-2020-25718 tests/krb5: Add tests for RODC-printed > and invalid TGTs > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_base_test.py | 6 +- > python/samba/tests/krb5/kdc_tgs_tests.py | 808 +++++++++++++++++++ > python/samba/tests/krb5/rfc4120_constants.py | 1 + > selftest/knownfail_heimdal_kdc | 64 ++ > selftest/knownfail_mit_kdc | 67 ++ > 5 files changed, 944 insertions(+), 2 deletions(-) > >diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py >index cc23484ba2cb..4fe7485c4928 100644 >--- a/python/samba/tests/krb5/kdc_base_test.py >+++ b/python/samba/tests/krb5/kdc_base_test.py >@@ -657,7 +657,8 @@ class KDCBaseTest(RawKerberosTest): > 'delegation_to_spn': None, > 'delegation_from_dn': None, > 'trusted_to_auth_for_delegation': False, >- 'fast_support': False >+ 'fast_support': False, >+ 'id': None > } > > account_opts = { >@@ -698,7 +699,8 @@ class KDCBaseTest(RawKerberosTest): > delegation_to_spn, > delegation_from_dn, > trusted_to_auth_for_delegation, >- fast_support): >+ fast_support, >+ id): > if account_type is self.AccountType.USER: > self.assertIsNone(spn) > self.assertIsNone(delegation_to_spn) >diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py >index fbeb5fe61fbb..74f1032163eb 100755 >--- a/python/samba/tests/krb5/kdc_tgs_tests.py >+++ b/python/samba/tests/krb5/kdc_tgs_tests.py >@@ -20,6 +20,13 @@ > import sys > import os > >+import ldb >+ >+ >+from samba import dsdb >+ >+from samba.dcerpc import krb5pac >+ > sys.path.insert(0, "bin/python") > os.environ["PYTHONUNBUFFERED"] = "1" > >@@ -32,6 +39,10 @@ from samba.tests.krb5.rfc4120_constants import ( > KRB_TGS_REP, > KDC_ERR_BADMATCH, > KDC_ERR_BADOPTION, >+ KDC_ERR_CLIENT_NAME_MISMATCH, >+ KDC_ERR_POLICY, >+ KDC_ERR_S_PRINCIPAL_UNKNOWN, >+ KDC_ERR_TGT_REVOKED, > NT_PRINCIPAL, > NT_SRV_INST, > ) >@@ -422,6 +433,803 @@ class KdcTgsTests(KDCBaseTest): > self._make_tgs_request(client_creds, service_creds, tgt, > expect_pac=False, expect_error=True) > >+ # Test making a TGS request. >+ def test_tgs_req(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds) >+ self._run_tgs(tgt, expected_error=0) >+ >+ def test_renew_req(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, renewable=True) >+ self._renew_tgt(tgt, expected_error=0) >+ >+ def test_validate_req(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, invalid=True) >+ self._validate_tgt(tgt, expected_error=0) >+ >+ def test_s4u2self_req(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds) >+ self._s4u2self(tgt, creds, expected_error=0) >+ >+ def test_user2user_req(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds) >+ self._user2user(tgt, creds, expected_error=0) >+ >+ # Test making a request without a PAC. >+ def test_tgs_no_pac(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, remove_pac=True) >+ self._run_tgs(tgt, expected_error=KDC_ERR_BADOPTION) >+ >+ def test_renew_no_pac(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, renewable=True, remove_pac=True) >+ self._renew_tgt(tgt, expected_error=KDC_ERR_BADOPTION) >+ >+ def test_validate_no_pac(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, invalid=True, remove_pac=True) >+ self._validate_tgt(tgt, expected_error=KDC_ERR_BADOPTION) >+ >+ def test_s4u2self_no_pac(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, remove_pac=True) >+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_BADOPTION) >+ >+ def test_user2user_no_pac(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, remove_pac=True) >+ self._user2user(tgt, creds, expected_error=KDC_ERR_BADOPTION) >+ >+ # Test changing the SID in the PAC to that of another account. >+ def test_tgs_sid_mismatch_existing(self): >+ creds = self._get_creds() >+ existing_rid = self._get_existing_rid() >+ tgt = self._get_tgt(creds, new_rid=existing_rid) >+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_renew_sid_mismatch_existing(self): >+ creds = self._get_creds() >+ existing_rid = self._get_existing_rid() >+ tgt = self._get_tgt(creds, renewable=True, new_rid=existing_rid) >+ self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_validate_sid_mismatch_existing(self): >+ creds = self._get_creds() >+ existing_rid = self._get_existing_rid() >+ tgt = self._get_tgt(creds, invalid=True, new_rid=existing_rid) >+ self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_s4u2self_sid_mismatch_existing(self): >+ creds = self._get_creds() >+ existing_rid = self._get_existing_rid() >+ tgt = self._get_tgt(creds, new_rid=existing_rid) >+ self._s4u2self(tgt, creds, >+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_user2user_sid_mismatch_existing(self): >+ creds = self._get_creds() >+ existing_rid = self._get_existing_rid() >+ tgt = self._get_tgt(creds, new_rid=existing_rid) >+ self._user2user(tgt, creds, >+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ # Test changing the SID in the PAC to a non-existent one. >+ def test_tgs_sid_mismatch_nonexisting(self): >+ creds = self._get_creds() >+ nonexistent_rid = self._get_non_existent_rid() >+ tgt = self._get_tgt(creds, new_rid=nonexistent_rid) >+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_renew_sid_mismatch_nonexisting(self): >+ creds = self._get_creds() >+ nonexistent_rid = self._get_non_existent_rid() >+ tgt = self._get_tgt(creds, renewable=True, >+ new_rid=nonexistent_rid) >+ self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_validate_sid_mismatch_nonexisting(self): >+ creds = self._get_creds() >+ nonexistent_rid = self._get_non_existent_rid() >+ tgt = self._get_tgt(creds, invalid=True, >+ new_rid=nonexistent_rid) >+ self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_s4u2self_sid_mismatch_nonexisting(self): >+ creds = self._get_creds() >+ nonexistent_rid = self._get_non_existent_rid() >+ tgt = self._get_tgt(creds, new_rid=nonexistent_rid) >+ self._s4u2self(tgt, creds, >+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_user2user_sid_mismatch_nonexisting(self): >+ creds = self._get_creds() >+ nonexistent_rid = self._get_non_existent_rid() >+ tgt = self._get_tgt(creds, new_rid=nonexistent_rid) >+ self._user2user(tgt, creds, >+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ # Test with an RODC-issued ticket where the client is revealed to the RODC. >+ def test_tgs_rodc_revealed(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._run_tgs(tgt, expected_error=0) >+ >+ def test_renew_rodc_revealed(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True) >+ self._renew_tgt(tgt, expected_error=0) >+ >+ def test_validate_rodc_revealed(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True) >+ self._validate_tgt(tgt, expected_error=0) >+ >+ def test_s4u2self_rodc_revealed(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._s4u2self(tgt, creds, expected_error=0) >+ >+ def test_user2user_rodc_revealed(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._user2user(tgt, creds, expected_error=0) >+ >+ # Test with an RODC-issued ticket where the SID in the PAC is changed to >+ # that of another account. >+ def test_tgs_rodc_sid_mismatch_existing(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ existing_rid = self._get_existing_rid(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid) >+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_renew_rodc_sid_mismatch_existing(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ existing_rid = self._get_existing_rid(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True, >+ new_rid=existing_rid) >+ self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_validate_rodc_sid_mismatch_existing(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ existing_rid = self._get_existing_rid(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True, >+ new_rid=existing_rid) >+ self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_s4u2self_rodc_sid_mismatch_existing(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ existing_rid = self._get_existing_rid(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid) >+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_user2user_rodc_sid_mismatch_existing(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ existing_rid = self._get_existing_rid(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid) >+ self._user2user(tgt, creds, >+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ # Test with an RODC-issued ticket where the SID in the PAC is changed to a >+ # non-existent one. >+ def test_tgs_rodc_sid_mismatch_nonexisting(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ nonexistent_rid = self._get_non_existent_rid() >+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid) >+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_renew_rodc_sid_mismatch_nonexisting(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ nonexistent_rid = self._get_non_existent_rid() >+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True, >+ new_rid=nonexistent_rid) >+ self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_validate_rodc_sid_mismatch_nonexisting(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ nonexistent_rid = self._get_non_existent_rid() >+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True, >+ new_rid=nonexistent_rid) >+ self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_s4u2self_rodc_sid_mismatch_nonexisting(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ nonexistent_rid = self._get_non_existent_rid() >+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid) >+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ def test_user2user_rodc_sid_mismatch_nonexisting(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ nonexistent_rid = self._get_non_existent_rid() >+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid) >+ self._user2user(tgt, creds, >+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH) >+ >+ # Test with an RODC-issued ticket where the client is not revealed to the >+ # RODC. >+ def test_tgs_rodc_not_revealed(self): >+ creds = self._get_creds(replication_allowed=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ # TODO: error code >+ self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_renew_rodc_not_revealed(self): >+ creds = self._get_creds(replication_allowed=True) >+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True) >+ self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_validate_rodc_not_revealed(self): >+ creds = self._get_creds(replication_allowed=True) >+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True) >+ self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_s4u2self_rodc_not_revealed(self): >+ creds = self._get_creds(replication_allowed=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_user2user_rodc_not_revealed(self): >+ creds = self._get_creds(replication_allowed=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ # Test with an RODC-issued ticket where the RODC account does not have the >+ # PARTIAL_SECRETS bit set. >+ def test_tgs_rodc_no_partial_secrets(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._remove_rodc_partial_secrets() >+ self._run_tgs(tgt, expected_error=KDC_ERR_POLICY) >+ >+ def test_renew_rodc_no_partial_secrets(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True) >+ self._remove_rodc_partial_secrets() >+ self._renew_tgt(tgt, expected_error=KDC_ERR_POLICY) >+ >+ def test_validate_rodc_no_partial_secrets(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True) >+ self._remove_rodc_partial_secrets() >+ self._validate_tgt(tgt, expected_error=KDC_ERR_POLICY) >+ >+ def test_s4u2self_rodc_no_partial_secrets(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._remove_rodc_partial_secrets() >+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_POLICY) >+ >+ def test_user2user_rodc_no_partial_secrets(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._remove_rodc_partial_secrets() >+ self._user2user(tgt, creds, expected_error=KDC_ERR_POLICY) >+ >+ # Test with an RODC-issued ticket where the RODC account does not have an >+ # msDS-KrbTgtLink. >+ def test_tgs_rodc_no_krbtgt_link(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._remove_rodc_krbtgt_link() >+ self._run_tgs(tgt, expected_error=KDC_ERR_POLICY) >+ >+ def test_renew_rodc_no_krbtgt_link(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True) >+ self._remove_rodc_krbtgt_link() >+ self._renew_tgt(tgt, expected_error=KDC_ERR_POLICY) >+ >+ def test_validate_rodc_no_krbtgt_link(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True) >+ self._remove_rodc_krbtgt_link() >+ self._validate_tgt(tgt, expected_error=KDC_ERR_POLICY) >+ >+ def test_s4u2self_rodc_no_krbtgt_link(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._remove_rodc_krbtgt_link() >+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_POLICY) >+ >+ def test_user2user_rodc_no_krbtgt_link(self): >+ creds = self._get_creds(replication_allowed=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._remove_rodc_krbtgt_link() >+ self._user2user(tgt, creds, expected_error=KDC_ERR_POLICY) >+ >+ # Test with an RODC-issued ticket where the client is not allowed to >+ # replicate to the RODC. >+ def test_tgs_rodc_not_allowed(self): >+ creds = self._get_creds(revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_renew_rodc_not_allowed(self): >+ creds = self._get_creds(revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True) >+ self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_validate_rodc_not_allowed(self): >+ creds = self._get_creds(revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True) >+ self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_s4u2self_rodc_not_allowed(self): >+ creds = self._get_creds(revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_user2user_rodc_not_allowed(self): >+ creds = self._get_creds(revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ # Test with an RODC-issued ticket where the client is denied from >+ # replicating to the RODC. >+ def test_tgs_rodc_denied(self): >+ creds = self._get_creds(replication_denied=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_renew_rodc_denied(self): >+ creds = self._get_creds(replication_denied=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True) >+ self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_validate_rodc_denied(self): >+ creds = self._get_creds(replication_denied=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True) >+ self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_s4u2self_rodc_denied(self): >+ creds = self._get_creds(replication_denied=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_user2user_rodc_denied(self): >+ creds = self._get_creds(replication_denied=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ # Test with an RODC-issued ticket where the client is both allowed and >+ # denied replicating to the RODC. >+ def test_tgs_rodc_allowed_denied(self): >+ creds = self._get_creds(replication_allowed=True, >+ replication_denied=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_renew_rodc_allowed_denied(self): >+ creds = self._get_creds(replication_allowed=True, >+ replication_denied=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True) >+ self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_validate_rodc_allowed_denied(self): >+ creds = self._get_creds(replication_allowed=True, >+ replication_denied=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True) >+ self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_s4u2self_rodc_allowed_denied(self): >+ creds = self._get_creds(replication_allowed=True, >+ replication_denied=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ def test_user2user_rodc_allowed_denied(self): >+ creds = self._get_creds(replication_allowed=True, >+ replication_denied=True, >+ revealed_to_rodc=True) >+ tgt = self._get_tgt(creds, from_rodc=True) >+ self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED) >+ >+ # Test user-to-user with incorrect service principal names. >+ def test_user2user_matching_sname_host(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds) >+ >+ user_name = self._get_mach_creds().get_username() >+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, >+ names=['host', user_name]) >+ >+ self._user2user(tgt, creds, sname=sname, >+ expected_error=KDC_ERR_S_PRINCIPAL_UNKNOWN) >+ >+ def test_user2user_matching_sname_no_host(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds) >+ >+ user_name = self._get_mach_creds().get_username() >+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, >+ names=[user_name]) >+ >+ self._user2user(tgt, creds, sname=sname, >+ expected_error=KDC_ERR_BADMATCH) >+ >+ def test_user2user_wrong_sname(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds) >+ >+ other_creds = self.get_service_creds() >+ user_name = other_creds.get_username() >+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, >+ names=[user_name]) >+ >+ self._user2user(tgt, creds, sname=sname, >+ expected_error=(KDC_ERR_BADMATCH, >+ KDC_ERR_BADOPTION)) >+ >+ def test_user2user_non_existent_sname(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds) >+ >+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, >+ names=['host', 'non_existent_user']) >+ >+ self._user2user(tgt, creds, sname=sname, >+ expected_error=KDC_ERR_S_PRINCIPAL_UNKNOWN) >+ >+ def test_user2user_service_ticket(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds) >+ >+ service_creds = self.get_service_creds() >+ service_ticket = self.get_service_ticket(tgt, service_creds) >+ >+ self._user2user(service_ticket, creds, expected_error=KDC_ERR_POLICY) >+ >+ def _get_tgt(self, >+ client_creds, >+ renewable=False, >+ invalid=False, >+ from_rodc=False, >+ new_rid=None, >+ remove_pac=False): >+ self.assertFalse(renewable and invalid) >+ >+ if remove_pac: >+ self.assertIsNone(new_rid) >+ >+ tgt = self.get_tgt(client_creds) >+ >+ if from_rodc: >+ krbtgt_creds = self.get_mock_rodc_krbtgt_creds() >+ else: >+ krbtgt_creds = self.get_krbtgt_creds() >+ >+ if new_rid is not None: >+ def change_sid_fn(pac): >+ for pac_buffer in pac.buffers: >+ if pac_buffer.type == krb5pac.PAC_TYPE_LOGON_INFO: >+ logon_info = pac_buffer.info.info >+ >+ logon_info.info3.base.rid = new_rid >+ >+ return pac >+ >+ modify_pac_fn = change_sid_fn >+ else: >+ modify_pac_fn = None >+ >+ krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds) >+ >+ if remove_pac: >+ checksum_keys = None >+ else: >+ checksum_keys = { >+ krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key >+ } >+ >+ if renewable: >+ def set_renewable(enc_part): >+ # Set the renewable flag. >+ renewable_flag = krb5_asn1.TicketFlags('renewable') >+ pos = len(tuple(renewable_flag)) - 1 >+ >+ flags = enc_part['flags'] >+ self.assertLessEqual(pos, len(flags)) >+ >+ new_flags = flags[:pos] + '1' + flags[pos + 1:] >+ enc_part['flags'] = new_flags >+ >+ # Set the renew-till time to be in the future. >+ renew_till = self.get_KerberosTime(offset=100 * 60 * 60) >+ enc_part['renew-till'] = renew_till >+ >+ return enc_part >+ >+ modify_fn = set_renewable >+ elif invalid: >+ def set_invalid(enc_part): >+ # Set the invalid flag. >+ invalid_flag = krb5_asn1.TicketFlags('invalid') >+ pos = len(tuple(invalid_flag)) - 1 >+ >+ flags = enc_part['flags'] >+ self.assertLessEqual(pos, len(flags)) >+ >+ new_flags = flags[:pos] + '1' + flags[pos + 1:] >+ enc_part['flags'] = new_flags >+ >+ # Set the ticket start time to be in the past. >+ past_time = self.get_KerberosTime(offset=-100 * 60 * 60) >+ enc_part['starttime'] = past_time >+ >+ return enc_part >+ >+ modify_fn = set_invalid >+ else: >+ modify_fn = None >+ >+ return self.modified_ticket( >+ tgt, >+ new_ticket_key=krbtgt_key, >+ modify_fn=modify_fn, >+ modify_pac_fn=modify_pac_fn, >+ exclude_pac=remove_pac, >+ update_pac_checksums=not remove_pac, >+ checksum_keys=checksum_keys) >+ >+ def _remove_rodc_partial_secrets(self): >+ samdb = self.get_samdb() >+ >+ rodc_ctx = self.get_mock_rodc_ctx() >+ rodc_dn = ldb.Dn(samdb, rodc_ctx.acct_dn) >+ >+ def add_rodc_partial_secrets(): >+ msg = ldb.Message() >+ msg.dn = rodc_dn >+ msg['userAccountControl'] = ldb.MessageElement( >+ str(rodc_ctx.userAccountControl), >+ ldb.FLAG_MOD_REPLACE, >+ 'userAccountControl') >+ samdb.modify(msg) >+ >+ self.addCleanup(add_rodc_partial_secrets) >+ >+ uac = rodc_ctx.userAccountControl & ~dsdb.UF_PARTIAL_SECRETS_ACCOUNT >+ >+ msg = ldb.Message() >+ msg.dn = rodc_dn >+ msg['userAccountControl'] = ldb.MessageElement( >+ str(uac), >+ ldb.FLAG_MOD_REPLACE, >+ 'userAccountControl') >+ samdb.modify(msg) >+ >+ def _remove_rodc_krbtgt_link(self): >+ samdb = self.get_samdb() >+ >+ rodc_ctx = self.get_mock_rodc_ctx() >+ rodc_dn = ldb.Dn(samdb, rodc_ctx.acct_dn) >+ >+ def add_rodc_krbtgt_link(): >+ msg = ldb.Message() >+ msg.dn = rodc_dn >+ msg['msDS-KrbTgtLink'] = ldb.MessageElement( >+ rodc_ctx.new_krbtgt_dn, >+ ldb.FLAG_MOD_ADD, >+ 'msDS-KrbTgtLink') >+ samdb.modify(msg) >+ >+ self.addCleanup(add_rodc_krbtgt_link) >+ >+ msg = ldb.Message() >+ msg.dn = rodc_dn >+ msg['msDS-KrbTgtLink'] = ldb.MessageElement( >+ [], >+ ldb.FLAG_MOD_DELETE, >+ 'msDS-KrbTgtLink') >+ samdb.modify(msg) >+ >+ def _get_creds(self, >+ replication_allowed=False, >+ replication_denied=False, >+ revealed_to_rodc=False): >+ return self.get_cached_creds( >+ account_type=self.AccountType.COMPUTER, >+ opts={ >+ 'allowed_replication_mock': replication_allowed, >+ 'denied_replication_mock': replication_denied, >+ 'revealed_to_mock_rodc': revealed_to_rodc, >+ 'id': 0 >+ }) >+ >+ def _get_existing_rid(self, >+ replication_allowed=False, >+ replication_denied=False, >+ revealed_to_rodc=False): >+ other_creds = self.get_cached_creds( >+ account_type=self.AccountType.COMPUTER, >+ opts={ >+ 'allowed_replication_mock': replication_allowed, >+ 'denied_replication_mock': replication_denied, >+ 'revealed_to_mock_rodc': revealed_to_rodc, >+ 'id': 1 >+ }) >+ >+ samdb = self.get_samdb() >+ >+ other_dn = other_creds.get_dn() >+ other_sid = self.get_objectSid(samdb, other_dn) >+ >+ other_rid = int(other_sid.rsplit('-', 1)[1]) >+ >+ return other_rid >+ >+ def _get_mach_creds(self): >+ return self.get_cached_creds( >+ account_type=self.AccountType.COMPUTER, >+ opts={ >+ 'allowed_replication_mock': True, >+ 'denied_replication_mock': False, >+ 'revealed_to_mock_rodc': True, >+ 'id': 2 >+ }) >+ >+ def _get_non_existent_rid(self): >+ return (1 << 30) - 1 >+ >+ def _run_tgs(self, tgt, expected_error): >+ target_creds = self.get_service_creds() >+ self._tgs_req(tgt, expected_error, target_creds) >+ >+ def _renew_tgt(self, tgt, expected_error): >+ krbtgt_creds = self.get_krbtgt_creds() >+ kdc_options = str(krb5_asn1.KDCOptions('renew')) >+ self._tgs_req(tgt, expected_error, krbtgt_creds, >+ kdc_options=kdc_options) >+ >+ def _validate_tgt(self, tgt, expected_error): >+ krbtgt_creds = self.get_krbtgt_creds() >+ kdc_options = str(krb5_asn1.KDCOptions('validate')) >+ self._tgs_req(tgt, expected_error, krbtgt_creds, >+ kdc_options=kdc_options) >+ >+ def _s4u2self(self, tgt, tgt_creds, expected_error): >+ user_creds = self._get_mach_creds() >+ >+ user_name = user_creds.get_username() >+ user_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, >+ names=[user_name]) >+ user_realm = user_creds.get_realm() >+ >+ def generate_s4u2self_padata(_kdc_exchange_dict, >+ _callback_dict, >+ req_body): >+ padata = self.PA_S4U2Self_create( >+ name=user_cname, >+ realm=user_realm, >+ tgt_session_key=tgt.session_key, >+ ctype=None) >+ >+ return [padata], req_body >+ >+ self._tgs_req(tgt, expected_error, tgt_creds, >+ expected_cname=user_cname, >+ generate_padata_fn=generate_s4u2self_padata, >+ expect_claims=False) >+ >+ def _user2user(self, tgt, tgt_creds, expected_error, sname=None): >+ user_creds = self._get_mach_creds() >+ user_tgt = self.get_tgt(user_creds) >+ >+ kdc_options = str(krb5_asn1.KDCOptions('enc-tkt-in-skey')) >+ self._tgs_req(user_tgt, expected_error, tgt_creds, >+ kdc_options=kdc_options, >+ additional_ticket=tgt, >+ sname=sname) >+ >+ def _tgs_req(self, tgt, expected_error, target_creds, >+ kdc_options='0', >+ expected_cname=None, >+ additional_ticket=None, >+ generate_padata_fn=None, >+ sname=None, >+ expect_claims=True): >+ srealm = target_creds.get_realm() >+ >+ if sname is None: >+ target_name = target_creds.get_username() >+ if target_name == 'krbtgt': >+ sname = self.PrincipalName_create(name_type=NT_SRV_INST, >+ names=[target_name, srealm]) >+ else: >+ if target_name[-1] == '$': >+ target_name = target_name[:-1] >+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL, >+ names=['host', target_name]) >+ >+ if additional_ticket is not None: >+ additional_tickets = [additional_ticket.ticket] >+ decryption_key = additional_ticket.session_key >+ else: >+ additional_tickets = None >+ decryption_key = self.TicketDecryptionKey_from_creds( >+ target_creds) >+ >+ subkey = self.RandomKey(tgt.session_key.etype) >+ >+ etypes = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5) >+ >+ if expected_error: >+ check_error_fn = self.generic_check_kdc_error >+ check_rep_fn = None >+ else: >+ check_error_fn = None >+ check_rep_fn = self.generic_check_kdc_rep >+ >+ if expected_cname is None: >+ expected_cname = tgt.cname >+ >+ kdc_exchange_dict = self.tgs_exchange_dict( >+ expected_crealm=tgt.crealm, >+ expected_cname=expected_cname, >+ expected_srealm=srealm, >+ expected_sname=sname, >+ ticket_decryption_key=decryption_key, >+ generate_padata_fn=generate_padata_fn, >+ check_error_fn=check_error_fn, >+ check_rep_fn=check_rep_fn, >+ check_kdc_private_fn=self.generic_check_kdc_private, >+ expected_error_mode=expected_error, >+ tgt=tgt, >+ authenticator_subkey=subkey, >+ kdc_options=kdc_options, >+ expect_edata=False, >+ expect_claims=expect_claims) >+ >+ self._generic_kdc_exchange(kdc_exchange_dict, >+ cname=None, >+ realm=srealm, >+ sname=sname, >+ etypes=etypes, >+ additional_tickets=additional_tickets) >+ > > if __name__ == "__main__": > global_asn1_print = False >diff --git a/python/samba/tests/krb5/rfc4120_constants.py b/python/samba/tests/krb5/rfc4120_constants.py >index b643185f7676..490cd255ec30 100644 >--- a/python/samba/tests/krb5/rfc4120_constants.py >+++ b/python/samba/tests/krb5/rfc4120_constants.py >@@ -72,6 +72,7 @@ KDC_ERR_POLICY = 12 > KDC_ERR_BADOPTION = 13 > KDC_ERR_ETYPE_NOSUPP = 14 > KDC_ERR_SUMTYPE_NOSUPP = 15 >+KDC_ERR_TGT_REVOKED = 20 > KDC_ERR_PREAUTH_FAILED = 24 > KDC_ERR_PREAUTH_REQUIRED = 25 > KDC_ERR_BAD_INTEGRITY = 31 >diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc >index 5e0d958ee595..27c2dfe3be3a 100644 >--- a/selftest/knownfail_heimdal_kdc >+++ b/selftest/knownfail_heimdal_kdc >@@ -278,3 +278,67 @@ > ^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_rename > ^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_delete > ^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_rename >+# >+# KDC TGT tests >+# >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_allowed_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_no_krbtgt_link >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_no_partial_secrets >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_not_allowed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_not_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_allowed_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_no_krbtgt_link >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_no_partial_secrets >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_not_allowed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_not_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_allowed_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_no_krbtgt_link >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_no_partial_secrets >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_not_allowed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_not_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_matching_sname_host >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_matching_sname_no_host >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_non_existent_sname >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_req >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_allowed_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_no_krbtgt_link >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_no_partial_secrets >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_not_allowed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_not_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_allowed_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_no_krbtgt_link >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_no_partial_secrets >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_allowed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_nonexisting >diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc >index 4441be9d2039..84f74e5523ee 100644 >--- a/selftest/knownfail_mit_kdc >+++ b/selftest/knownfail_mit_kdc >@@ -393,3 +393,70 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > ^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_rename > ^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_delete > ^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_rename >+# >+# KDC TGT tests >+# >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_allowed_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_no_krbtgt_link >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_no_partial_secrets >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_not_allowed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_not_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_allowed_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_no_krbtgt_link >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_no_partial_secrets >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_not_allowed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_not_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_allowed_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_no_krbtgt_link >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_no_partial_secrets >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_not_allowed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_not_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_matching_sname_no_host >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_req >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_allowed_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_no_krbtgt_link >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_no_partial_secrets >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_not_allowed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_not_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_allowed_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_denied >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_no_krbtgt_link >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_no_partial_secrets >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_allowed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_revealed >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_existing >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_sid_mismatch_nonexisting >-- >2.25.1 > > >From d7c834fef29add126da65142199830ff8282fdb4 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Thu, 28 Oct 2021 16:20:07 +1300 >Subject: [PATCH 116/262] CVE-2020-25719 tests/krb5: Add tests for including > authdata without a PAC > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_tgs_tests.py | 32 +++++++++++++++++++++++- > python/samba/tests/krb5/raw_testcase.py | 14 +++++++---- > selftest/knownfail_heimdal_kdc | 5 ++++ > selftest/knownfail_mit_kdc | 5 ++++ > 4 files changed, 50 insertions(+), 6 deletions(-) > >diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py >index 74f1032163eb..5de79c30e1be 100755 >--- a/python/samba/tests/krb5/kdc_tgs_tests.py >+++ b/python/samba/tests/krb5/kdc_tgs_tests.py >@@ -485,6 +485,34 @@ class KdcTgsTests(KDCBaseTest): > tgt = self._get_tgt(creds, remove_pac=True) > self._user2user(tgt, creds, expected_error=KDC_ERR_BADOPTION) > >+ # Test making a request with authdata and without a PAC. >+ def test_tgs_authdata_no_pac(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True) >+ self._run_tgs(tgt, expected_error=KDC_ERR_BADOPTION) >+ >+ def test_renew_authdata_no_pac(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, renewable=True, remove_pac=True, >+ allow_empty_authdata=True) >+ self._renew_tgt(tgt, expected_error=KDC_ERR_BADOPTION) >+ >+ def test_validate_authdata_no_pac(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, invalid=True, remove_pac=True, >+ allow_empty_authdata=True) >+ self._validate_tgt(tgt, expected_error=KDC_ERR_BADOPTION) >+ >+ def test_s4u2self_authdata_no_pac(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True) >+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_BADOPTION) >+ >+ def test_user2user_authdata_no_pac(self): >+ creds = self._get_creds() >+ tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True) >+ self._user2user(tgt, creds, expected_error=KDC_ERR_BADOPTION) >+ > # Test changing the SID in the PAC to that of another account. > def test_tgs_sid_mismatch_existing(self): > creds = self._get_creds() >@@ -928,7 +956,8 @@ class KdcTgsTests(KDCBaseTest): > invalid=False, > from_rodc=False, > new_rid=None, >- remove_pac=False): >+ remove_pac=False, >+ allow_empty_authdata=False): > self.assertFalse(renewable and invalid) > > if remove_pac: >@@ -1011,6 +1040,7 @@ class KdcTgsTests(KDCBaseTest): > modify_fn=modify_fn, > modify_pac_fn=modify_pac_fn, > exclude_pac=remove_pac, >+ allow_empty_authdata=allow_empty_authdata, > update_pac_checksums=not remove_pac, > checksum_keys=checksum_keys) > >diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py >index 8e55790272a7..b5ac393ea673 100644 >--- a/python/samba/tests/krb5/raw_testcase.py >+++ b/python/samba/tests/krb5/raw_testcase.py >@@ -3224,6 +3224,7 @@ class RawKerberosTest(TestCaseInTempDir): > modify_fn=None, > modify_pac_fn=None, > exclude_pac=False, >+ allow_empty_authdata=False, > update_pac_checksums=True, > checksum_keys=None, > include_checksums=None): >@@ -3332,8 +3333,10 @@ class RawKerberosTest(TestCaseInTempDir): > > # Replace the PAC in the authorization data and re-add it to the > # ticket enc-part. >- auth_data, _ = self.replace_pac(auth_data, new_pac, >- expect_pac=expect_pac) >+ auth_data, _ = self.replace_pac( >+ auth_data, new_pac, >+ expect_pac=expect_pac, >+ allow_empty_authdata=allow_empty_authdata) > enc_part['authorization-data'] = auth_data > > # Re-encrypt the ticket enc-part with the new key. >@@ -3454,7 +3457,8 @@ class RawKerberosTest(TestCaseInTempDir): > > kdc_checksum_buffer.info.signature = kdc_checksum > >- def replace_pac(self, auth_data, new_pac, expect_pac=True): >+ def replace_pac(self, auth_data, new_pac, expect_pac=True, >+ allow_empty_authdata=False): > if new_pac is not None: > self.assertElementEqual(new_pac, 'ad-type', AD_WIN2K_PAC) > self.assertElementPresent(new_pac, 'ad-data') >@@ -3483,7 +3487,7 @@ class RawKerberosTest(TestCaseInTempDir): > if expect_pac: > self.assertIsNotNone(old_pac, 'Expected PAC') > >- if relevant_elems: >+ if relevant_elems or allow_empty_authdata: > ad_relevant = self.der_encode( > relevant_elems, > asn1Spec=krb5_asn1.AD_IF_RELEVANT()) >@@ -3494,7 +3498,7 @@ class RawKerberosTest(TestCaseInTempDir): > else: > authdata_elem = None > >- if authdata_elem is not None: >+ if authdata_elem is not None or allow_empty_authdata: > new_auth_data.append(authdata_elem) > > if expect_pac: >diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc >index 27c2dfe3be3a..572fbb0e0cde 100644 >--- a/selftest/knownfail_heimdal_kdc >+++ b/selftest/knownfail_heimdal_kdc >@@ -281,6 +281,7 @@ > # > # KDC TGT tests > # >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_allowed_denied > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_denied >@@ -292,6 +293,7 @@ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_existing > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_allowed_denied > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_denied >@@ -303,6 +305,7 @@ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_nonexisting > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_existing > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_allowed_denied > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_denied >@@ -314,6 +317,7 @@ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_matching_sname_host > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_matching_sname_no_host > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac >@@ -331,6 +335,7 @@ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_existing > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_nonexisting > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_allowed_denied > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_denied >diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc >index 84f74e5523ee..127fcdc425d5 100644 >--- a/selftest/knownfail_mit_kdc >+++ b/selftest/knownfail_mit_kdc >@@ -396,6 +396,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > # > # KDC TGT tests > # >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_allowed_denied > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_denied >@@ -408,6 +409,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_existing > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_allowed_denied >@@ -421,6 +423,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_nonexisting > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_existing > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_allowed_denied > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_denied >@@ -433,6 +436,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_matching_sname_no_host > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_req >@@ -448,6 +452,7 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_existing > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_nonexisting > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_allowed_denied > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_denied >-- >2.25.1 > > >From 45c41b082defd1ac4303e8c2151cabf881032b79 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Thu, 21 Oct 2021 16:46:56 +1300 >Subject: [PATCH 117/262] CVE-2020-25721 tests/krb5: Add tests for extended > PAC_UPN_DNS_INFO PAC buffer > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14835 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/kdc_base_test.py | 3 +- > python/samba/tests/krb5/kdc_tgs_tests.py | 51 +++++++++++++++++++++++- > python/samba/tests/krb5/raw_testcase.py | 41 +++++++++++++++++++ > python/samba/tests/krb5/s4u_tests.py | 2 + > selftest/knownfail_heimdal_kdc | 4 ++ > selftest/knownfail_mit_kdc | 4 ++ > 6 files changed, 103 insertions(+), 2 deletions(-) > >diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py >index 4fe7485c4928..9be6cbab30bc 100644 >--- a/python/samba/tests/krb5/kdc_base_test.py >+++ b/python/samba/tests/krb5/kdc_base_test.py >@@ -1358,7 +1358,7 @@ class KDCBaseTest(RawKerberosTest): > > def get_tgt(self, creds, to_rodc=False, kdc_options=None, > expected_flags=None, unexpected_flags=None, >- expected_account_name=None, >+ expected_account_name=None, expected_upn_name=None, > expected_sid=None, > pac_request=True, expect_pac=True, fresh=False): > user_name = creds.get_username() >@@ -1410,6 +1410,7 @@ class KDCBaseTest(RawKerberosTest): > expected_srealm=realm, > expected_sname=sname, > expected_account_name=expected_account_name, >+ expected_upn_name=expected_upn_name, > expected_sid=expected_sid, > expected_salt=salt, > expected_flags=expected_flags, >diff --git a/python/samba/tests/krb5/kdc_tgs_tests.py b/python/samba/tests/krb5/kdc_tgs_tests.py >index 5de79c30e1be..5313dbc6045f 100755 >--- a/python/samba/tests/krb5/kdc_tgs_tests.py >+++ b/python/samba/tests/krb5/kdc_tgs_tests.py >@@ -227,7 +227,10 @@ class KdcTgsTests(KDCBaseTest): > > def _make_tgs_request(self, client_creds, service_creds, tgt, > pac_request=None, expect_pac=True, >- expect_error=False): >+ expect_error=False, >+ expected_account_name=None, >+ expected_upn_name=None, >+ expected_sid=None): > client_account = client_creds.get_username() > cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, > names=[client_account]) >@@ -268,6 +271,9 @@ class KdcTgsTests(KDCBaseTest): > expected_cname=expected_cname, > expected_srealm=expected_srealm, > expected_sname=expected_sname, >+ expected_account_name=expected_account_name, >+ expected_upn_name=expected_upn_name, >+ expected_sid=expected_sid, > expected_supported_etypes=expected_supported_etypes, > ticket_decryption_key=target_decryption_key, > check_error_fn=check_error_fn, >@@ -433,6 +439,49 @@ class KdcTgsTests(KDCBaseTest): > self._make_tgs_request(client_creds, service_creds, tgt, > expect_pac=False, expect_error=True) > >+ def test_upn_dns_info_ex_user(self): >+ client_creds = self.get_client_creds() >+ self._run_upn_dns_info_ex_test(client_creds) >+ >+ def test_upn_dns_info_ex_mac(self): >+ mach_creds = self.get_mach_creds() >+ self._run_upn_dns_info_ex_test(mach_creds) >+ >+ def test_upn_dns_info_ex_upn_user(self): >+ client_creds = self.get_cached_creds( >+ account_type=self.AccountType.USER, >+ opts={'upn': 'upn_dns_info_test_upn0@bar'}) >+ self._run_upn_dns_info_ex_test(client_creds) >+ >+ def test_upn_dns_info_ex_upn_mac(self): >+ mach_creds = self.get_cached_creds( >+ account_type=self.AccountType.COMPUTER, >+ opts={'upn': 'upn_dns_info_test_upn1@bar'}) >+ self._run_upn_dns_info_ex_test(mach_creds) >+ >+ def _run_upn_dns_info_ex_test(self, client_creds): >+ service_creds = self.get_service_creds() >+ >+ samdb = self.get_samdb() >+ dn = client_creds.get_dn() >+ >+ account_name = client_creds.get_username() >+ upn_name = client_creds.get_upn() >+ if upn_name is None: >+ realm = client_creds.get_realm().lower() >+ upn_name = f'{account_name}@{realm}' >+ sid = self.get_objectSid(samdb, dn) >+ >+ tgt = self.get_tgt(client_creds, >+ expected_account_name=account_name, >+ expected_upn_name=upn_name, >+ expected_sid=sid) >+ >+ self._make_tgs_request(client_creds, service_creds, tgt, >+ expected_account_name=account_name, >+ expected_upn_name=upn_name, >+ expected_sid=sid) >+ > # Test making a TGS request. > def test_tgs_req(self): > creds = self._get_creds() >diff --git a/python/samba/tests/krb5/raw_testcase.py b/python/samba/tests/krb5/raw_testcase.py >index b5ac393ea673..18ee8738eaa5 100644 >--- a/python/samba/tests/krb5/raw_testcase.py >+++ b/python/samba/tests/krb5/raw_testcase.py >@@ -1986,6 +1986,7 @@ class RawKerberosTest(TestCaseInTempDir): > expected_srealm=None, > expected_sname=None, > expected_account_name=None, >+ expected_upn_name=None, > expected_sid=None, > expected_supported_etypes=None, > expected_flags=None, >@@ -2019,6 +2020,7 @@ class RawKerberosTest(TestCaseInTempDir): > expect_edata=None, > expect_pac=True, > expect_claims=True, >+ expect_upn_dns_info_ex=None, > to_rodc=False): > if expected_error_mode == 0: > expected_error_mode = () >@@ -2037,6 +2039,7 @@ class RawKerberosTest(TestCaseInTempDir): > 'expected_srealm': expected_srealm, > 'expected_sname': expected_sname, > 'expected_account_name': expected_account_name, >+ 'expected_upn_name': expected_upn_name, > 'expected_sid': expected_sid, > 'expected_supported_etypes': expected_supported_etypes, > 'expected_flags': expected_flags, >@@ -2070,6 +2073,7 @@ class RawKerberosTest(TestCaseInTempDir): > 'expect_edata': expect_edata, > 'expect_pac': expect_pac, > 'expect_claims': expect_claims, >+ 'expect_upn_dns_info_ex': expect_upn_dns_info_ex, > 'to_rodc': to_rodc > } > if callback_dict is None: >@@ -2084,6 +2088,7 @@ class RawKerberosTest(TestCaseInTempDir): > expected_srealm=None, > expected_sname=None, > expected_account_name=None, >+ expected_upn_name=None, > expected_sid=None, > expected_supported_etypes=None, > expected_flags=None, >@@ -2116,6 +2121,7 @@ class RawKerberosTest(TestCaseInTempDir): > expect_edata=None, > expect_pac=True, > expect_claims=True, >+ expect_upn_dns_info_ex=None, > expected_proxy_target=None, > expected_transited_services=None, > to_rodc=False): >@@ -2136,6 +2142,7 @@ class RawKerberosTest(TestCaseInTempDir): > 'expected_srealm': expected_srealm, > 'expected_sname': expected_sname, > 'expected_account_name': expected_account_name, >+ 'expected_upn_name': expected_upn_name, > 'expected_sid': expected_sid, > 'expected_supported_etypes': expected_supported_etypes, > 'expected_flags': expected_flags, >@@ -2168,6 +2175,7 @@ class RawKerberosTest(TestCaseInTempDir): > 'expect_edata': expect_edata, > 'expect_pac': expect_pac, > 'expect_claims': expect_claims, >+ 'expect_upn_dns_info_ex': expect_upn_dns_info_ex, > 'expected_proxy_target': expected_proxy_target, > 'expected_transited_services': expected_transited_services, > 'to_rodc': to_rodc >@@ -2584,6 +2592,12 @@ class RawKerberosTest(TestCaseInTempDir): > expected_account_name = kdc_exchange_dict['expected_account_name'] > expected_sid = kdc_exchange_dict['expected_sid'] > >+ expect_upn_dns_info_ex = kdc_exchange_dict['expect_upn_dns_info_ex'] >+ if expect_upn_dns_info_ex is None and ( >+ expected_account_name is not None >+ or expected_sid is not None): >+ expect_upn_dns_info_ex = True >+ > for pac_buffer in pac.buffers: > if pac_buffer.type == krb5pac.PAC_TYPE_CONSTRAINED_DELEGATION: > expected_proxy_target = kdc_exchange_dict[ >@@ -2618,6 +2632,31 @@ class RawKerberosTest(TestCaseInTempDir): > expected_rid = int(expected_sid.rsplit('-', 1)[1]) > self.assertEqual(expected_rid, logon_info.rid) > >+ elif pac_buffer.type == krb5pac.PAC_TYPE_UPN_DNS_INFO: >+ upn_dns_info = pac_buffer.info >+ upn_dns_info_ex = upn_dns_info.ex >+ >+ expected_realm = kdc_exchange_dict['expected_crealm'] >+ self.assertEqual(expected_realm, >+ upn_dns_info.dns_domain_name) >+ >+ expected_upn_name = kdc_exchange_dict['expected_upn_name'] >+ if expected_upn_name is not None: >+ self.assertEqual(expected_upn_name, >+ upn_dns_info.upn_name) >+ >+ if expect_upn_dns_info_ex: >+ self.assertIsNotNone(upn_dns_info_ex) >+ >+ if upn_dns_info_ex is not None: >+ if expected_account_name is not None: >+ self.assertEqual(expected_account_name, >+ upn_dns_info_ex.samaccountname) >+ >+ if expected_sid is not None: >+ self.assertEqual(expected_sid, >+ str(upn_dns_info_ex.objectsid)) >+ > def generic_check_kdc_error(self, > kdc_exchange_dict, > callback_dict, >@@ -3600,6 +3639,7 @@ class RawKerberosTest(TestCaseInTempDir): > padata, > kdc_options, > expected_account_name=None, >+ expected_upn_name=None, > expected_sid=None, > expected_flags=None, > unexpected_flags=None, >@@ -3634,6 +3674,7 @@ class RawKerberosTest(TestCaseInTempDir): > expected_srealm=expected_srealm, > expected_sname=expected_sname, > expected_account_name=expected_account_name, >+ expected_upn_name=expected_upn_name, > expected_sid=expected_sid, > expected_supported_etypes=expected_supported_etypes, > ticket_decryption_key=ticket_decryption_key, >diff --git a/python/samba/tests/krb5/s4u_tests.py b/python/samba/tests/krb5/s4u_tests.py >index a80a7b3427e0..5005affd6b39 100755 >--- a/python/samba/tests/krb5/s4u_tests.py >+++ b/python/samba/tests/krb5/s4u_tests.py >@@ -309,6 +309,7 @@ class S4UKerberosTests(KDCBaseTest): > tgt=service_tgt, > authenticator_subkey=authenticator_subkey, > kdc_options=str(kdc_options), >+ expect_upn_dns_info_ex=False, > expect_claims=False) > > self._generic_kdc_exchange(kdc_exchange_dict, >@@ -610,6 +611,7 @@ class S4UKerberosTests(KDCBaseTest): > kdc_options=kdc_options, > pac_options=pac_options, > expect_edata=expect_edata, >+ expect_upn_dns_info_ex=False, > expected_proxy_target=expected_proxy_target, > expected_transited_services=expected_transited_services, > expect_pac=expect_pac) >diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc >index 572fbb0e0cde..468668235907 100644 >--- a/selftest/knownfail_heimdal_kdc >+++ b/selftest/knownfail_heimdal_kdc >@@ -317,6 +317,10 @@ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_upn_dns_info_ex_mac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_upn_dns_info_ex_upn_mac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_upn_dns_info_ex_upn_user >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_upn_dns_info_ex_user > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_matching_sname_host > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_matching_sname_no_host >diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc >index 127fcdc425d5..d2acc5559ed5 100644 >--- a/selftest/knownfail_mit_kdc >+++ b/selftest/knownfail_mit_kdc >@@ -436,6 +436,10 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_ > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_existing > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_sid_mismatch_nonexisting >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_upn_dns_info_ex_mac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_upn_dns_info_ex_upn_mac >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_upn_dns_info_ex_upn_user >+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_upn_dns_info_ex_user > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_authdata_no_pac > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_matching_sname_no_host > ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac >-- >2.25.1 > > >From e52eec01f1680d951f6aeb74ea022af6dc1363bf Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 24 Aug 2021 17:11:24 +0200 >Subject: [PATCH 118/262] CVE-2020-25719 CVE-2020-25717 tests/krb5: Add tests > for connecting to services anonymously and without a PAC > >At the end of the patchset we assume NT_STATUS_NO_IMPERSONATION_TOKEN if >no PAC is available. > >For now we want to look for ACCESS_DENIED as this allows >the test to pass (showing that gensec:require_pac = true >is a useful partial mitigation). > >This will also help others doing backports that do not >take the full patch set. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14799 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/test_ccache.py | 31 +++++++++--- > python/samba/tests/krb5/test_ldap.py | 70 ++++++++++++++++++++++---- > python/samba/tests/krb5/test_rpc.py | 46 ++++++++++++++--- > python/samba/tests/krb5/test_smb.py | 31 +++++++++--- > source4/selftest/tests.py | 17 ++++--- > 5 files changed, 158 insertions(+), 37 deletions(-) > >diff --git a/python/samba/tests/krb5/test_ccache.py b/python/samba/tests/krb5/test_ccache.py >index 040ae5cc9a1f..cb5061b92d9c 100755 >--- a/python/samba/tests/krb5/test_ccache.py >+++ b/python/samba/tests/krb5/test_ccache.py >@@ -21,10 +21,11 @@ import sys > import os > > from ldb import SCOPE_SUBTREE >-from samba import gensec >+from samba import NTSTATUSError, gensec > from samba.auth import AuthContext > from samba.dcerpc import security > from samba.ndr import ndr_unpack >+from samba.ntstatus import NT_STATUS_ACCESS_DENIED > > from samba.tests.krb5.kdc_base_test import KDCBaseTest > >@@ -41,11 +42,18 @@ class CcacheTests(KDCBaseTest): > """ > > def test_ccache(self): >+ self._run_ccache_test("ccacheusr") >+ >+ def test_ccache_no_pac(self): >+ self._run_ccache_test("ccacheusr_nopac", include_pac=False, >+ expect_anon=True, allow_error=True) >+ >+ def _run_ccache_test(self, user_name, include_pac=True, >+ expect_anon=False, allow_error=False): > # Create a user account and a machine account, along with a Kerberos > # credentials cache file where the service ticket authenticating the > # user are stored. > >- user_name = "ccacheusr" > mach_name = "ccachemac" > service = "host" > >@@ -67,7 +75,10 @@ class CcacheTests(KDCBaseTest): > # ticket, to ensure that the krbtgt ticket doesn't also need to be > # stored. > (creds, cachefile) = self.create_ccache_with_user(user_credentials, >- mach_credentials) >+ mach_credentials, >+ pac=include_pac) >+ # Remove the cached credentials file. >+ self.addCleanup(os.remove, cachefile.name) > > # Authenticate in-process to the machine account using the user's > # cached credentials. >@@ -117,7 +128,16 @@ class CcacheTests(KDCBaseTest): > sid = ndr_unpack(security.dom_sid, ldb_res[0]["objectSid"][0]) > > # Retrieve the SIDs from the security token. >- session = gensec_server.session_info() >+ try: >+ session = gensec_server.session_info() >+ except NTSTATUSError as e: >+ if not allow_error: >+ self.fail() >+ >+ enum, _ = e.args >+ self.assertEqual(NT_STATUS_ACCESS_DENIED, enum) >+ return >+ > token = session.security_token > token_sids = token.sids > self.assertGreater(len(token_sids), 0) >@@ -125,9 +145,6 @@ class CcacheTests(KDCBaseTest): > # Ensure that they match. > self.assertEqual(sid, token_sids[0]) > >- # Remove the cached credentials file. >- os.remove(cachefile.name) >- > > if __name__ == "__main__": > global_asn1_print = False >diff --git a/python/samba/tests/krb5/test_ldap.py b/python/samba/tests/krb5/test_ldap.py >index 7d9ffebe2985..31e50487338b 100755 >--- a/python/samba/tests/krb5/test_ldap.py >+++ b/python/samba/tests/krb5/test_ldap.py >@@ -20,10 +20,11 @@ > import sys > import os > >-from ldb import SCOPE_BASE, SCOPE_SUBTREE >+from ldb import LdbError, ERR_OPERATIONS_ERROR, SCOPE_BASE, SCOPE_SUBTREE > from samba.dcerpc import security > from samba.ndr import ndr_unpack > from samba.samdb import SamDB >+from samba import credentials > > from samba.tests.krb5.kdc_base_test import KDCBaseTest > >@@ -40,13 +41,20 @@ class LdapTests(KDCBaseTest): > """ > > def test_ldap(self): >+ self._run_ldap_test("ldapusr") >+ >+ def test_ldap_no_pac(self): >+ self._run_ldap_test("ldapusr_nopac", include_pac=False, >+ expect_anon=True, allow_error=True) >+ >+ def _run_ldap_test(self, user_name, include_pac=True, >+ expect_anon=False, allow_error=False): > # Create a user account and a machine account, along with a Kerberos > # credentials cache file where the service ticket authenticating the > # user are stored. > > samdb = self.get_samdb() > >- user_name = "ldapusr" > mach_name = samdb.host_dns_name() > service = "ldap" > >@@ -62,7 +70,10 @@ class LdapTests(KDCBaseTest): > (creds, cachefile) = self.create_ccache_with_user(user_credentials, > mach_credentials, > service, >- mach_name) >+ mach_name, >+ pac=include_pac) >+ # Remove the cached credentials file. >+ self.addCleanup(os.remove, cachefile.name) > > # Authenticate in-process to the machine account using the user's > # cached credentials. >@@ -74,22 +85,61 @@ class LdapTests(KDCBaseTest): > self.assertEqual(1, len(ldb_res)) > sid = ndr_unpack(security.dom_sid, ldb_res[0]["objectSid"][0]) > >+ # Connect to the machine account and retrieve the user SID. >+ try: >+ ldb_as_user = SamDB(url="ldap://%s" % mach_name, >+ credentials=creds, >+ lp=self.get_lp()) >+ except LdbError as e: >+ if not allow_error: >+ self.fail() >+ >+ enum, estr = e.args >+ self.assertEqual(ERR_OPERATIONS_ERROR, enum) >+ self.assertIn('NT_STATUS_ACCESS_DENIED', estr) >+ return >+ >+ ldb_res = ldb_as_user.search('', >+ scope=SCOPE_BASE, >+ attrs=["tokenGroups"]) >+ self.assertEqual(1, len(ldb_res)) >+ >+ token_groups = ldb_res[0]["tokenGroups"] >+ token_sid = ndr_unpack(security.dom_sid, token_groups[0]) >+ >+ if expect_anon: >+ # Ensure we got an anonymous token. >+ self.assertEqual(security.SID_NT_ANONYMOUS, str(token_sid)) >+ token_sid = ndr_unpack(security.dom_sid, token_groups[1]) >+ self.assertEqual(security.SID_NT_NETWORK, str(token_sid)) >+ if len(token_groups) >= 3: >+ token_sid = ndr_unpack(security.dom_sid, token_groups[2]) >+ self.assertEqual(security.SID_NT_THIS_ORGANISATION, >+ str(token_sid)) >+ else: >+ # Ensure that they match. >+ self.assertEqual(sid, token_sid) >+ >+ def test_ldap_anonymous(self): >+ samdb = self.get_samdb() >+ mach_name = samdb.host_dns_name() >+ >+ anon_creds = credentials.Credentials() >+ anon_creds.set_anonymous() >+ > # Connect to the machine account and retrieve the user SID. > ldb_as_user = SamDB(url="ldap://%s" % mach_name, >- credentials=creds, >+ credentials=anon_creds, > lp=self.get_lp()) > ldb_res = ldb_as_user.search('', > scope=SCOPE_BASE, > attrs=["tokenGroups"]) > self.assertEqual(1, len(ldb_res)) > >+ # Ensure we got an anonymous token. > token_sid = ndr_unpack(security.dom_sid, ldb_res[0]["tokenGroups"][0]) >- >- # Ensure that they match. >- self.assertEqual(sid, token_sid) >- >- # Remove the cached credentials file. >- os.remove(cachefile.name) >+ self.assertEqual(security.SID_NT_ANONYMOUS, str(token_sid)) >+ self.assertEqual(len(ldb_res[0]["tokenGroups"]), 1) > > > if __name__ == "__main__": >diff --git a/python/samba/tests/krb5/test_rpc.py b/python/samba/tests/krb5/test_rpc.py >index ef8dd4dcbf5b..54ad7cf0e481 100755 >--- a/python/samba/tests/krb5/test_rpc.py >+++ b/python/samba/tests/krb5/test_rpc.py >@@ -20,7 +20,9 @@ > import sys > import os > >+from samba import NTSTATUSError, credentials > from samba.dcerpc import lsa >+from samba.ntstatus import NT_STATUS_ACCESS_DENIED > > from samba.tests.krb5.kdc_base_test import KDCBaseTest > >@@ -37,13 +39,20 @@ class RpcTests(KDCBaseTest): > """ > > def test_rpc(self): >+ self._run_rpc_test("rpcusr") >+ >+ def test_rpc_no_pac(self): >+ self._run_rpc_test("rpcusr_nopac", include_pac=False, >+ expect_anon=True, allow_error=True) >+ >+ def _run_rpc_test(self, user_name, include_pac=True, >+ expect_anon=False, allow_error=False): > # Create a user account and a machine account, along with a Kerberos > # credentials cache file where the service ticket authenticating the > # user are stored. > > samdb = self.get_samdb() > >- user_name = "rpcusr" > mach_name = samdb.host_dns_name() > service = "cifs" > >@@ -59,20 +68,45 @@ class RpcTests(KDCBaseTest): > (creds, cachefile) = self.create_ccache_with_user(user_credentials, > mach_credentials, > service, >- mach_name) >+ mach_name, >+ pac=include_pac) >+ # Remove the cached credentials file. >+ self.addCleanup(os.remove, cachefile.name) > > # Authenticate in-process to the machine account using the user's > # cached credentials. > > binding_str = "ncacn_np:%s[\\pipe\\lsarpc]" % mach_name >- conn = lsa.lsarpc(binding_str, self.get_lp(), creds) >+ try: >+ conn = lsa.lsarpc(binding_str, self.get_lp(), creds) >+ except NTSTATUSError as e: >+ if not allow_error: >+ self.fail() >+ >+ enum, _ = e.args >+ self.assertEqual(NT_STATUS_ACCESS_DENIED, enum) >+ return > > (account_name, _) = conn.GetUserName(None, None, None) > >- self.assertEqual(user_name, account_name.string) >+ if expect_anon: >+ self.assertNotEqual(user_name, account_name.string) >+ else: >+ self.assertEqual(user_name, account_name.string) > >- # Remove the cached credentials file. >- os.remove(cachefile.name) >+ def test_rpc_anonymous(self): >+ samdb = self.get_samdb() >+ mach_name = samdb.host_dns_name() >+ >+ anon_creds = credentials.Credentials() >+ anon_creds.set_anonymous() >+ >+ binding_str = "ncacn_np:%s[\\pipe\\lsarpc]" % mach_name >+ conn = lsa.lsarpc(binding_str, self.get_lp(), anon_creds) >+ >+ (account_name, _) = conn.GetUserName(None, None, None) >+ >+ self.assertEqual('ANONYMOUS LOGON', account_name.string) > > > if __name__ == "__main__": >diff --git a/python/samba/tests/krb5/test_smb.py b/python/samba/tests/krb5/test_smb.py >index 1e70ed322bfc..79ff16ac8795 100755 >--- a/python/samba/tests/krb5/test_smb.py >+++ b/python/samba/tests/krb5/test_smb.py >@@ -21,8 +21,10 @@ import sys > import os > > from ldb import SCOPE_SUBTREE >+from samba import NTSTATUSError > from samba.dcerpc import security > from samba.ndr import ndr_unpack >+from samba.ntstatus import NT_STATUS_ACCESS_DENIED > from samba.samba3 import libsmb_samba_internal as libsmb > from samba.samba3 import param as s3param > >@@ -41,13 +43,20 @@ class SmbTests(KDCBaseTest): > """ > > def test_smb(self): >+ self._run_smb_test("smbusr") >+ >+ def test_smb_no_pac(self): >+ self._run_smb_test("smbusr_nopac", include_pac=False, >+ expect_error=True) >+ >+ def _run_smb_test(self, user_name, include_pac=True, >+ expect_error=False): > # Create a user account and a machine account, along with a Kerberos > # credentials cache file where the service ticket authenticating the > # user are stored. > > samdb = self.get_samdb() > >- user_name = "smbusr" > mach_name = samdb.host_dns_name() > service = "cifs" > share = "tmp" >@@ -64,7 +73,10 @@ class SmbTests(KDCBaseTest): > (creds, cachefile) = self.create_ccache_with_user(user_credentials, > mach_credentials, > service, >- mach_name) >+ mach_name, >+ pac=include_pac) >+ # Remove the cached credentials file. >+ self.addCleanup(os.remove, cachefile.name) > > # Set the Kerberos 5 credentials cache environment variable. This is > # required because the codepath that gets run (gse_krb5) looks for it >@@ -95,16 +107,23 @@ class SmbTests(KDCBaseTest): > self.addCleanup(s3_lp.set, "client max protocol", max_protocol) > s3_lp.set("client max protocol", "NT1") > >- conn = libsmb.Conn(mach_name, share, lp=s3_lp, creds=creds) >+ try: >+ conn = libsmb.Conn(mach_name, share, lp=s3_lp, creds=creds) >+ except NTSTATUSError as e: >+ if not expect_error: >+ self.fail() >+ >+ enum, _ = e.args >+ self.assertEqual(NT_STATUS_ACCESS_DENIED, enum) >+ return >+ else: >+ self.assertFalse(expect_error) > > (uid, gid, gids, sids, guest) = conn.posix_whoami() > > # Ensure that they match. > self.assertEqual(sid, sids[0]) > >- # Remove the cached credentials file. >- os.remove(cachefile.name) >- > > if __name__ == "__main__": > global_asn1_print = False >diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py >index 53721d1afda6..bd68094436fb 100755 >--- a/source4/selftest/tests.py >+++ b/source4/selftest/tests.py >@@ -828,14 +828,15 @@ planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ldap", > 'FAST_SUPPORT': have_fast_support, > 'TKT_SIG_SUPPORT': tkt_sig_support > }) >-planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_rpc", >- environ={ >- 'ADMIN_USERNAME': '$USERNAME', >- 'ADMIN_PASSWORD': '$PASSWORD', >- 'STRICT_CHECKING': '0', >- 'FAST_SUPPORT': have_fast_support, >- 'TKT_SIG_SUPPORT': tkt_sig_support >- }) >+for env in ['ad_dc_default', 'ad_member']: >+ planoldpythontestsuite(env, "samba.tests.krb5.test_rpc", >+ environ={ >+ 'ADMIN_USERNAME': '$DC_USERNAME', >+ 'ADMIN_PASSWORD': '$DC_PASSWORD', >+ 'STRICT_CHECKING': '0', >+ 'FAST_SUPPORT': have_fast_support, >+ 'TKT_SIG_SUPPORT': tkt_sig_support >+ }) > planoldpythontestsuite("ad_dc_smb1", "samba.tests.krb5.test_smb", > environ={ > 'ADMIN_USERNAME': '$USERNAME', >-- >2.25.1 > > >From 8b020fbbf3ebe2979e7e3064ac0c7dcdee286a3e Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 22 Oct 2021 16:20:36 +0200 >Subject: [PATCH 119/262] CVE-2020-25719 CVE-2020-25717: selftest: remove > "gensec:require_pac" settings > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14799 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 > >[jsutton@samba.org Added knownfail entries] > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > selftest/knownfail.d/no-pac | 4 ++++ > selftest/selftest.pl | 2 -- > selftest/target/Samba4.pm | 2 -- > 3 files changed, 4 insertions(+), 4 deletions(-) > create mode 100644 selftest/knownfail.d/no-pac > >diff --git a/selftest/knownfail.d/no-pac b/selftest/knownfail.d/no-pac >new file mode 100644 >index 000000000000..9723d581c2a1 >--- /dev/null >+++ b/selftest/knownfail.d/no-pac >@@ -0,0 +1,4 @@ >+^samba.tests.krb5.test_ccache.samba.tests.krb5.test_ccache.CcacheTests.test_ccache_no_pac >+^samba.tests.krb5.test_ldap.samba.tests.krb5.test_ldap.LdapTests.test_ldap_no_pac >+^samba.tests.krb5.test_rpc.samba.tests.krb5.test_rpc.RpcTests.test_rpc_no_pac >+^samba.tests.krb5.test_smb.samba.tests.krb5.test_smb.SmbTests.test_smb_no_pac >diff --git a/selftest/selftest.pl b/selftest/selftest.pl >index 258a8437922c..48792b59bf19 100755 >--- a/selftest/selftest.pl >+++ b/selftest/selftest.pl >@@ -609,8 +609,6 @@ sub write_clientconf($$$) > client min protocol = CORE > log level = 1 > torture:basedir = $clientdir >-#We don't want to pass our self-tests if the PAC code is wrong >- gensec:require_pac = true > #We don't want to run 'speed' tests for very long > torture:timelimit = 1 > winbind separator = / >diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm >index 7c17060dcb04..156dc16bda0e 100755 >--- a/selftest/target/Samba4.pm >+++ b/selftest/target/Samba4.pm >@@ -777,8 +777,6 @@ sub provision_raw_step1($$) > notify:inotify = false > ldb:nosync = true > ldap server require strong auth = yes >-#We don't want to pass our self-tests if the PAC code is wrong >- gensec:require_pac = true > log file = $ctx->{logdir}/log.\%m > log level = $ctx->{server_loglevel} > lanman auth = Yes >-- >2.25.1 > > >From 46deede5cf067689d329fe6f2810f8b7922b7562 Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Fri, 29 Oct 2021 10:27:41 +1300 >Subject: [PATCH 120/262] CVE-2020-25719 CVE-2020-25717 tests/krb5: Adapt tests > for connecting without a PAC to new error codes > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14799 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/krb5/test_ccache.py | 5 +++-- > python/samba/tests/krb5/test_ldap.py | 2 +- > python/samba/tests/krb5/test_rpc.py | 4 ++-- > python/samba/tests/krb5/test_smb.py | 4 ++-- > 4 files changed, 8 insertions(+), 7 deletions(-) > >diff --git a/python/samba/tests/krb5/test_ccache.py b/python/samba/tests/krb5/test_ccache.py >index cb5061b92d9c..d21ec84796e5 100755 >--- a/python/samba/tests/krb5/test_ccache.py >+++ b/python/samba/tests/krb5/test_ccache.py >@@ -25,7 +25,7 @@ from samba import NTSTATUSError, gensec > from samba.auth import AuthContext > from samba.dcerpc import security > from samba.ndr import ndr_unpack >-from samba.ntstatus import NT_STATUS_ACCESS_DENIED >+from samba.ntstatus import NT_STATUS_NO_IMPERSONATION_TOKEN > > from samba.tests.krb5.kdc_base_test import KDCBaseTest > >@@ -84,6 +84,7 @@ class CcacheTests(KDCBaseTest): > # cached credentials. > > lp = self.get_lp() >+ lp.set('server role', 'active directory domain controller') > > settings = {} > settings["lp_ctx"] = lp >@@ -135,7 +136,7 @@ class CcacheTests(KDCBaseTest): > self.fail() > > enum, _ = e.args >- self.assertEqual(NT_STATUS_ACCESS_DENIED, enum) >+ self.assertEqual(NT_STATUS_NO_IMPERSONATION_TOKEN, enum) > return > > token = session.security_token >diff --git a/python/samba/tests/krb5/test_ldap.py b/python/samba/tests/krb5/test_ldap.py >index 31e50487338b..0205bdf6fb73 100755 >--- a/python/samba/tests/krb5/test_ldap.py >+++ b/python/samba/tests/krb5/test_ldap.py >@@ -96,7 +96,7 @@ class LdapTests(KDCBaseTest): > > enum, estr = e.args > self.assertEqual(ERR_OPERATIONS_ERROR, enum) >- self.assertIn('NT_STATUS_ACCESS_DENIED', estr) >+ self.assertIn('NT_STATUS_NO_IMPERSONATION_TOKEN', estr) > return > > ldb_res = ldb_as_user.search('', >diff --git a/python/samba/tests/krb5/test_rpc.py b/python/samba/tests/krb5/test_rpc.py >index 54ad7cf0e481..0f2170a8dede 100755 >--- a/python/samba/tests/krb5/test_rpc.py >+++ b/python/samba/tests/krb5/test_rpc.py >@@ -22,7 +22,7 @@ import os > > from samba import NTSTATUSError, credentials > from samba.dcerpc import lsa >-from samba.ntstatus import NT_STATUS_ACCESS_DENIED >+from samba.ntstatus import NT_STATUS_NO_IMPERSONATION_TOKEN > > from samba.tests.krb5.kdc_base_test import KDCBaseTest > >@@ -84,7 +84,7 @@ class RpcTests(KDCBaseTest): > self.fail() > > enum, _ = e.args >- self.assertEqual(NT_STATUS_ACCESS_DENIED, enum) >+ self.assertEqual(NT_STATUS_NO_IMPERSONATION_TOKEN, enum) > return > > (account_name, _) = conn.GetUserName(None, None, None) >diff --git a/python/samba/tests/krb5/test_smb.py b/python/samba/tests/krb5/test_smb.py >index 79ff16ac8795..7408e5dbecea 100755 >--- a/python/samba/tests/krb5/test_smb.py >+++ b/python/samba/tests/krb5/test_smb.py >@@ -24,7 +24,7 @@ from ldb import SCOPE_SUBTREE > from samba import NTSTATUSError > from samba.dcerpc import security > from samba.ndr import ndr_unpack >-from samba.ntstatus import NT_STATUS_ACCESS_DENIED >+from samba.ntstatus import NT_STATUS_NO_IMPERSONATION_TOKEN > from samba.samba3 import libsmb_samba_internal as libsmb > from samba.samba3 import param as s3param > >@@ -114,7 +114,7 @@ class SmbTests(KDCBaseTest): > self.fail() > > enum, _ = e.args >- self.assertEqual(NT_STATUS_ACCESS_DENIED, enum) >+ self.assertEqual(NT_STATUS_NO_IMPERSONATION_TOKEN, enum) > return > else: > self.assertFalse(expect_error) >-- >2.25.1 > > >From 823ea0a8cf64c40506556d43f76c4ed0ef486e2f Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Mon, 4 Oct 2021 17:29:34 +0200 >Subject: [PATCH 121/262] CVE-2020-25717: s3:winbindd: make sure we default to > r->out.authoritative = true > >We need to make sure that temporary failures don't trigger a fallback >to the local SAM that silently ignores the domain name part for users. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/winbindd/winbindd_dual_srv.c | 7 +++++++ > source3/winbindd/winbindd_irpc.c | 7 +++++++ > source3/winbindd/winbindd_pam.c | 15 +++++++++++---- > source3/winbindd/winbindd_pam_auth_crap.c | 9 ++++++++- > source3/winbindd/winbindd_util.c | 7 +++++++ > 5 files changed, 40 insertions(+), 5 deletions(-) > >diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c >index 4a4894c2658a..078fa77aed62 100644 >--- a/source3/winbindd/winbindd_dual_srv.c >+++ b/source3/winbindd/winbindd_dual_srv.c >@@ -940,6 +940,13 @@ NTSTATUS _winbind_SamLogon(struct pipes_struct *p, > union netr_Validation *validation = NULL; > bool interactive = false; > >+ /* >+ * Make sure we start with authoritative=true, >+ * it will only set to false if we don't know the >+ * domain. >+ */ >+ r->out.authoritative = true; >+ > domain = wb_child_domain(); > if (domain == NULL) { > return NT_STATUS_REQUEST_NOT_ACCEPTED; >diff --git a/source3/winbindd/winbindd_irpc.c b/source3/winbindd/winbindd_irpc.c >index fda29c7e7022..12f4554f9b6b 100644 >--- a/source3/winbindd/winbindd_irpc.c >+++ b/source3/winbindd/winbindd_irpc.c >@@ -141,6 +141,13 @@ static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg, > const char *target_domain_name = NULL; > const char *account_name = NULL; > >+ /* >+ * Make sure we start with authoritative=true, >+ * it will only set to false if we don't know the >+ * domain. >+ */ >+ req->out.authoritative = true; >+ > switch (req->in.logon_level) { > case NetlogonInteractiveInformation: > case NetlogonServiceInformation: >diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c >index c49033b375df..59dd18e27b86 100644 >--- a/source3/winbindd/winbindd_pam.c >+++ b/source3/winbindd/winbindd_pam.c >@@ -1797,7 +1797,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon( > { > fstring name_namespace, name_domain, name_user; > NTSTATUS result; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uint32_t flags = 0; > uint16_t validation_level = 0; > union netr_Validation *validation = NULL; >@@ -2451,6 +2451,13 @@ done: > result = NT_STATUS_NO_LOGON_SERVERS; > } > >+ /* >+ * Here we don't alter >+ * state->response->data.auth.authoritative based >+ * on the servers response >+ * as we don't want a fallback to the local sam >+ * for interactive PAM logons >+ */ > set_auth_errors(state->response, result); > > DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n", >@@ -2665,7 +2672,7 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, > const char *name_domain = NULL; > const char *workstation; > uint64_t logon_id = 0; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uint32_t flags = 0; > uint16_t validation_level; > union netr_Validation *validation = NULL; >@@ -2738,7 +2745,6 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, > &validation_level, > &validation); > if (!NT_STATUS_IS_OK(result)) { >- state->response->data.auth.authoritative = authoritative; > goto done; > } > >@@ -2770,7 +2776,6 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, > "from firewalled domain [%s]\n", > info3->base.account_name.string, > info3->base.logon_domain.string); >- state->response->data.auth.authoritative = true; > result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED; > goto done; > } >@@ -2792,6 +2797,8 @@ done: > } > > set_auth_errors(state->response, result); >+ state->response->data.auth.authoritative = authoritative; >+ > /* > * Log the winbind pam authentication, the logon_id will tie this to > * any of the logons invoked from this request. >diff --git a/source3/winbindd/winbindd_pam_auth_crap.c b/source3/winbindd/winbindd_pam_auth_crap.c >index b7912db43df2..40cab81b5ea9 100644 >--- a/source3/winbindd/winbindd_pam_auth_crap.c >+++ b/source3/winbindd/winbindd_pam_auth_crap.c >@@ -24,6 +24,7 @@ > > struct winbindd_pam_auth_crap_state { > struct winbindd_response *response; >+ bool authoritative; > uint32_t flags; > }; > >@@ -45,7 +46,7 @@ struct tevent_req *winbindd_pam_auth_crap_send( > if (req == NULL) { > return NULL; > } >- >+ state->authoritative = true; > state->flags = request->flags; > > if (state->flags & WBFLAG_PAM_AUTH_PAC) { >@@ -124,6 +125,11 @@ struct tevent_req *winbindd_pam_auth_crap_send( > > domain = find_auth_domain(request->flags, auth_domain); > if (domain == NULL) { >+ /* >+ * We don't know the domain so >+ * we're not authoritative >+ */ >+ state->authoritative = false; > tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); > return tevent_req_post(req, ev); > } >@@ -184,6 +190,7 @@ NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req, > > if (tevent_req_is_nterror(req, &status)) { > set_auth_errors(response, status); >+ response->data.auth.authoritative = state->authoritative; > return status; > } > >diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c >index bec706f87dea..ef197310fa0c 100644 >--- a/source3/winbindd/winbindd_util.c >+++ b/source3/winbindd/winbindd_util.c >@@ -2092,6 +2092,13 @@ void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain) > > void set_auth_errors(struct winbindd_response *resp, NTSTATUS result) > { >+ /* >+ * Make sure we start with authoritative=true, >+ * it will only set to false if we don't know the >+ * domain. >+ */ >+ resp->data.auth.authoritative = true; >+ > resp->data.auth.nt_status = NT_STATUS_V(result); > fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result)); > >-- >2.25.1 > > >From 3c0d0e3ffc9789af2e27471a6dcc5767718f257b Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Mon, 4 Oct 2021 17:29:34 +0200 >Subject: [PATCH 122/262] CVE-2020-25717: s4:auth/ntlm: make sure > auth_check_password() defaults to r->out.authoritative = true > >We need to make sure that temporary failures don't trigger a fallback >to the local SAM that silently ignores the domain name part for users. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/auth/ntlm/auth.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c >index 1aa2e3b065fc..e0c4436343cd 100644 >--- a/source4/auth/ntlm/auth.c >+++ b/source4/auth/ntlm/auth.c >@@ -169,6 +169,11 @@ _PUBLIC_ NTSTATUS auth_check_password(struct auth4_context *auth_ctx, > /*TODO: create a new event context here! */ > ev = auth_ctx->event_ctx; > >+ /* >+ * We are authoritative by default >+ */ >+ *pauthoritative = 1; >+ > subreq = auth_check_password_send(mem_ctx, > ev, > auth_ctx, >-- >2.25.1 > > >From 68a1b75a45b31ac0d43847964b6411925cc150b8 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 26 Oct 2021 17:42:41 +0200 >Subject: [PATCH 123/262] CVE-2020-25717: s4:torture: start with authoritative > = 1 > >This is not strictly needed, but makes it easier to audit >that we don't miss important places. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/torture/rpc/samlogon.c | 4 ++-- > source4/torture/rpc/schannel.c | 2 +- > 2 files changed, 3 insertions(+), 3 deletions(-) > >diff --git a/source4/torture/rpc/samlogon.c b/source4/torture/rpc/samlogon.c >index 76933b8869ee..703e25fe3c51 100644 >--- a/source4/torture/rpc/samlogon.c >+++ b/source4/torture/rpc/samlogon.c >@@ -1407,7 +1407,7 @@ static bool test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, > > union netr_LogonLevel logon; > union netr_Validation validation; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uint32_t flags = 0; > > ZERO_STRUCT(logon); >@@ -1520,7 +1520,7 @@ bool test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, > > union netr_LogonLevel logon; > union netr_Validation validation; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > struct dcerpc_binding_handle *b = p->binding_handle; > > ZERO_STRUCT(a); >diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c >index fff0b1aacbdd..6dc58c860760 100644 >--- a/source4/torture/rpc/schannel.c >+++ b/source4/torture/rpc/schannel.c >@@ -50,7 +50,7 @@ bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx, > struct netr_NetworkInfo ninfo; > union netr_LogonLevel logon; > union netr_Validation validation; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uint32_t _flags = 0; > DATA_BLOB names_blob, chal, lm_resp, nt_resp; > int i; >-- >2.25.1 > > >From db7179bd762f2d61e505b093485e59c5d012bb60 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 26 Oct 2021 17:42:41 +0200 >Subject: [PATCH 124/262] CVE-2020-25717: s4:smb_server: start with > authoritative = 1 > >This is not strictly needed, but makes it easier to audit >that we don't miss important places. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/smb_server/smb/sesssetup.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > >diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c >index 13f139344120..5e817eecd4b6 100644 >--- a/source4/smb_server/smb/sesssetup.c >+++ b/source4/smb_server/smb/sesssetup.c >@@ -102,7 +102,7 @@ static void sesssetup_old_send(struct tevent_req *subreq) > struct auth_session_info *session_info; > struct smbsrv_session *smb_sess; > NTSTATUS status; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uint32_t flags; > > status = auth_check_password_recv(subreq, req, &user_info_dc, >@@ -243,7 +243,7 @@ static void sesssetup_nt1_send(struct tevent_req *subreq) > struct auth_user_info_dc *user_info_dc = NULL; > struct auth_session_info *session_info; > struct smbsrv_session *smb_sess; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uint32_t flags; > NTSTATUS status; > >-- >2.25.1 > > >From c83293e927093ee7aef64d62f717fe7896ed0f97 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 26 Oct 2021 17:42:41 +0200 >Subject: [PATCH 125/262] CVE-2020-25717: s4:auth_simple: start with > authoritative = 1 > >This is not strictly needed, but makes it easier to audit >that we don't miss important places. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/auth/ntlm/auth_simple.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source4/auth/ntlm/auth_simple.c b/source4/auth/ntlm/auth_simple.c >index 8df160cefc37..8301aec519ca 100644 >--- a/source4/auth/ntlm/auth_simple.c >+++ b/source4/auth/ntlm/auth_simple.c >@@ -150,7 +150,7 @@ static void authenticate_ldap_simple_bind_done(struct tevent_req *subreq) > const struct tsocket_address *local_address = user_info->local_host; > const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE; > struct auth_user_info_dc *user_info_dc = NULL; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uint32_t flags = 0; > NTSTATUS nt_status; > >-- >2.25.1 > > >From ff4ee6ae8c69a6d636d2884b462f1920b7667972 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 26 Oct 2021 17:42:41 +0200 >Subject: [PATCH 126/262] CVE-2020-25717: s3:ntlm_auth: start with > authoritative = 1 > >This is not strictly needed, but makes it easier to audit >that we don't miss important places. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/utils/ntlm_auth.c | 4 ++-- > source3/utils/ntlm_auth_diagnostics.c | 10 +++++----- > 2 files changed, 7 insertions(+), 7 deletions(-) > >diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c >index 7f8d2688978d..1d22a48c57ce 100644 >--- a/source3/utils/ntlm_auth.c >+++ b/source3/utils/ntlm_auth.c >@@ -1926,7 +1926,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod > TALLOC_FREE(mem_ctx); > > } else { >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > > if (!domain) { > domain = smb_xstrdup(get_winbind_domain()); >@@ -2442,7 +2442,7 @@ static bool check_auth_crap(void) > char *hex_lm_key; > char *hex_user_session_key; > char *error_string; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > > setbuf(stdout, NULL); > >diff --git a/source3/utils/ntlm_auth_diagnostics.c b/source3/utils/ntlm_auth_diagnostics.c >index 41591a8de339..fc0fc19bacb4 100644 >--- a/source3/utils/ntlm_auth_diagnostics.c >+++ b/source3/utils/ntlm_auth_diagnostics.c >@@ -54,7 +54,7 @@ static bool test_lm_ntlm_broken(enum ntlm_break break_which) > DATA_BLOB lm_response = data_blob(NULL, 24); > DATA_BLOB nt_response = data_blob(NULL, 24); > DATA_BLOB session_key = data_blob(NULL, 16); >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uchar lm_key[8]; > uchar user_session_key[16]; > uchar lm_hash[16]; >@@ -177,7 +177,7 @@ static bool test_ntlm_in_lm(void) > NTSTATUS nt_status; > uint32_t flags = 0; > DATA_BLOB nt_response = data_blob(NULL, 24); >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uchar lm_key[8]; > uchar lm_hash[16]; > uchar user_session_key[16]; >@@ -245,7 +245,7 @@ static bool test_ntlm_in_both(void) > uint32_t flags = 0; > DATA_BLOB nt_response = data_blob(NULL, 24); > DATA_BLOB session_key = data_blob(NULL, 16); >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uint8_t lm_key[8]; > uint8_t lm_hash[16]; > uint8_t user_session_key[16]; >@@ -322,7 +322,7 @@ static bool test_lmv2_ntlmv2_broken(enum ntlm_break break_which) > DATA_BLOB lmv2_response = data_blob_null; > DATA_BLOB ntlmv2_session_key = data_blob_null; > DATA_BLOB names_blob = NTLMv2_generate_names_blob(NULL, get_winbind_netbios_name(), get_winbind_domain()); >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uchar user_session_key[16]; > DATA_BLOB chall = get_challenge(); > char *error_string; >@@ -452,7 +452,7 @@ static bool test_plaintext(enum ntlm_break break_which) > char *password; > smb_ucs2_t *nt_response_ucs2; > size_t converted_size; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uchar user_session_key[16]; > uchar lm_key[16]; > static const uchar zeros[8] = { 0, }; >-- >2.25.1 > > >From b27c621aaa819b0da135fae25c414078cd668f93 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 26 Oct 2021 17:42:41 +0200 >Subject: [PATCH 127/262] CVE-2020-25717: s3:torture: start with authoritative > = 1 > >This is not strictly needed, but makes it easier to audit >that we don't miss important places. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/torture/pdbtest.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source3/torture/pdbtest.c b/source3/torture/pdbtest.c >index 5d74aa9ab780..b300504c4cb4 100644 >--- a/source3/torture/pdbtest.c >+++ b/source3/torture/pdbtest.c >@@ -277,7 +277,7 @@ static bool test_auth(TALLOC_CTX *mem_ctx, struct samu *pdb_entry) > struct netr_SamInfo6 *info6_wbc = NULL; > NTSTATUS status; > bool ok; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > int rc; > > rc = SMBOWFencrypt(pdb_get_nt_passwd(pdb_entry), challenge_8, >-- >2.25.1 > > >From 5a0c128d57977047056659e52fc7958df6f4f762 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 26 Oct 2021 17:42:41 +0200 >Subject: [PATCH 128/262] CVE-2020-25717: s3:rpcclient: start with > authoritative = 1 > >This is not strictly needed, but makes it easier to audit >that we don't miss important places. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/rpcclient/cmd_netlogon.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c >index d5c1b91f2bee..4ea63e40b8db 100644 >--- a/source3/rpcclient/cmd_netlogon.c >+++ b/source3/rpcclient/cmd_netlogon.c >@@ -496,7 +496,7 @@ static NTSTATUS cmd_netlogon_sam_logon(struct rpc_pipe_client *cli, > uint32_t logon_param = 0; > const char *workstation = NULL; > struct netr_SamInfo3 *info3 = NULL; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > uint32_t flags = 0; > uint16_t validation_level; > union netr_Validation *validation = NULL; >-- >2.25.1 > > >From cf0943ca3ca57822db4728f8cda8e0702fd15984 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 26 Oct 2021 17:42:41 +0200 >Subject: [PATCH 129/262] CVE-2020-25717: s3:auth: start with authoritative = 1 > >This is not strictly needed, but makes it easier to audit >that we don't miss important places. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/auth/auth_generic.c | 2 +- > source3/auth/auth_samba4.c | 2 +- > 2 files changed, 2 insertions(+), 2 deletions(-) > >diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c >index 8af744810345..8044e6d8af0b 100644 >--- a/source3/auth/auth_generic.c >+++ b/source3/auth/auth_generic.c >@@ -416,7 +416,7 @@ NTSTATUS auth_check_password_session_info(struct auth4_context *auth_context, > { > NTSTATUS nt_status; > void *server_info; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > struct tevent_context *ev = NULL; > struct tevent_req *subreq = NULL; > bool ok; >diff --git a/source3/auth/auth_samba4.c b/source3/auth/auth_samba4.c >index 418e2cfa56d1..d964160414f5 100644 >--- a/source3/auth/auth_samba4.c >+++ b/source3/auth/auth_samba4.c >@@ -119,7 +119,7 @@ static NTSTATUS check_samba4_security( > NTSTATUS nt_status; > struct auth_user_info_dc *user_info_dc; > struct auth4_context *auth4_context; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > struct auth_serversupplied_info *server_info = NULL; > > nt_status = make_auth4_context_s4(auth_context, mem_ctx, &auth4_context); >-- >2.25.1 > > >From fb30fa19f2f474d8455ba0eb99ae5265c175ff67 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 26 Oct 2021 17:42:41 +0200 >Subject: [PATCH 130/262] CVE-2020-25717: auth/ntlmssp: start with > authoritative = 1 > >This is not strictly needed, but makes it easier to audit >that we don't miss important places. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > auth/ntlmssp/ntlmssp_server.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c >index 001238278d7f..939aa0ef4aa5 100644 >--- a/auth/ntlmssp/ntlmssp_server.c >+++ b/auth/ntlmssp/ntlmssp_server.c >@@ -799,7 +799,7 @@ static void ntlmssp_server_auth_done(struct tevent_req *subreq) > struct gensec_security *gensec_security = state->gensec_security; > struct gensec_ntlmssp_context *gensec_ntlmssp = state->gensec_ntlmssp; > struct auth4_context *auth_context = gensec_security->auth_context; >- uint8_t authoritative = 0; >+ uint8_t authoritative = 1; > NTSTATUS status; > > status = auth_context->check_ntlm_password_recv(subreq, >-- >2.25.1 > > >From 95d8fdf1c799a0e3d6d864550fa4c079c0069f87 Mon Sep 17 00:00:00 2001 >From: Samuel Cabrero <scabrero@samba.org> >Date: Tue, 28 Sep 2021 10:43:40 +0200 >Subject: [PATCH 131/262] CVE-2020-25717: loadparm: Add new parameter "min > domain uid" > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> > >Signed-off-by: Samuel Cabrero <scabrero@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> > >[abartlet@samba.org Backported from master/4.15 due to > conflicts with other new parameters] >--- > docs-xml/smbdotconf/security/mindomainuid.xml | 17 +++++++++++++++++ > docs-xml/smbdotconf/winbind/idmapconfig.xml | 4 ++++ > lib/param/loadparm.c | 4 ++++ > source3/param/loadparm.c | 2 ++ > 4 files changed, 27 insertions(+) > create mode 100644 docs-xml/smbdotconf/security/mindomainuid.xml > >diff --git a/docs-xml/smbdotconf/security/mindomainuid.xml b/docs-xml/smbdotconf/security/mindomainuid.xml >new file mode 100644 >index 000000000000..46ae795d7304 >--- /dev/null >+++ b/docs-xml/smbdotconf/security/mindomainuid.xml >@@ -0,0 +1,17 @@ >+<samba:parameter name="min domain uid" >+ type="integer" >+ context="G" >+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> >+<description> >+ <para> >+ The integer parameter specifies the minimum uid allowed when mapping a >+ local account to a domain account. >+ </para> >+ >+ <para> >+ Note that this option interacts with the configured <emphasis>idmap ranges</emphasis>! >+ </para> >+</description> >+ >+<value type="default">1000</value> >+</samba:parameter> >diff --git a/docs-xml/smbdotconf/winbind/idmapconfig.xml b/docs-xml/smbdotconf/winbind/idmapconfig.xml >index 1374040fb29d..f70f11df7571 100644 >--- a/docs-xml/smbdotconf/winbind/idmapconfig.xml >+++ b/docs-xml/smbdotconf/winbind/idmapconfig.xml >@@ -80,6 +80,9 @@ > authoritative for a unix ID to SID mapping, so it must be set > for each individually configured domain and for the default > configuration. The configured ranges must be mutually disjoint. >+ </para> >+ <para> >+ Note that the low value interacts with the <smbconfoption name="min domain uid"/> option! > </para></listitem> > </varlistentry> > >@@ -115,4 +118,5 @@ > </programlisting> > > </description> >+<related>min domain uid</related> > </samba:parameter> >diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c >index 006caabc092a..d2f6e6241ada 100644 >--- a/lib/param/loadparm.c >+++ b/lib/param/loadparm.c >@@ -3079,6 +3079,10 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) > lpcfg_do_global_parameter( > lp_ctx, "ldap max search request size", "256000"); > >+ lpcfg_do_global_parameter(lp_ctx, >+ "min domain uid", >+ "1000"); >+ > for (i = 0; parm_table[i].label; i++) { > if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) { > lp_ctx->flags[i] |= FLAG_DEFAULT; >diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c >index a3abaa2ec673..301e3622ed47 100644 >--- a/source3/param/loadparm.c >+++ b/source3/param/loadparm.c >@@ -960,6 +960,8 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) > Globals.ldap_max_authenticated_request_size = 16777216; > Globals.ldap_max_search_request_size = 256000; > >+ Globals.min_domain_uid = 1000; >+ > /* Now put back the settings that were set with lp_set_cmdline() */ > apply_lp_set_cmdline(); > } >-- >2.25.1 > > >From a0cfff955d274e41f0039915492a2f03b14c4ffe Mon Sep 17 00:00:00 2001 >From: Samuel Cabrero <scabrero@samba.org> >Date: Tue, 5 Oct 2021 12:31:29 +0200 >Subject: [PATCH 132/262] CVE-2020-25717: selftest: Add ad_member_no_nss_wb > environment > >This environment creates an AD member that doesn't have >'nss_winbind' configured, while winbindd is still started. > >For testing we map a DOMAIN\root user to the local root >account and unix token of the local root user. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> > >Signed-off-by: Samuel Cabrero <scabrero@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> > >[abartlet@samba.org backported to Samba 4.14 without offline > tests in Samba3.pm] >--- > selftest/target/Samba.pm | 1 + > selftest/target/Samba3.pm | 68 +++++++++++++++++++++++++++++++++++---- > 2 files changed, 62 insertions(+), 7 deletions(-) > >diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm >index 1e3b321258fb..6caeb932e28a 100644 >--- a/selftest/target/Samba.pm >+++ b/selftest/target/Samba.pm >@@ -579,6 +579,7 @@ sub get_interface($) > lclnt4dc2smb1 => 55, > fipsdc => 56, > fipsadmember => 57, >+ admemnonsswb => 60, > > rootdnsforwarder => 64, > >diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm >index 9481d1896162..0410e36ffa92 100755 >--- a/selftest/target/Samba3.pm >+++ b/selftest/target/Samba3.pm >@@ -238,6 +238,7 @@ sub check_env($$) > ad_member_idmap_rid => ["ad_dc"], > ad_member_idmap_ad => ["fl2008r2dc"], > ad_member_fips => ["ad_dc_fips"], >+ ad_member_no_nss_wb => ["ad_dc"], > > clusteredmember_smb1 => ["nt4_dc"], > ); >@@ -652,7 +653,9 @@ sub provision_ad_member > $dcvars, > $trustvars_f, > $trustvars_e, >- $force_fips_mode) = @_; >+ $extra_member_options, >+ $force_fips_mode, >+ $no_nss_winbind) = @_; > > my $prefix_abs = abs_path($prefix); > my @dirs = (); >@@ -690,6 +693,10 @@ sub provision_ad_member > $netbios_aliases = "netbios aliases = foo bar"; > } > >+ unless (defined($extra_member_options)) { >+ $extra_member_options = ""; >+ } >+ > my $member_options = " > security = ads > workgroup = $dcvars->{DOMAIN} >@@ -713,6 +720,10 @@ sub provision_ad_member > rpc_daemon:epmd = fork > rpc_daemon:lsasd = fork > >+ # Begin extra member options >+ $extra_member_options >+ # End extra member options >+ > [sub_dug] > path = $share_dir/D_%D/U_%U/G_%G > writeable = yes >@@ -791,12 +802,17 @@ sub provision_ad_member > # access the share for tests. > chmod 0777, "$prefix/share"; > >- if (not $self->check_or_start( >- env_vars => $ret, >- nmbd => "yes", >- winbindd => "yes", >- smbd => "yes")) { >- return undef; >+ if (defined($no_nss_winbind)) { >+ $ret->{NSS_WRAPPER_MODULE_SO_PATH} = ""; >+ $ret->{NSS_WRAPPER_MODULE_FN_PREFIX} = ""; >+ } >+ >+ if (not $self->check_or_start( >+ env_vars => $ret, >+ nmbd => "yes", >+ winbindd => "yes", >+ smbd => "yes")) { >+ return undef; > } > > $ret->{DC_SERVER} = $dcvars->{SERVER}; >@@ -1174,9 +1190,47 @@ sub setup_ad_member_fips > $dcvars, > $trustvars_f, > $trustvars_e, >+ undef, > 1); > } > >+sub setup_ad_member_no_nss_wb >+{ >+ my ($self, >+ $prefix, >+ $dcvars, >+ $trustvars_f, >+ $trustvars_e) = @_; >+ >+ # If we didn't build with ADS, pretend this env was never available >+ if (not $self->have_ads()) { >+ return "UNKNOWN"; >+ } >+ >+ print "PROVISIONING AD MEMBER WITHOUT NSS WINBIND..."; >+ >+ my $extra_member_options = " >+ username map = $prefix/lib/username.map >+"; >+ >+ my $ret = $self->provision_ad_member($prefix, >+ "ADMEMNONSSWB", >+ $dcvars, >+ $trustvars_f, >+ $trustvars_e, >+ $extra_member_options, >+ undef, >+ 1); >+ >+ open(USERMAP, ">$prefix/lib/username.map") or die("Unable to open $prefix/lib/username.map"); >+ print USERMAP " >+root = $dcvars->{DOMAIN}/root >+"; >+ close(USERMAP); >+ >+ return $ret; >+} >+ > sub setup_simpleserver > { > my ($self, $path) = @_; >-- >2.25.1 > > >From 204344174f0fdf310d1c5ad2a7bd75a4eaab1623 Mon Sep 17 00:00:00 2001 >From: Samuel Cabrero <scabrero@samba.org> >Date: Tue, 5 Oct 2021 16:56:06 +0200 >Subject: [PATCH 133/262] CVE-2020-25717: selftest: Add a test for the new 'min > domain uid' parameter > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> > >Signed-off-by: Samuel Cabrero <scabrero@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >[abartlet@samba.org Fixed knowfail per instruction from metze] >--- > .../samba/tests/krb5/test_min_domain_uid.py | 121 ++++++++++++++++++ > python/samba/tests/usage.py | 1 + > selftest/knownfail.d/min_domain_uid | 1 + > source4/selftest/tests.py | 7 + > 4 files changed, 130 insertions(+) > create mode 100755 python/samba/tests/krb5/test_min_domain_uid.py > create mode 100644 selftest/knownfail.d/min_domain_uid > >diff --git a/python/samba/tests/krb5/test_min_domain_uid.py b/python/samba/tests/krb5/test_min_domain_uid.py >new file mode 100755 >index 000000000000..77414b239f08 >--- /dev/null >+++ b/python/samba/tests/krb5/test_min_domain_uid.py >@@ -0,0 +1,121 @@ >+#!/usr/bin/env python3 >+# Unix SMB/CIFS implementation. >+# Copyright (C) Samuel Cabrero 2021 >+# >+# 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 <http://www.gnu.org/licenses/>. >+# >+ >+import sys >+import os >+import pwd >+import ctypes >+ >+from samba.tests import env_get_var_value >+from samba.samba3 import libsmb_samba_internal as libsmb >+from samba.samba3 import param as s3param >+from samba import NTSTATUSError, ntstatus >+ >+from samba.tests.krb5.kdc_base_test import KDCBaseTest >+from samba.credentials import MUST_USE_KERBEROS, DONT_USE_KERBEROS >+ >+sys.path.insert(0, "bin/python") >+os.environ["PYTHONUNBUFFERED"] = "1" >+ >+class SmbMinDomainUid(KDCBaseTest): >+ """Test for SMB authorization without NSS winbind. In such setup domain >+ accounts are mapped to local accounts using the 'username map' option. >+ """ >+ >+ def setUp(self): >+ super(KDCBaseTest, self).setUp() >+ >+ # Create a user account, along with a Kerberos credentials cache file >+ # where the service ticket authenticating the user are stored. >+ self.samdb = self.get_samdb() >+ >+ self.mach_name = env_get_var_value('SERVER') >+ self.user_name = "root" >+ self.service = "cifs" >+ self.share = "tmp" >+ >+ # Create the user account. >+ (self.user_creds, _) = self.create_account(self.samdb, self.user_name) >+ >+ # Build the global inject file path >+ server_conf = env_get_var_value('SMB_CONF_PATH') >+ server_conf_dir = os.path.dirname(server_conf) >+ self.global_inject = os.path.join(server_conf_dir, "global_inject.conf") >+ >+ def _test_min_uid(self, creds): >+ # Assert unix root uid is less than 'idmap config ADDOMAIN' minimum >+ s3_lp = s3param.get_context() >+ s3_lp.load(self.get_lp().configfile) >+ >+ domain_range = s3_lp.get("idmap config * : range").split('-') >+ domain_range_low = int(domain_range[0]) >+ unix_root_pw = pwd.getpwnam(self.user_name) >+ self.assertLess(unix_root_pw.pw_uid, domain_range_low) >+ self.assertLess(unix_root_pw.pw_gid, domain_range_low) >+ >+ conn = libsmb.Conn(self.mach_name, self.share, lp=s3_lp, creds=creds) >+ # Disconnect >+ conn = None >+ >+ # Restrict access to local root account uid >+ with open(self.global_inject, 'w') as f: >+ f.write("min domain uid = %s\n" % (unix_root_pw.pw_uid + 1)) >+ >+ with self.assertRaises(NTSTATUSError) as cm: >+ conn = libsmb.Conn(self.mach_name, >+ self.share, >+ lp=s3_lp, >+ creds=creds) >+ code = ctypes.c_uint32(cm.exception.args[0]).value >+ self.assertEqual(code, ntstatus.NT_STATUS_INVALID_TOKEN) >+ >+ # check that the local root account uid is now allowed >+ with open(self.global_inject, 'w') as f: >+ f.write("min domain uid = %s\n" % unix_root_pw.pw_uid) >+ >+ conn = libsmb.Conn(self.mach_name, self.share, lp=s3_lp, creds=creds) >+ # Disconnect >+ conn = None >+ >+ with open(self.global_inject, 'w') as f: >+ f.truncate() >+ >+ def test_min_domain_uid_krb5(self): >+ krb5_state = self.user_creds.get_kerberos_state() >+ self.user_creds.set_kerberos_state(MUST_USE_KERBEROS) >+ ret = self._test_min_uid(self.user_creds) >+ self.user_creds.set_kerberos_state(krb5_state) >+ return ret >+ >+ def test_min_domain_uid_ntlmssp(self): >+ krb5_state = self.user_creds.get_kerberos_state() >+ self.user_creds.set_kerberos_state(DONT_USE_KERBEROS) >+ ret = self._test_min_uid(self.user_creds) >+ self.user_creds.set_kerberos_state(krb5_state) >+ return ret >+ >+ def tearDown(self): >+ # Ensure no leftovers in global inject file >+ with open(self.global_inject, 'w') as f: >+ f.truncate() >+ >+ super(KDCBaseTest, self).tearDown() >+ >+if __name__ == "__main__": >+ import unittest >+ unittest.main() >diff --git a/python/samba/tests/usage.py b/python/samba/tests/usage.py >index 5cae74299853..048bd1c30995 100644 >--- a/python/samba/tests/usage.py >+++ b/python/samba/tests/usage.py >@@ -106,6 +106,7 @@ EXCLUDE_USAGE = { > 'python/samba/tests/krb5/salt_tests.py', > 'python/samba/tests/krb5/spn_tests.py', > 'python/samba/tests/krb5/alias_tests.py', >+ 'python/samba/tests/krb5/test_min_domain_uid.py', > } > > EXCLUDE_HELP = { >diff --git a/selftest/knownfail.d/min_domain_uid b/selftest/knownfail.d/min_domain_uid >new file mode 100644 >index 000000000000..00bf75cd8af5 >--- /dev/null >+++ b/selftest/knownfail.d/min_domain_uid >@@ -0,0 +1 @@ >+^samba.tests.krb5.test_min_domain_uid.samba.*.SmbMinDomainUid.test_min_domain_uid_.*\(ad_member_no_nss_wb:local\) >diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py >index bd68094436fb..312e7944a0ce 100755 >--- a/source4/selftest/tests.py >+++ b/source4/selftest/tests.py >@@ -845,6 +845,13 @@ planoldpythontestsuite("ad_dc_smb1", "samba.tests.krb5.test_smb", > 'FAST_SUPPORT': have_fast_support, > 'TKT_SIG_SUPPORT': tkt_sig_support > }) >+planoldpythontestsuite("ad_member_no_nss_wb:local", >+ "samba.tests.krb5.test_min_domain_uid", >+ environ={ >+ 'ADMIN_USERNAME': '$DC_USERNAME', >+ 'ADMIN_PASSWORD': '$DC_PASSWORD', >+ 'STRICT_CHECKING': '0' >+ }) > > for env in ["ad_dc", smbv1_disabled_testenv]: > planoldpythontestsuite(env, "samba.tests.smb", extra_args=['-U"$USERNAME%$PASSWORD"']) >-- >2.25.1 > > >From 26fa3225df16b8d3d4340a99b74f9bf57ac15e38 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 8 Oct 2021 19:57:18 +0200 >Subject: [PATCH 134/262] CVE-2020-25717: s3:auth: let > auth3_generate_session_info_pac() forward the low level errors > >Mapping everything to ACCESS_DENIED makes it hard to debug problems, >which may happen because of our more restrictive behaviour in future. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/auth/auth_generic.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c >index 8044e6d8af0b..86585ad690cf 100644 >--- a/source3/auth/auth_generic.c >+++ b/source3/auth/auth_generic.c >@@ -166,7 +166,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > if (!NT_STATUS_IS_OK(status)) { > DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n", > nt_errstr(status))); >- status = NT_STATUS_ACCESS_DENIED; >+ status = nt_status_squash(status); > goto done; > } > >-- >2.25.1 > > >From 56fc3e11c5f2a2080b0aeb17b3fa578b884251f9 Mon Sep 17 00:00:00 2001 >From: Samuel Cabrero <scabrero@samba.org> >Date: Tue, 28 Sep 2021 10:45:11 +0200 >Subject: [PATCH 135/262] CVE-2020-25717: s3:auth: Check minimum domain uid > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> > >Signed-off-by: Samuel Cabrero <scabrero@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >[abartlet@samba.org Removed knownfail on advice from metze] >--- > selftest/knownfail.d/min_domain_uid | 1 - > source3/auth/auth_util.c | 16 ++++++++++++++++ > 2 files changed, 16 insertions(+), 1 deletion(-) > delete mode 100644 selftest/knownfail.d/min_domain_uid > >diff --git a/selftest/knownfail.d/min_domain_uid b/selftest/knownfail.d/min_domain_uid >deleted file mode 100644 >index 00bf75cd8af5..000000000000 >--- a/selftest/knownfail.d/min_domain_uid >+++ /dev/null >@@ -1 +0,0 @@ >-^samba.tests.krb5.test_min_domain_uid.samba.*.SmbMinDomainUid.test_min_domain_uid_.*\(ad_member_no_nss_wb:local\) >diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c >index 4686b29111e8..4de4bc74374b 100644 >--- a/source3/auth/auth_util.c >+++ b/source3/auth/auth_util.c >@@ -2103,6 +2103,22 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, > } > } > goto out; >+ } else if ((lp_security() == SEC_ADS || lp_security() == SEC_DOMAIN) && >+ !is_myname(domain) && pwd->pw_uid < lp_min_domain_uid()) { >+ /* >+ * !is_myname(domain) because when smbd starts tries to setup >+ * the guest user info, calling this function with nobody >+ * username. Nobody is usually uid 65535 but it can be changed >+ * to a regular user with 'guest account' parameter >+ */ >+ nt_status = NT_STATUS_INVALID_TOKEN; >+ DBG_NOTICE("Username '%s%s%s' is invalid on this system, " >+ "it does not meet 'min domain uid' " >+ "restriction (%u < %u): %s\n", >+ nt_domain, lp_winbind_separator(), nt_username, >+ pwd->pw_uid, lp_min_domain_uid(), >+ nt_errstr(nt_status)); >+ goto out; > } > > result = make_server_info(tmp_ctx); >-- >2.25.1 > > >From b4958a72991ec028fa1632fab408239308c55298 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 8 Oct 2021 17:40:30 +0200 >Subject: [PATCH 136/262] CVE-2020-25717: s3:auth: we should not try to > autocreate the guest account > >We should avoid autocreation of users as much as possible. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/auth/user_krb5.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source3/auth/user_krb5.c b/source3/auth/user_krb5.c >index 8998f9c8f8ae..074e8c7eb711 100644 >--- a/source3/auth/user_krb5.c >+++ b/source3/auth/user_krb5.c >@@ -155,7 +155,7 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, > if (!fuser) { > return NT_STATUS_NO_MEMORY; > } >- pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true); >+ pw = smb_getpwnam(mem_ctx, fuser, &unixuser, false); > } > > /* extra sanity check that the guest account is valid */ >-- >2.25.1 > > >From 7629eab0b79e65e5f178dcf373a0f8b300e30aff Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 8 Oct 2021 18:08:20 +0200 >Subject: [PATCH 137/262] CVE-2020-25717: s3:auth: no longer let > check_account() autocreate local users > >So far we autocreated local user accounts based on just the >account_name (just ignoring any domain part). > >This only happens via a possible 'add user script', >which is not typically defined on domain members >and on NT4 DCs local users already exist in the >local passdb anyway. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/auth/auth_util.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c >index 4de4bc74374b..99b85d47a5f0 100644 >--- a/source3/auth/auth_util.c >+++ b/source3/auth/auth_util.c >@@ -1898,7 +1898,7 @@ static NTSTATUS check_account(TALLOC_CTX *mem_ctx, const char *domain, > return NT_STATUS_NO_MEMORY; > } > >- passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, true ); >+ passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, false); > if (!passwd) { > DEBUG(3, ("Failed to find authenticated user %s via " > "getpwnam(), denying access.\n", dom_user)); >-- >2.25.1 > > >From 04145de01cc3b0e500918a6cd52db7eb20e9d903 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Fri, 8 Oct 2021 12:33:16 +0200 >Subject: [PATCH 138/262] CVE-2020-25717: s3:auth: remove fallbacks in > smb_getpwnam() > >So far we tried getpwnam("DOMAIN\account") first and >always did a fallback to getpwnam("account") completely >ignoring the domain part, this just causes problems >as we mix "DOMAIN1\account", "DOMAIN2\account", >and "account"! > >As we require a running winbindd for domain member setups >we should no longer do a fallback to just "account" for >users served by winbindd! > >For users of the local SAM don't use this code path, >as check_sam_security() doesn't call check_account(). > >The only case where smb_getpwnam("account") happens is >when map_username() via ("username map [script]") mapped >"DOMAIN\account" to something without '\', but that is >explicitly desired by the admin. > >Note: use 'git show -w' > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> > >Signed-off-by: Ralph Boehme <slow@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > selftest/knownfail.d/ktest | 26 +++++++++++++ > source3/auth/auth_util.c | 77 +++++++++++++++++++++----------------- > 2 files changed, 68 insertions(+), 35 deletions(-) > create mode 100644 selftest/knownfail.d/ktest > >diff --git a/selftest/knownfail.d/ktest b/selftest/knownfail.d/ktest >new file mode 100644 >index 000000000000..809612ba0b94 >--- /dev/null >+++ b/selftest/knownfail.d/ktest >@@ -0,0 +1,26 @@ >+^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2...lsa.LookupSidsReply.ktest >+^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2...lsa.LookupSidsReply.ktest >+^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5...rpcclient.ktest:local >+^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5...rpcclient.ktest:local >+^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,connect...lsa.LookupSidsReply.ktest >+^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,connect...lsa.LookupSidsReply.ktest >+^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,packet...lsa.LookupSidsReply.ktest >+^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,packet...lsa.LookupSidsReply.ktest >+^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,packet...rpcclient.ktest:local >+^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,packet...rpcclient.ktest:local >+^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,sign...lsa.LookupSidsReply.ktest >+^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,sign...lsa.LookupSidsReply.ktest >+^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,sign...rpcclient.ktest:local >+^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,sign...rpcclient.ktest:local >+^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,seal...lsa.LookupSidsReply.ktest >+^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,seal...lsa.LookupSidsReply.ktest >+^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,seal...rpcclient.ktest:local >+^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,seal...rpcclient.ktest:local >+^samba3.blackbox.smbclient_krb5.old.ccache..smbclient.ktest:local >+^samba3.blackbox.smbclient_krb5.new.ccache..smbclient.ktest:local >+^samba3.blackbox.smbclient_large_file..krb5.smbclient.large.posix.write.read.ktest:local >+^samba3.blackbox.smbclient_large_file..krb5.cmp.of.read.and.written.files.ktest:local >+^samba3.blackbox.smbclient_krb5.old.ccache.--client-protection=encrypt.smbclient.ktest:local >+^samba3.blackbox.smbclient_krb5.new.ccache.--client-protection=encrypt.smbclient.ktest:local >+^samba3.blackbox.smbclient_large_file.--client-protection=encrypt.krb5.smbclient.large.posix.write.read.ktest:local >+^samba3.blackbox.smbclient_large_file.--client-protection=encrypt.krb5.cmp.of.read.and.written.files.ktest:local >diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c >index 99b85d47a5f0..d81313a0495e 100644 >--- a/source3/auth/auth_util.c >+++ b/source3/auth/auth_util.c >@@ -1933,7 +1933,7 @@ struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser, > { > struct passwd *pw = NULL; > char *p = NULL; >- char *username = NULL; >+ const char *username = NULL; > > /* we only save a copy of the username it has been mangled > by winbindd use default domain */ >@@ -1952,48 +1952,55 @@ struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser, > /* code for a DOMAIN\user string */ > > if ( p ) { >- pw = Get_Pwnam_alloc( mem_ctx, domuser ); >- if ( pw ) { >- /* make sure we get the case of the username correct */ >- /* work around 'winbind use default domain = yes' */ >- >- if ( lp_winbind_use_default_domain() && >- !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) { >- char *domain; >- >- /* split the domain and username into 2 strings */ >- *p = '\0'; >- domain = username; >- >- *p_save_username = talloc_asprintf(mem_ctx, >- "%s%c%s", >- domain, >- *lp_winbind_separator(), >- pw->pw_name); >- if (!*p_save_username) { >- TALLOC_FREE(pw); >- return NULL; >- } >- } else { >- *p_save_username = talloc_strdup(mem_ctx, pw->pw_name); >- } >+ const char *domain = NULL; > >- /* whew -- done! */ >- return pw; >+ /* split the domain and username into 2 strings */ >+ *p = '\0'; >+ domain = username; >+ p++; >+ username = p; >+ >+ if (strequal(domain, get_global_sam_name())) { >+ /* >+ * This typically don't happen >+ * as check_sam_Security() >+ * don't call make_server_info_info3() >+ * and thus check_account(). >+ * >+ * But we better keep this. >+ */ >+ goto username_only; > } > >- /* setup for lookup of just the username */ >- /* remember that p and username are overlapping memory */ >- >- p++; >- username = talloc_strdup(mem_ctx, p); >- if (!username) { >+ pw = Get_Pwnam_alloc( mem_ctx, domuser ); >+ if (pw == NULL) { > return NULL; > } >+ /* make sure we get the case of the username correct */ >+ /* work around 'winbind use default domain = yes' */ >+ >+ if ( lp_winbind_use_default_domain() && >+ !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) { >+ *p_save_username = talloc_asprintf(mem_ctx, >+ "%s%c%s", >+ domain, >+ *lp_winbind_separator(), >+ pw->pw_name); >+ if (!*p_save_username) { >+ TALLOC_FREE(pw); >+ return NULL; >+ } >+ } else { >+ *p_save_username = talloc_strdup(mem_ctx, pw->pw_name); >+ } >+ >+ /* whew -- done! */ >+ return pw; >+ > } > > /* just lookup a plain username */ >- >+username_only: > pw = Get_Pwnam_alloc(mem_ctx, username); > > /* Create local user if requested but only if winbindd >-- >2.25.1 > > >From ac82778e41d116fa9d5d3b6b53f275fa365e5d63 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 21 Sep 2021 13:13:52 +0200 >Subject: [PATCH 139/262] CVE-2020-25717: s3:lib: add > lp_allow_trusted_domains() logic to is_allowed_domain() > >is_allowed_domain() is a central place we already use to >trigger NT_STATUS_AUTHENTICATION_FIREWALL_FAILED, so >we can add additional logic there. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/lib/util_names.c | 15 ++++++++++++++- > 1 file changed, 14 insertions(+), 1 deletion(-) > >diff --git a/source3/lib/util_names.c b/source3/lib/util_names.c >index 630a25875c7b..876035cbe29c 100644 >--- a/source3/lib/util_names.c >+++ b/source3/lib/util_names.c >@@ -200,5 +200,18 @@ bool is_allowed_domain(const char *domain_name) > } > } > >- return true; >+ if (lp_allow_trusted_domains()) { >+ return true; >+ } >+ >+ if (strequal(lp_workgroup(), domain_name)) { >+ return true; >+ } >+ >+ if (is_myname(domain_name)) { >+ return true; >+ } >+ >+ DBG_NOTICE("Not trusted domain '%s'\n", domain_name); >+ return false; > } >-- >2.25.1 > > >From 99e694c1041e3db6e31c3a49eab4f6a2269fcf98 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Mon, 4 Oct 2021 18:03:55 +0200 >Subject: [PATCH 140/262] CVE-2020-25717: s3:auth: don't let create_local_token > depend on !winbind_ping() > >We always require a running winbindd on a domain member, so >we should better fail a request instead of silently alter >the behaviour, which results in a different unix token, just >because winbindd might be restarted. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/auth/auth_util.c | 10 ++++------ > 1 file changed, 4 insertions(+), 6 deletions(-) > >diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c >index d81313a0495e..065b525500f9 100644 >--- a/source3/auth/auth_util.c >+++ b/source3/auth/auth_util.c >@@ -576,13 +576,11 @@ NTSTATUS create_local_token(TALLOC_CTX *mem_ctx, > } > > /* >- * If winbind is not around, we can not make much use of the SIDs the >- * domain controller provided us with. Likewise if the user name was >- * mapped to some local unix user. >+ * If the user name was mapped to some local unix user, >+ * we can not make much use of the SIDs the >+ * domain controller provided us with. > */ >- >- if (((lp_server_role() == ROLE_DOMAIN_MEMBER) && !winbind_ping()) || >- (server_info->nss_token)) { >+ if (server_info->nss_token) { > char *found_username = NULL; > status = create_token_from_username(session_info, > server_info->unix_name, >-- >2.25.1 > > >From 12a6efda8cd4aaa53f4dbce92e12b7c953766007 Mon Sep 17 00:00:00 2001 >From: Alexander Bokovoy <ab@samba.org> >Date: Wed, 11 Nov 2020 18:50:45 +0200 >Subject: [PATCH 141/262] CVE-2020-25717: Add FreeIPA domain controller role > >As we want to reduce use of 'classic domain controller' role but FreeIPA >relies on it internally, add a separate role to mark FreeIPA domain >controller role. > >It means that role won't result in ROLE_STANDALONE. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> > >Signed-off-by: Alexander Bokovoy <ab@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > docs-xml/smbdotconf/security/serverrole.xml | 7 ++++ > lib/param/loadparm_server_role.c | 2 ++ > lib/param/param_table.c | 1 + > lib/param/util.c | 1 + > libcli/netlogon/netlogon.c | 2 +- > libds/common/roles.h | 1 + > source3/auth/auth.c | 3 ++ > source3/auth/auth_sam.c | 14 ++++---- > source3/include/smb_macros.h | 2 +- > source3/lib/netapi/joindomain.c | 1 + > source3/param/loadparm.c | 4 ++- > source3/passdb/lookup_sid.c | 2 +- > source3/passdb/machine_account_secrets.c | 7 ++-- > source3/registry/reg_backend_prod_options.c | 1 + > source3/rpc_server/dssetup/srv_dssetup_nt.c | 1 + > source3/smbd/server.c | 2 +- > source3/winbindd/winbindd_misc.c | 2 +- > source3/winbindd/winbindd_util.c | 40 ++++++++++++++++----- > source4/auth/ntlm/auth.c | 1 + > source4/kdc/kdc-heimdal.c | 1 + > source4/rpc_server/samr/dcesrv_samr.c | 2 ++ > 21 files changed, 72 insertions(+), 25 deletions(-) > >diff --git a/docs-xml/smbdotconf/security/serverrole.xml b/docs-xml/smbdotconf/security/serverrole.xml >index 9511c61c96d6..b8b83a127b5d 100644 >--- a/docs-xml/smbdotconf/security/serverrole.xml >+++ b/docs-xml/smbdotconf/security/serverrole.xml >@@ -78,6 +78,13 @@ > url="http://wiki.samba.org/index.php/Samba4/HOWTO">Samba4 > HOWTO</ulink></para> > >+ <para><anchor id="IPA-DC"/><emphasis>SERVER ROLE = IPA DOMAIN CONTROLLER</emphasis></para> >+ >+ <para>This mode of operation runs Samba in a hybrid mode for IPA >+ domain controller, providing forest trust to Active Directory. >+ This role requires special configuration performed by IPA installers >+ and should not be used manually by any administrator. >+ </para> > </description> > > <related>security</related> >diff --git a/lib/param/loadparm_server_role.c b/lib/param/loadparm_server_role.c >index 7a6bc7707235..a78d1ab9cf39 100644 >--- a/lib/param/loadparm_server_role.c >+++ b/lib/param/loadparm_server_role.c >@@ -42,6 +42,7 @@ static const struct srv_role_tab { > { ROLE_DOMAIN_BDC, "ROLE_DOMAIN_BDC" }, > { ROLE_DOMAIN_PDC, "ROLE_DOMAIN_PDC" }, > { ROLE_ACTIVE_DIRECTORY_DC, "ROLE_ACTIVE_DIRECTORY_DC" }, >+ { ROLE_IPA_DC, "ROLE_IPA_DC"}, > { 0, NULL } > }; > >@@ -140,6 +141,7 @@ bool lp_is_security_and_server_role_valid(int server_role, int security) > case ROLE_DOMAIN_PDC: > case ROLE_DOMAIN_BDC: > case ROLE_ACTIVE_DIRECTORY_DC: >+ case ROLE_IPA_DC: > if (security == SEC_USER) { > valid = true; > } >diff --git a/lib/param/param_table.c b/lib/param/param_table.c >index 47b85de1f876..780252017d22 100644 >--- a/lib/param/param_table.c >+++ b/lib/param/param_table.c >@@ -111,6 +111,7 @@ static const struct enum_list enum_server_role[] = { > {ROLE_ACTIVE_DIRECTORY_DC, "active directory domain controller"}, > {ROLE_ACTIVE_DIRECTORY_DC, "domain controller"}, > {ROLE_ACTIVE_DIRECTORY_DC, "dc"}, >+ {ROLE_IPA_DC, "IPA primary domain controller"}, > {-1, NULL} > }; > >diff --git a/lib/param/util.c b/lib/param/util.c >index cd8e74b9d8f3..9a0fc102de89 100644 >--- a/lib/param/util.c >+++ b/lib/param/util.c >@@ -255,6 +255,7 @@ const char *lpcfg_sam_name(struct loadparm_context *lp_ctx) > case ROLE_DOMAIN_BDC: > case ROLE_DOMAIN_PDC: > case ROLE_ACTIVE_DIRECTORY_DC: >+ case ROLE_IPA_DC: > return lpcfg_workgroup(lp_ctx); > default: > return lpcfg_netbios_name(lp_ctx); >diff --git a/libcli/netlogon/netlogon.c b/libcli/netlogon/netlogon.c >index 239503e85b64..59af460dc4e8 100644 >--- a/libcli/netlogon/netlogon.c >+++ b/libcli/netlogon/netlogon.c >@@ -93,7 +93,7 @@ NTSTATUS pull_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx, > if (ndr->offset < ndr->data_size) { > TALLOC_FREE(ndr); > /* >- * We need to handle a bug in FreeIPA (at least <= 4.1.2). >+ * We need to handle a bug in IPA (at least <= 4.1.2). > * > * They include the ip address information without setting > * NETLOGON_NT_VERSION_5EX_WITH_IP, while using >diff --git a/libds/common/roles.h b/libds/common/roles.h >index 4772c8d7d3f7..03ba1915b215 100644 >--- a/libds/common/roles.h >+++ b/libds/common/roles.h >@@ -33,6 +33,7 @@ enum server_role { > > /* not in samr.idl */ > ROLE_ACTIVE_DIRECTORY_DC = 4, >+ ROLE_IPA_DC = 5, > > /* To determine the role automatically, this is not a valid role */ > ROLE_AUTO = 100 >diff --git a/source3/auth/auth.c b/source3/auth/auth.c >index 12f7917b38d7..4944c0fee1a9 100644 >--- a/source3/auth/auth.c >+++ b/source3/auth/auth.c >@@ -542,6 +542,7 @@ NTSTATUS make_auth3_context_for_ntlm(TALLOC_CTX *mem_ctx, > break; > case ROLE_DOMAIN_BDC: > case ROLE_DOMAIN_PDC: >+ case ROLE_IPA_DC: > role = "'DC'"; > methods = "anonymous sam winbind sam_ignoredomain"; > break; >@@ -573,6 +574,7 @@ NTSTATUS make_auth3_context_for_netlogon(TALLOC_CTX *mem_ctx, > switch (lp_server_role()) { > case ROLE_DOMAIN_BDC: > case ROLE_DOMAIN_PDC: >+ case ROLE_IPA_DC: > methods = "sam_netlogon3 winbind"; > break; > >@@ -594,6 +596,7 @@ NTSTATUS make_auth3_context_for_winbind(TALLOC_CTX *mem_ctx, > case ROLE_DOMAIN_MEMBER: > case ROLE_DOMAIN_BDC: > case ROLE_DOMAIN_PDC: >+ case ROLE_IPA_DC: > methods = "sam"; > break; > case ROLE_ACTIVE_DIRECTORY_DC: >diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c >index e8e0d543f8c3..a2ce10139750 100644 >--- a/source3/auth/auth_sam.c >+++ b/source3/auth/auth_sam.c >@@ -143,12 +143,13 @@ static NTSTATUS auth_samstrict_auth(const struct auth_context *auth_context, > break; > case ROLE_DOMAIN_PDC: > case ROLE_DOMAIN_BDC: >+ case ROLE_IPA_DC: > if (!is_local_name && !is_my_domain) { > /* If we are running on a DC that has PASSDB module with domain > * information, check if DNS forest name is matching the domain >- * name. This is the case of FreeIPA domain controller when >- * trusted AD DCs attempt to authenticate FreeIPA users using >- * the forest root domain (which is the only domain in FreeIPA). >+ * name. This is the case of IPA domain controller when >+ * trusted AD DCs attempt to authenticate IPA users using >+ * the forest root domain (which is the only domain in IPA). > */ > struct pdb_domain_info *dom_info = NULL; > >@@ -234,6 +235,7 @@ static NTSTATUS auth_sam_netlogon3_auth(const struct auth_context *auth_context, > switch (lp_server_role()) { > case ROLE_DOMAIN_PDC: > case ROLE_DOMAIN_BDC: >+ case ROLE_IPA_DC: > break; > default: > DBG_ERR("Invalid server role\n"); >@@ -252,9 +254,9 @@ static NTSTATUS auth_sam_netlogon3_auth(const struct auth_context *auth_context, > if (!is_my_domain) { > /* If we are running on a DC that has PASSDB module with domain > * information, check if DNS forest name is matching the domain >- * name. This is the case of FreeIPA domain controller when >- * trusted AD DCs attempt to authenticate FreeIPA users using >- * the forest root domain (which is the only domain in FreeIPA). >+ * name. This is the case of IPA domain controller when >+ * trusted AD DCs attempt to authenticate IPA users using >+ * the forest root domain (which is the only domain in IPA). > */ > struct pdb_domain_info *dom_info = NULL; > dom_info = pdb_get_domain_info(mem_ctx); >diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h >index 1513696f7660..68abe83dcbca 100644 >--- a/source3/include/smb_macros.h >+++ b/source3/include/smb_macros.h >@@ -199,7 +199,7 @@ copy an IP address from one buffer to another > Check to see if we are a DC for this domain > *****************************************************************************/ > >-#define IS_DC (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC || lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) >+#define IS_DC (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC || lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_server_role() == ROLE_IPA_DC) > #define IS_AD_DC (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) > > /* >diff --git a/source3/lib/netapi/joindomain.c b/source3/lib/netapi/joindomain.c >index f2d36fc00dbe..d1710c4b938b 100644 >--- a/source3/lib/netapi/joindomain.c >+++ b/source3/lib/netapi/joindomain.c >@@ -375,6 +375,7 @@ WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx, > case ROLE_DOMAIN_MEMBER: > case ROLE_DOMAIN_PDC: > case ROLE_DOMAIN_BDC: >+ case ROLE_IPA_DC: > *r->out.name_type = NetSetupDomainName; > break; > case ROLE_STANDALONE: >diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c >index 301e3622ed47..56cf0abb33af 100644 >--- a/source3/param/loadparm.c >+++ b/source3/param/loadparm.c >@@ -4405,6 +4405,7 @@ int lp_default_server_announce(void) > default_server_announce |= SV_TYPE_DOMAIN_MEMBER; > break; > case ROLE_DOMAIN_PDC: >+ case ROLE_IPA_DC: > default_server_announce |= SV_TYPE_DOMAIN_CTRL; > break; > case ROLE_DOMAIN_BDC: >@@ -4430,7 +4431,8 @@ int lp_default_server_announce(void) > bool lp_domain_master(void) > { > if (Globals._domain_master == Auto) >- return (lp_server_role() == ROLE_DOMAIN_PDC); >+ return (lp_server_role() == ROLE_DOMAIN_PDC || >+ lp_server_role() == ROLE_IPA_DC); > > return (bool)Globals._domain_master; > } >diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c >index 0e01467b3cb4..a551bcfd24a0 100644 >--- a/source3/passdb/lookup_sid.c >+++ b/source3/passdb/lookup_sid.c >@@ -121,7 +121,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, > > /* If we are running on a DC that has PASSDB module with domain > * information, check if DNS forest name is matching the domain >- * name. This is the case of FreeIPA domain controller when >+ * name. This is the case of IPA domain controller when > * trusted AD DC looks up users found in a Global Catalog of > * the forest root domain. */ > if (!check_global_sam && (IS_DC)) { >diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c >index 7c103d0a6e40..0b18334446eb 100644 >--- a/source3/passdb/machine_account_secrets.c >+++ b/source3/passdb/machine_account_secrets.c >@@ -197,7 +197,8 @@ bool secrets_fetch_domain_guid(const char *domain, struct GUID *guid) > dyn_guid = (struct GUID *)secrets_fetch(key, &size); > > if (!dyn_guid) { >- if (lp_server_role() == ROLE_DOMAIN_PDC) { >+ if (lp_server_role() == ROLE_DOMAIN_PDC || >+ lp_server_role() == ROLE_IPA_DC) { > new_guid = GUID_random(); > if (!secrets_store_domain_guid(domain, &new_guid)) > return False; >@@ -313,9 +314,7 @@ static const char *trust_keystr(const char *domain) > > enum netr_SchannelType get_default_sec_channel(void) > { >- if (lp_server_role() == ROLE_DOMAIN_BDC || >- lp_server_role() == ROLE_DOMAIN_PDC || >- lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) { >+ if (IS_DC) { > return SEC_CHAN_BDC; > } else { > return SEC_CHAN_WKSTA; >diff --git a/source3/registry/reg_backend_prod_options.c b/source3/registry/reg_backend_prod_options.c >index 655c587ac405..7bd3f324c373 100644 >--- a/source3/registry/reg_backend_prod_options.c >+++ b/source3/registry/reg_backend_prod_options.c >@@ -40,6 +40,7 @@ static int prod_options_fetch_values(const char *key, struct regval_ctr *regvals > switch (lp_server_role()) { > case ROLE_DOMAIN_PDC: > case ROLE_DOMAIN_BDC: >+ case ROLE_IPA_DC: > value_ascii = "LanmanNT"; > break; > case ROLE_STANDALONE: >diff --git a/source3/rpc_server/dssetup/srv_dssetup_nt.c b/source3/rpc_server/dssetup/srv_dssetup_nt.c >index 64569382695a..932452bc13ba 100644 >--- a/source3/rpc_server/dssetup/srv_dssetup_nt.c >+++ b/source3/rpc_server/dssetup/srv_dssetup_nt.c >@@ -63,6 +63,7 @@ static WERROR fill_dsrole_dominfo_basic(TALLOC_CTX *ctx, > basic->domain = get_global_sam_name(); > break; > case ROLE_DOMAIN_PDC: >+ case ROLE_IPA_DC: > basic->role = DS_ROLE_PRIMARY_DC; > basic->domain = get_global_sam_name(); > break; >diff --git a/source3/smbd/server.c b/source3/smbd/server.c >index 39f83c3daa68..d574e7de1a5d 100644 >--- a/source3/smbd/server.c >+++ b/source3/smbd/server.c >@@ -1973,7 +1973,7 @@ extern void build_options(bool screen); > exit_daemon("smbd can not open secrets.tdb", EACCES); > } > >- if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) { >+ if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC || lp_server_role() == ROLE_IPA_DC) { > struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers()); > if (!open_schannel_session_store(NULL, lp_ctx)) { > exit_daemon("ERROR: Samba cannot open schannel store for secured NETLOGON operations.", EACCES); >diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c >index d27ed76e81e7..0e31fc6b65c1 100644 >--- a/source3/winbindd/winbindd_misc.c >+++ b/source3/winbindd/winbindd_misc.c >@@ -75,7 +75,7 @@ static char *get_trust_type_string(TALLOC_CTX *mem_ctx, > case SEC_CHAN_BDC: { > int role = lp_server_role(); > >- if (role == ROLE_DOMAIN_PDC) { >+ if (role == ROLE_DOMAIN_PDC || role == ROLE_IPA_DC) { > s = talloc_strdup(mem_ctx, "PDC"); > if (s == NULL) { > return NULL; >diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c >index ef197310fa0c..1ae4a8d3ca3d 100644 >--- a/source3/winbindd/winbindd_util.c >+++ b/source3/winbindd/winbindd_util.c >@@ -1251,15 +1251,37 @@ bool init_domain_list(void) > secure_channel_type = SEC_CHAN_LOCAL; > } > >- status = add_trusted_domain(get_global_sam_name(), >- NULL, >- get_global_sam_sid(), >- LSA_TRUST_TYPE_DOWNLEVEL, >- trust_flags, >- 0, /* trust_attribs */ >- secure_channel_type, >- NULL, >- &domain); >+ if ((pdb_domain_info != NULL) && (role == ROLE_IPA_DC)) { >+ /* This is IPA DC that presents itself as >+ * an Active Directory domain controller to trusted AD >+ * forests but in fact is a classic domain controller. >+ */ >+ trust_flags = NETR_TRUST_FLAG_PRIMARY; >+ trust_flags |= NETR_TRUST_FLAG_IN_FOREST; >+ trust_flags |= NETR_TRUST_FLAG_NATIVE; >+ trust_flags |= NETR_TRUST_FLAG_OUTBOUND; >+ trust_flags |= NETR_TRUST_FLAG_TREEROOT; >+ status = add_trusted_domain(pdb_domain_info->name, >+ pdb_domain_info->dns_domain, >+ &pdb_domain_info->sid, >+ LSA_TRUST_TYPE_UPLEVEL, >+ trust_flags, >+ LSA_TRUST_ATTRIBUTE_WITHIN_FOREST, >+ secure_channel_type, >+ NULL, >+ &domain); >+ TALLOC_FREE(pdb_domain_info); >+ } else { >+ status = add_trusted_domain(get_global_sam_name(), >+ NULL, >+ get_global_sam_sid(), >+ LSA_TRUST_TYPE_DOWNLEVEL, >+ trust_flags, >+ 0, /* trust_attribs */ >+ secure_channel_type, >+ NULL, >+ &domain); >+ } > if (!NT_STATUS_IS_OK(status)) { > DBG_ERR("Failed to add local SAM to " > "domain to winbindd's internal list\n"); >diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c >index e0c4436343cd..6302a60232db 100644 >--- a/source4/auth/ntlm/auth.c >+++ b/source4/auth/ntlm/auth.c >@@ -736,6 +736,7 @@ const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context * > case ROLE_DOMAIN_BDC: > case ROLE_DOMAIN_PDC: > case ROLE_ACTIVE_DIRECTORY_DC: >+ case ROLE_IPA_DC: > auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL); > break; > } >diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c >index ee4e1387def3..28dadcb1fd58 100644 >--- a/source4/kdc/kdc-heimdal.c >+++ b/source4/kdc/kdc-heimdal.c >@@ -276,6 +276,7 @@ static NTSTATUS kdc_task_init(struct task_server *task) > return NT_STATUS_INVALID_DOMAIN_ROLE; > case ROLE_DOMAIN_PDC: > case ROLE_DOMAIN_BDC: >+ case ROLE_IPA_DC: > task_server_terminate( > task, "Cannot start KDC as a 'classic Samba' DC", false); > return NT_STATUS_INVALID_DOMAIN_ROLE; >diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c >index 70f914bf14c7..7345cac6bd67 100644 >--- a/source4/rpc_server/samr/dcesrv_samr.c >+++ b/source4/rpc_server/samr/dcesrv_samr.c >@@ -573,6 +573,7 @@ static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state > break; > case ROLE_DOMAIN_PDC: > case ROLE_DOMAIN_BDC: >+ case ROLE_IPA_DC: > case ROLE_AUTO: > return NT_STATUS_INTERNAL_ERROR; > case ROLE_DOMAIN_MEMBER: >@@ -721,6 +722,7 @@ static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state, > break; > case ROLE_DOMAIN_PDC: > case ROLE_DOMAIN_BDC: >+ case ROLE_IPA_DC: > case ROLE_AUTO: > return NT_STATUS_INTERNAL_ERROR; > case ROLE_DOMAIN_MEMBER: >-- >2.25.1 > > >From a1c953cacfba70e9b44455775c009f0989f18e01 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 5 Oct 2021 18:11:57 +0200 >Subject: [PATCH 142/262] CVE-2020-25719 CVE-2020-25717: auth/gensec: always > require a PAC in domain mode (DC or member) > >AD domains always provide a PAC unless UF_NO_AUTH_DATA_REQUIRED is set >on the service account, which can only be explicitly configured, >but that's an invalid configuration! > >We still try to support standalone servers in an MIT realm, >as legacy setup. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >[jsutton@samba.org Removed knownfail entries] >--- > auth/gensec/gensec_util.c | 27 +++++++++++++++++++++++---- > selftest/knownfail.d/no-pac | 4 ---- > 2 files changed, 23 insertions(+), 8 deletions(-) > delete mode 100644 selftest/knownfail.d/no-pac > >diff --git a/auth/gensec/gensec_util.c b/auth/gensec/gensec_util.c >index e185acc0c205..694661b53b56 100644 >--- a/auth/gensec/gensec_util.c >+++ b/auth/gensec/gensec_util.c >@@ -25,6 +25,8 @@ > #include "auth/gensec/gensec_internal.h" > #include "auth/common_auth.h" > #include "../lib/util/asn1.h" >+#include "param/param.h" >+#include "libds/common/roles.h" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_AUTH >@@ -46,10 +48,27 @@ NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx, > session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; > > if (!pac_blob) { >- if (gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) { >- DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n", >- principal_string)); >- return NT_STATUS_ACCESS_DENIED; >+ enum server_role server_role = >+ lpcfg_server_role(gensec_security->settings->lp_ctx); >+ >+ /* >+ * For any domain setup (DC or member) we require having >+ * a PAC, as the service ticket comes from an AD DC, >+ * which will always provide a PAC, unless >+ * UF_NO_AUTH_DATA_REQUIRED is configured for our >+ * account, but that's just an invalid configuration, >+ * the admin configured for us! >+ * >+ * As a legacy case, we still allow kerberos tickets from an MIT >+ * realm, but only in standalone mode. In that mode we'll only >+ * ever accept a kerberos authentication with a keytab file >+ * being explicitly configured via the 'keytab method' option. >+ */ >+ if (server_role != ROLE_STANDALONE) { >+ DBG_WARNING("Unable to find PAC in ticket from %s, " >+ "failing to allow access\n", >+ principal_string); >+ return NT_STATUS_NO_IMPERSONATION_TOKEN; > } > DBG_NOTICE("Unable to find PAC for %s, resorting to local " > "user lookup\n", principal_string); >diff --git a/selftest/knownfail.d/no-pac b/selftest/knownfail.d/no-pac >deleted file mode 100644 >index 9723d581c2a1..000000000000 >--- a/selftest/knownfail.d/no-pac >+++ /dev/null >@@ -1,4 +0,0 @@ >-^samba.tests.krb5.test_ccache.samba.tests.krb5.test_ccache.CcacheTests.test_ccache_no_pac >-^samba.tests.krb5.test_ldap.samba.tests.krb5.test_ldap.LdapTests.test_ldap_no_pac >-^samba.tests.krb5.test_rpc.samba.tests.krb5.test_rpc.RpcTests.test_rpc_no_pac >-^samba.tests.krb5.test_smb.samba.tests.krb5.test_smb.SmbTests.test_smb_no_pac >-- >2.25.1 > > >From 8e590d4cd10e45ff51590cbedd898736edd3ecc7 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Mon, 11 Oct 2021 23:17:19 +0200 >Subject: [PATCH 143/262] CVE-2020-25719 CVE-2020-25717: s4:auth: remove unused > auth_generate_session_info_principal() > >We'll require a PAC at the main gensec layer already. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/auth/auth.h | 8 ------ > source4/auth/ntlm/auth.c | 49 ++++-------------------------------- > source4/auth/ntlm/auth_sam.c | 12 --------- > 3 files changed, 5 insertions(+), 64 deletions(-) > >diff --git a/source4/auth/auth.h b/source4/auth/auth.h >index 3f9fb1ae3cbc..6b7db99cbe2d 100644 >--- a/source4/auth/auth.h >+++ b/source4/auth/auth.h >@@ -69,14 +69,6 @@ struct auth_operations { > TALLOC_CTX *mem_ctx, > struct auth_user_info_dc **interim_info, > bool *authoritative); >- >- /* Lookup a 'session info interim' return based only on the principal or DN */ >- NTSTATUS (*get_user_info_dc_principal)(TALLOC_CTX *mem_ctx, >- struct auth4_context *auth_context, >- const char *principal, >- struct ldb_dn *user_dn, >- struct auth_user_info_dc **interim_info); >- uint32_t flags; > }; > > struct auth_method_context { >diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c >index 6302a60232db..98283b0e2411 100644 >--- a/source4/auth/ntlm/auth.c >+++ b/source4/auth/ntlm/auth.c >@@ -86,48 +86,6 @@ _PUBLIC_ NTSTATUS auth_get_challenge(struct auth4_context *auth_ctx, uint8_t cha > return NT_STATUS_OK; > } > >-/**************************************************************************** >-Used in the gensec_gssapi and gensec_krb5 server-side code, where the >-PAC isn't available, and for tokenGroups in the DSDB stack. >- >- Supply either a principal or a DN >-****************************************************************************/ >-static NTSTATUS auth_generate_session_info_principal(struct auth4_context *auth_ctx, >- TALLOC_CTX *mem_ctx, >- const char *principal, >- struct ldb_dn *user_dn, >- uint32_t session_info_flags, >- struct auth_session_info **session_info) >-{ >- NTSTATUS nt_status; >- struct auth_method_context *method; >- struct auth_user_info_dc *user_info_dc; >- >- for (method = auth_ctx->methods; method; method = method->next) { >- if (!method->ops->get_user_info_dc_principal) { >- continue; >- } >- >- nt_status = method->ops->get_user_info_dc_principal(mem_ctx, auth_ctx, principal, user_dn, &user_info_dc); >- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { >- continue; >- } >- if (!NT_STATUS_IS_OK(nt_status)) { >- return nt_status; >- } >- >- nt_status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx, >- user_info_dc, >- user_info_dc->info->account_name, >- session_info_flags, session_info); >- talloc_free(user_info_dc); >- >- return nt_status; >- } >- >- return NT_STATUS_NOT_IMPLEMENTED; >-} >- > /** > * Check a user's Plaintext, LM or NTLM password. > * (sync version) >@@ -626,8 +584,11 @@ static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx, > TALLOC_CTX *tmp_ctx; > > if (!pac_blob) { >- return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name, >- NULL, session_info_flags, session_info); >+ /* >+ * This should already be catched at the main >+ * gensec layer, but better check twice >+ */ >+ return NT_STATUS_INTERNAL_ERROR; > } > > tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context"); >diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c >index e4ebeae75234..e80b1e82fec8 100644 >--- a/source4/auth/ntlm/auth_sam.c >+++ b/source4/auth/ntlm/auth_sam.c >@@ -937,22 +937,11 @@ static NTSTATUS authsam_want_check(struct auth_method_context *ctx, > return NT_STATUS_OK; > } > >-/* Wrapper for the auth subsystem pointer */ >-static NTSTATUS authsam_get_user_info_dc_principal_wrapper(TALLOC_CTX *mem_ctx, >- struct auth4_context *auth_context, >- const char *principal, >- struct ldb_dn *user_dn, >- struct auth_user_info_dc **user_info_dc) >-{ >- return authsam_get_user_info_dc_principal(mem_ctx, auth_context->lp_ctx, auth_context->sam_ctx, >- principal, user_dn, user_info_dc); >-} > static const struct auth_operations sam_ignoredomain_ops = { > .name = "sam_ignoredomain", > .want_check = authsam_ignoredomain_want_check, > .check_password_send = authsam_check_password_send, > .check_password_recv = authsam_check_password_recv, >- .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, > }; > > static const struct auth_operations sam_ops = { >@@ -960,7 +949,6 @@ static const struct auth_operations sam_ops = { > .want_check = authsam_want_check, > .check_password_send = authsam_check_password_send, > .check_password_recv = authsam_check_password_recv, >- .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, > }; > > _PUBLIC_ NTSTATUS auth4_sam_init(TALLOC_CTX *); >-- >2.25.1 > > >From b82736cbd2e81ce20c63d3093e936caeeb51d634 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 21 Sep 2021 12:27:28 +0200 >Subject: [PATCH 144/262] CVE-2020-25717: s3:ntlm_auth: fix memory leaks in > ntlm_auth_generate_session_info_pac() > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/utils/ntlm_auth.c | 18 ++++++++++++------ > 1 file changed, 12 insertions(+), 6 deletions(-) > >diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c >index 1d22a48c57ce..e6efdfcec5c1 100644 >--- a/source3/utils/ntlm_auth.c >+++ b/source3/utils/ntlm_auth.c >@@ -817,23 +817,27 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c > if (!p) { > DEBUG(3, ("[%s] Doesn't look like a valid principal\n", > princ_name)); >- return NT_STATUS_LOGON_FAILURE; >+ status = NT_STATUS_LOGON_FAILURE; >+ goto done; > } > > user = talloc_strndup(mem_ctx, princ_name, p - princ_name); > if (!user) { >- return NT_STATUS_NO_MEMORY; >+ status = NT_STATUS_NO_MEMORY; >+ goto done; > } > > realm = talloc_strdup(talloc_tos(), p + 1); > if (!realm) { >- return NT_STATUS_NO_MEMORY; >+ status = NT_STATUS_NO_MEMORY; >+ goto done; > } > > if (!strequal(realm, lp_realm())) { > DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm)); > if (!lp_allow_trusted_domains()) { >- return NT_STATUS_LOGON_FAILURE; >+ status = NT_STATUS_LOGON_FAILURE; >+ goto done; > } > } > >@@ -841,7 +845,8 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c > domain = talloc_strdup(mem_ctx, > logon_info->info3.base.logon_domain.string); > if (!domain) { >- return NT_STATUS_NO_MEMORY; >+ status = NT_STATUS_NO_MEMORY; >+ goto done; > } > DEBUG(10, ("Domain is [%s] (using PAC)\n", domain)); > } else { >@@ -871,7 +876,8 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c > domain = talloc_strdup(mem_ctx, realm); > } > if (!domain) { >- return NT_STATUS_NO_MEMORY; >+ status = NT_STATUS_NO_MEMORY; >+ goto done; > } > DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain)); > } >-- >2.25.1 > > >From 6b5c3a2f302b6257152f0782ebc5c480f57ce73d Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 21 Sep 2021 12:44:01 +0200 >Subject: [PATCH 145/262] CVE-2020-25717: s3:ntlm_auth: let > ntlm_auth_generate_session_info_pac() base the name on the PAC LOGON_INFO > only > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/utils/ntlm_auth.c | 91 ++++++++++++--------------------------- > 1 file changed, 28 insertions(+), 63 deletions(-) > >diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c >index e6efdfcec5c1..5541c58350b5 100644 >--- a/source3/utils/ntlm_auth.c >+++ b/source3/utils/ntlm_auth.c >@@ -789,10 +789,8 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c > struct PAC_LOGON_INFO *logon_info = NULL; > char *unixuser; > NTSTATUS status; >- char *domain = NULL; >- char *realm = NULL; >- char *user = NULL; >- char *p; >+ const char *domain = ""; >+ const char *user = ""; > > tmp_ctx = talloc_new(mem_ctx); > if (!tmp_ctx) { >@@ -809,79 +807,46 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c > if (!NT_STATUS_IS_OK(status)) { > goto done; > } >- } >- >- DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name)); >- >- p = strchr_m(princ_name, '@'); >- if (!p) { >- DEBUG(3, ("[%s] Doesn't look like a valid principal\n", >- princ_name)); >- status = NT_STATUS_LOGON_FAILURE; >+ } else { >+ status = NT_STATUS_ACCESS_DENIED; >+ DBG_WARNING("Kerberos ticket for[%s] has no PAC: %s\n", >+ princ_name, nt_errstr(status)); > goto done; > } > >- user = talloc_strndup(mem_ctx, princ_name, p - princ_name); >- if (!user) { >- status = NT_STATUS_NO_MEMORY; >- goto done; >+ if (logon_info->info3.base.account_name.string != NULL) { >+ user = logon_info->info3.base.account_name.string; >+ } else { >+ user = ""; >+ } >+ if (logon_info->info3.base.logon_domain.string != NULL) { >+ domain = logon_info->info3.base.logon_domain.string; >+ } else { >+ domain = ""; > } > >- realm = talloc_strdup(talloc_tos(), p + 1); >- if (!realm) { >- status = NT_STATUS_NO_MEMORY; >+ if (strlen(user) == 0 || strlen(domain) == 0) { >+ status = NT_STATUS_ACCESS_DENIED; >+ DBG_WARNING("Kerberos ticket for[%s] has invalid " >+ "account_name[%s]/logon_domain[%s]: %s\n", >+ princ_name, >+ logon_info->info3.base.account_name.string, >+ logon_info->info3.base.logon_domain.string, >+ nt_errstr(status)); > goto done; > } > >- if (!strequal(realm, lp_realm())) { >- DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm)); >+ DBG_NOTICE("Kerberos ticket principal name is [%s] " >+ "account_name[%s]/logon_domain[%s]\n", >+ princ_name, user, domain); >+ >+ if (!strequal(domain, lp_workgroup())) { > if (!lp_allow_trusted_domains()) { > status = NT_STATUS_LOGON_FAILURE; > goto done; > } > } > >- if (logon_info && logon_info->info3.base.logon_domain.string) { >- domain = talloc_strdup(mem_ctx, >- logon_info->info3.base.logon_domain.string); >- if (!domain) { >- status = NT_STATUS_NO_MEMORY; >- goto done; >- } >- DEBUG(10, ("Domain is [%s] (using PAC)\n", domain)); >- } else { >- >- /* If we have winbind running, we can (and must) shorten the >- username by using the short netbios name. Otherwise we will >- have inconsistent user names. With Kerberos, we get the >- fully qualified realm, with ntlmssp we get the short >- name. And even w2k3 does use ntlmssp if you for example >- connect to an ip address. */ >- >- wbcErr wbc_status; >- struct wbcDomainInfo *info = NULL; >- >- DEBUG(10, ("Mapping [%s] to short name using winbindd\n", >- realm)); >- >- wbc_status = wbcDomainInfo(realm, &info); >- >- if (WBC_ERROR_IS_OK(wbc_status)) { >- domain = talloc_strdup(mem_ctx, >- info->short_name); >- wbcFreeMemory(info); >- } else { >- DEBUG(3, ("Could not find short name: %s\n", >- wbcErrorString(wbc_status))); >- domain = talloc_strdup(mem_ctx, realm); >- } >- if (!domain) { >- status = NT_STATUS_NO_MEMORY; >- goto done; >- } >- DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain)); >- } >- > unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user); > if (!unixuser) { > status = NT_STATUS_NO_MEMORY; >-- >2.25.1 > > >From 4f289d29358fa3317805fe7ad6940375feb34de9 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Mon, 4 Oct 2021 19:42:20 +0200 >Subject: [PATCH 146/262] CVE-2020-25717: s3:auth: let > auth3_generate_session_info_pac() delegate everything to > make_server_info_wbcAuthUserInfo() > >This consolidates the code paths used for NTLMSSP and Kerberos! > >I checked what we were already doing for NTLMSSP, which is this: > >a) source3/auth/auth_winbind.c calls wbcAuthenticateUserEx() >b) as a domain member we require a valid response from winbindd, > otherwise we'll return NT_STATUS_NO_LOGON_SERVERS >c) we call make_server_info_wbcAuthUserInfo(), which internally > calls make_server_info_info3() >d) auth_check_ntlm_password() calls > smb_pam_accountcheck(unix_username, rhost), where rhost > is only an ipv4 or ipv6 address (without reverse dns lookup) >e) from auth3_check_password_send/auth3_check_password_recv() > server_returned_info will be passed to auth3_generate_session_info(), > triggered by gensec_session_info(), which means we'll call into > create_local_token() in order to transform auth_serversupplied_info > into auth_session_info. > >For Kerberos gensec_session_info() will call >auth3_generate_session_info_pac() via the gensec_generate_session_info_pac() >helper function. The current logic is this: > >a) gensec_generate_session_info_pac() is the function that > evaluates the 'gensec:require_pac', which defaulted to 'no' > before. >b) auth3_generate_session_info_pac() called > wbcAuthenticateUserEx() in order to pass the PAC blob > to winbindd, but only to prime its cache, e.g. netsamlogon cache > and others. Most failures were just ignored. >c) If the PAC blob is available, it extracted the PAC_LOGON_INFO > from it. >d) Then we called the horrible get_user_from_kerberos_info() function: > - It uses a first part of the tickets principal name (before the @) > as username and combines that with the 'logon_info->base.logon_domain' > if the logon_info (PAC) is present. > - As a fallback without a PAC it's tries to ask winbindd for a mapping > from realm to netbios domain name. > - Finally is falls back to using the realm as netbios domain name > With this information is builds 'userdomain+winbind_separator+useraccount' > and calls map_username() followed by smb_getpwnam() with create=true, > Note this is similar to the make_server_info_info3() => check_account() > => smb_getpwnam() logic under 3. > - It also calls smb_pam_accountcheck(), but may pass the reverse DNS lookup name > instead of the ip address as rhost. > - It does some MAP_TO_GUEST_ON_BAD_UID logic and auto creates the > guest account. >e) We called create_info3_from_pac_logon_info() >f) make_session_info_krb5() calls gets called and triggers this: > - If get_user_from_kerberos_info() mapped to guest, it calls > make_server_info_guest() > - If create_info3_from_pac_logon_info() created a info3 from logon_info, > it calls make_server_info_info3() > - Without a PAC it tries pdb_getsampwnam()/make_server_info_sam() with > a fallback to make_server_info_pw() > From there it calls create_local_token() > >I tried to change auth3_generate_session_info_pac() to behave similar >to auth_winbind.c together with auth3_generate_session_info() as >a domain member, as we now rely on a PAC: > >a) As domain member we require a PAC and always call wbcAuthenticateUserEx() > and require a valid response! >b) we call make_server_info_wbcAuthUserInfo(), which internally > calls make_server_info_info3(). Note make_server_info_info3() > handles MAP_TO_GUEST_ON_BAD_UID and make_server_info_guest() > internally. >c) Similar to auth_check_ntlm_password() we now call > smb_pam_accountcheck(unix_username, rhost), where rhost > is only an ipv4 or ipv6 address (without reverse dns lookup) >d) From there it calls create_local_token() > >As standalone server (in an MIT realm) we continue >with the already existing code logic, which works without a PAC: >a) we keep smb_getpwnam() with create=true logic as it > also requires an explicit 'add user script' option. >b) In the following commits we assert that there's > actually no PAC in this mode, which means we can > remove unused and confusing code. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14646 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/auth/auth_generic.c | 137 ++++++++++++++++++++++++++++-------- > 1 file changed, 109 insertions(+), 28 deletions(-) > >diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c >index 86585ad690cf..450c358beebc 100644 >--- a/source3/auth/auth_generic.c >+++ b/source3/auth/auth_generic.c >@@ -46,6 +46,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > uint32_t session_info_flags, > struct auth_session_info **session_info) > { >+ enum server_role server_role = lp_server_role(); > TALLOC_CTX *tmp_ctx; > struct PAC_LOGON_INFO *logon_info = NULL; > struct netr_SamInfo3 *info3_copy = NULL; >@@ -54,39 +55,59 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > char *ntuser; > char *ntdomain; > char *username; >- char *rhost; >+ const char *rhost; > struct passwd *pw; > NTSTATUS status; >- int rc; > > tmp_ctx = talloc_new(mem_ctx); > if (!tmp_ctx) { > return NT_STATUS_NO_MEMORY; > } > >- if (pac_blob) { >-#ifdef HAVE_KRB5 >+ if (tsocket_address_is_inet(remote_address, "ip")) { >+ rhost = tsocket_address_inet_addr_string( >+ remote_address, tmp_ctx); >+ if (rhost == NULL) { >+ status = NT_STATUS_NO_MEMORY; >+ goto done; >+ } >+ } else { >+ rhost = "127.0.0.1"; >+ } >+ >+ if (server_role != ROLE_STANDALONE) { > struct wbcAuthUserParams params = { 0 }; > struct wbcAuthUserInfo *info = NULL; > struct wbcAuthErrorInfo *err = NULL; >+ struct auth_serversupplied_info *server_info = NULL; >+ char *original_user_name = NULL; >+ char *p = NULL; > wbcErr wbc_err; > >+ if (pac_blob == NULL) { >+ /* >+ * This should already be catched at the main >+ * gensec layer, but better check twice >+ */ >+ status = NT_STATUS_INTERNAL_ERROR; >+ goto done; >+ } >+ > /* > * Let winbind decode the PAC. > * This will also store the user > * data in the netsamlogon cache. > * >- * We need to do this *before* we >- * call get_user_from_kerberos_info() >- * as that does a user lookup that >- * expects info in the netsamlogon cache. >- * >- * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=11259 >+ * This used to be a cache prime >+ * optimization, but now we delegate >+ * all logic to winbindd, as we require >+ * winbindd as domain member anyway. > */ > params.level = WBC_AUTH_USER_LEVEL_PAC; > params.password.pac.data = pac_blob->data; > params.password.pac.length = pac_blob->length; > >+ /* we are contacting the privileged pipe */ > become_root(); > wbc_err = wbcAuthenticateUserEx(¶ms, &info, &err); > unbecome_root(); >@@ -99,18 +120,90 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > */ > > switch (wbc_err) { >- case WBC_ERR_WINBIND_NOT_AVAILABLE: > case WBC_ERR_SUCCESS: > break; >+ case WBC_ERR_WINBIND_NOT_AVAILABLE: >+ status = NT_STATUS_NO_LOGON_SERVERS; >+ DBG_ERR("winbindd not running - " >+ "but required as domain member: %s\n", >+ nt_errstr(status)); >+ goto done; > case WBC_ERR_AUTH_ERROR: > status = NT_STATUS(err->nt_status); > wbcFreeMemory(err); > goto done; >+ case WBC_ERR_NO_MEMORY: >+ status = NT_STATUS_NO_MEMORY; >+ goto done; > default: > status = NT_STATUS_LOGON_FAILURE; > goto done; > } > >+ status = make_server_info_wbcAuthUserInfo(tmp_ctx, >+ info->account_name, >+ info->domain_name, >+ info, &server_info); >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(10, ("make_server_info_wbcAuthUserInfo failed: %s\n", >+ nt_errstr(status))); >+ goto done; >+ } >+ >+ /* We skip doing this step if the caller asked us not to */ >+ if (!(server_info->guest)) { >+ const char *unix_username = server_info->unix_name; >+ >+ /* We might not be root if we are an RPC call */ >+ become_root(); >+ status = smb_pam_accountcheck(unix_username, rhost); >+ unbecome_root(); >+ >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(3, ("check_ntlm_password: PAM Account for user [%s] " >+ "FAILED with error %s\n", >+ unix_username, nt_errstr(status))); >+ goto done; >+ } >+ >+ DEBUG(5, ("check_ntlm_password: PAM Account for user [%s] " >+ "succeeded\n", unix_username)); >+ } >+ >+ DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name)); >+ >+ p = strchr_m(princ_name, '@'); >+ if (!p) { >+ DEBUG(3, ("[%s] Doesn't look like a valid principal\n", >+ princ_name)); >+ status = NT_STATUS_LOGON_FAILURE; >+ goto done; >+ } >+ >+ original_user_name = talloc_strndup(tmp_ctx, princ_name, p - princ_name); >+ if (original_user_name == NULL) { >+ status = NT_STATUS_NO_MEMORY; >+ goto done; >+ } >+ >+ status = create_local_token(mem_ctx, >+ server_info, >+ NULL, >+ original_user_name, >+ session_info); >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(10, ("create_local_token failed: %s\n", >+ nt_errstr(status))); >+ goto done; >+ } >+ >+ goto session_info_ready; >+ } >+ >+ /* This is the standalone legacy code path */ >+ >+ if (pac_blob != NULL) { >+#ifdef HAVE_KRB5 > status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL, > NULL, NULL, 0, &logon_info); > #else >@@ -121,22 +214,6 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > } > } > >- rc = get_remote_hostname(remote_address, >- &rhost, >- tmp_ctx); >- if (rc < 0) { >- status = NT_STATUS_NO_MEMORY; >- goto done; >- } >- if (strequal(rhost, "UNKNOWN")) { >- rhost = tsocket_address_inet_addr_string(remote_address, >- tmp_ctx); >- if (rhost == NULL) { >- status = NT_STATUS_NO_MEMORY; >- goto done; >- } >- } >- > status = get_user_from_kerberos_info(tmp_ctx, rhost, > princ_name, logon_info, > &is_mapped, &is_guest, >@@ -170,6 +247,8 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > goto done; > } > >+session_info_ready: >+ > /* setup the string used by %U */ > set_current_user_info((*session_info)->unix_info->sanitized_username, > (*session_info)->unix_info->unix_name, >@@ -179,7 +258,9 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > lp_load_with_shares(get_dyn_CONFIGFILE()); > > DEBUG(5, (__location__ "OK: user: %s domain: %s client: %s\n", >- ntuser, ntdomain, rhost)); >+ (*session_info)->info->account_name, >+ (*session_info)->info->domain_name, >+ rhost)); > > status = NT_STATUS_OK; > >-- >2.25.1 > > >From a1dd8ee86ac43bbffda89646ba71c909d3da747f Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 5 Oct 2021 17:14:01 +0200 >Subject: [PATCH 147/262] CVE-2020-25717: selftest: configure 'ktest' env with > winbindd and idmap_autorid > >The 'ktest' environment was/is designed to test kerberos in an active >directory member setup. It was created at a time we wanted to test >smbd/winbindd with kerberos without having the source4 ad dc available. > >This still applies to testing the build with system krb5 libraries >but without relying on a running ad dc. > >As a domain member setup requires a running winbindd, we should test it >that way, in order to reflect a valid setup. > >As a side effect it provides a way to demonstrate that we can accept >smb connections authenticated via kerberos, but no connection to >a domain controller! In order get this working offline, we need an >idmap backend with ID_TYPE_BOTH support, so we use 'autorid', which >should be the default choice. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14646 >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > selftest/knownfail.d/ktest | 26 -------------------------- > selftest/target/Samba3.pm | 12 +++++------- > 2 files changed, 5 insertions(+), 33 deletions(-) > delete mode 100644 selftest/knownfail.d/ktest > >diff --git a/selftest/knownfail.d/ktest b/selftest/knownfail.d/ktest >deleted file mode 100644 >index 809612ba0b94..000000000000 >--- a/selftest/knownfail.d/ktest >+++ /dev/null >@@ -1,26 +0,0 @@ >-^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2...lsa.LookupSidsReply.ktest >-^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2...lsa.LookupSidsReply.ktest >-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5...rpcclient.ktest:local >-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5...rpcclient.ktest:local >-^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,connect...lsa.LookupSidsReply.ktest >-^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,connect...lsa.LookupSidsReply.ktest >-^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,packet...lsa.LookupSidsReply.ktest >-^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,packet...lsa.LookupSidsReply.ktest >-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,packet...rpcclient.ktest:local >-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,packet...rpcclient.ktest:local >-^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,sign...lsa.LookupSidsReply.ktest >-^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,sign...lsa.LookupSidsReply.ktest >-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,sign...rpcclient.ktest:local >-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,sign...rpcclient.ktest:local >-^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,seal...lsa.LookupSidsReply.ktest >-^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,seal...lsa.LookupSidsReply.ktest >-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,seal...rpcclient.ktest:local >-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,seal...rpcclient.ktest:local >-^samba3.blackbox.smbclient_krb5.old.ccache..smbclient.ktest:local >-^samba3.blackbox.smbclient_krb5.new.ccache..smbclient.ktest:local >-^samba3.blackbox.smbclient_large_file..krb5.smbclient.large.posix.write.read.ktest:local >-^samba3.blackbox.smbclient_large_file..krb5.cmp.of.read.and.written.files.ktest:local >-^samba3.blackbox.smbclient_krb5.old.ccache.--client-protection=encrypt.smbclient.ktest:local >-^samba3.blackbox.smbclient_krb5.new.ccache.--client-protection=encrypt.smbclient.ktest:local >-^samba3.blackbox.smbclient_large_file.--client-protection=encrypt.krb5.smbclient.large.posix.write.read.ktest:local >-^samba3.blackbox.smbclient_large_file.--client-protection=encrypt.krb5.cmp.of.read.and.written.files.ktest:local >diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm >index 0410e36ffa92..39327964569f 100755 >--- a/selftest/target/Samba3.pm >+++ b/selftest/target/Samba3.pm >@@ -1694,7 +1694,6 @@ sub setup_ktest > workgroup = KTEST > realm = ktest.samba.example.com > security = ads >- username map = $prefix/lib/username.map > server signing = required > server min protocol = SMB3_00 > client max protocol = SMB3 >@@ -1702,6 +1701,10 @@ sub setup_ktest > # This disables NTLM auth against the local SAM, which > # we use can then test this setting by. > ntlm auth = disabled >+ >+ idmap config * : backend = autorid >+ idmap config * : range = 1000000-1999999 >+ idmap config * : rangesize = 100000 > "; > > my $ret = $self->provision( >@@ -1727,12 +1730,6 @@ sub setup_ktest > > $ret->{KRB5_CONFIG} = $ctx->{krb5_conf}; > >- open(USERMAP, ">$prefix/lib/username.map") or die("Unable to open $prefix/lib/username.map"); >- print USERMAP " >-$ret->{USERNAME} = KTEST\\Administrator >-"; >- close(USERMAP); >- > #This is the secrets.tdb created by 'net ads join' from Samba3 to a > #Samba4 DC with the same parameters as are being used here. The > #domain SID is S-1-5-21-1071277805-689288055-3486227160 >@@ -1784,6 +1781,7 @@ $ret->{USERNAME} = KTEST\\Administrator > if (not $self->check_or_start( > env_vars => $ret, > nmbd => "yes", >+ winbindd => "offline", > smbd => "yes")) { > return undef; > } >-- >2.25.1 > > >From 9096b698068ecd12014f0640af6e0aca9872f3c4 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 5 Oct 2021 18:12:49 +0200 >Subject: [PATCH 148/262] CVE-2020-25717: s3:auth: let > auth3_generate_session_info_pac() reject a PAC in standalone mode > >We should be strict in standalone mode, that we only support MIT realms >without a PAC in order to keep the code sane. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/auth/auth_generic.c | 29 +++++++++-------------------- > 1 file changed, 9 insertions(+), 20 deletions(-) > >diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c >index 450c358beebc..7d00cfa95c76 100644 >--- a/source3/auth/auth_generic.c >+++ b/source3/auth/auth_generic.c >@@ -48,8 +48,6 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > { > enum server_role server_role = lp_server_role(); > TALLOC_CTX *tmp_ctx; >- struct PAC_LOGON_INFO *logon_info = NULL; >- struct netr_SamInfo3 *info3_copy = NULL; > bool is_mapped; > bool is_guest; > char *ntuser; >@@ -203,19 +201,20 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > /* This is the standalone legacy code path */ > > if (pac_blob != NULL) { >-#ifdef HAVE_KRB5 >- status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL, >- NULL, NULL, 0, &logon_info); >-#else >- status = NT_STATUS_ACCESS_DENIED; >-#endif >+ /* >+ * In standalone mode we don't expect a PAC! >+ * we only support MIT realms >+ */ >+ status = NT_STATUS_BAD_TOKEN_TYPE; >+ DBG_WARNING("Unexpected PAC for [%s] in standalone mode - %s\n", >+ princ_name, nt_errstr(status)); > if (!NT_STATUS_IS_OK(status)) { > goto done; > } > } > > status = get_user_from_kerberos_info(tmp_ctx, rhost, >- princ_name, logon_info, >+ princ_name, NULL, > &is_mapped, &is_guest, > &ntuser, &ntdomain, > &username, &pw); >@@ -226,19 +225,9 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > goto done; > } > >- /* Get the info3 from the PAC data if we have it */ >- if (logon_info) { >- status = create_info3_from_pac_logon_info(tmp_ctx, >- logon_info, >- &info3_copy); >- if (!NT_STATUS_IS_OK(status)) { >- goto done; >- } >- } >- > status = make_session_info_krb5(mem_ctx, > ntuser, ntdomain, username, pw, >- info3_copy, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */, >+ NULL, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */, > session_info); > if (!NT_STATUS_IS_OK(status)) { > DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n", >-- >2.25.1 > > >From 34657a303c1891d8fe819240eb5ff5e50c51086d Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 8 Oct 2021 17:59:59 +0200 >Subject: [PATCH 149/262] CVE-2020-25717: s3:auth: simplify > get_user_from_kerberos_info() by removing the unused logon_info argument > >This code is only every called in standalone mode on a MIT realm, >it means we never have a PAC and we also don't have winbindd arround. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/auth/auth_generic.c | 2 +- > source3/auth/proto.h | 1 - > source3/auth/user_krb5.c | 57 +++++++------------------------------ > 3 files changed, 11 insertions(+), 49 deletions(-) > >diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c >index 7d00cfa95c76..8649dd87efcf 100644 >--- a/source3/auth/auth_generic.c >+++ b/source3/auth/auth_generic.c >@@ -214,7 +214,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > } > > status = get_user_from_kerberos_info(tmp_ctx, rhost, >- princ_name, NULL, >+ princ_name, > &is_mapped, &is_guest, > &ntuser, &ntdomain, > &username, &pw); >diff --git a/source3/auth/proto.h b/source3/auth/proto.h >index 097b17fee44a..46fae447347f 100644 >--- a/source3/auth/proto.h >+++ b/source3/auth/proto.h >@@ -423,7 +423,6 @@ struct PAC_LOGON_INFO; > NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, > const char *cli_name, > const char *princ_name, >- struct PAC_LOGON_INFO *logon_info, > bool *is_mapped, > bool *mapped_to_guest, > char **ntuser, >diff --git a/source3/auth/user_krb5.c b/source3/auth/user_krb5.c >index 074e8c7eb711..7b69ca6c222e 100644 >--- a/source3/auth/user_krb5.c >+++ b/source3/auth/user_krb5.c >@@ -31,7 +31,6 @@ > NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, > const char *cli_name, > const char *princ_name, >- struct PAC_LOGON_INFO *logon_info, > bool *is_mapped, > bool *mapped_to_guest, > char **ntuser, >@@ -40,8 +39,8 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, > struct passwd **_pw) > { > NTSTATUS status; >- char *domain = NULL; >- char *realm = NULL; >+ const char *domain = NULL; >+ const char *realm = NULL; > char *user = NULL; > char *p; > char *fuser = NULL; >@@ -62,55 +61,16 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, > return NT_STATUS_NO_MEMORY; > } > >- realm = talloc_strdup(talloc_tos(), p + 1); >- if (!realm) { >- return NT_STATUS_NO_MEMORY; >- } >+ realm = p + 1; > > if (!strequal(realm, lp_realm())) { > DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm)); > if (!lp_allow_trusted_domains()) { > return NT_STATUS_LOGON_FAILURE; > } >- } >- >- if (logon_info && logon_info->info3.base.logon_domain.string) { >- domain = talloc_strdup(mem_ctx, >- logon_info->info3.base.logon_domain.string); >- if (!domain) { >- return NT_STATUS_NO_MEMORY; >- } >- DEBUG(10, ("Domain is [%s] (using PAC)\n", domain)); >+ domain = realm; > } else { >- >- /* If we have winbind running, we can (and must) shorten the >- username by using the short netbios name. Otherwise we will >- have inconsistent user names. With Kerberos, we get the >- fully qualified realm, with ntlmssp we get the short >- name. And even w2k3 does use ntlmssp if you for example >- connect to an ip address. */ >- >- wbcErr wbc_status; >- struct wbcDomainInfo *info = NULL; >- >- DEBUG(10, ("Mapping [%s] to short name using winbindd\n", >- realm)); >- >- wbc_status = wbcDomainInfo(realm, &info); >- >- if (WBC_ERROR_IS_OK(wbc_status)) { >- domain = talloc_strdup(mem_ctx, >- info->short_name); >- wbcFreeMemory(info); >- } else { >- DEBUG(3, ("Could not find short name: %s\n", >- wbcErrorString(wbc_status))); >- domain = talloc_strdup(mem_ctx, realm); >- } >- if (!domain) { >- return NT_STATUS_NO_MEMORY; >- } >- DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain)); >+ domain = lp_workgroup(); > } > > fuser = talloc_asprintf(mem_ctx, >@@ -175,7 +135,11 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, > return NT_STATUS_NO_MEMORY; > } > *ntuser = user; >- *ntdomain = domain; >+ *ntdomain = talloc_strdup(mem_ctx, domain); >+ if (*ntdomain == NULL) { >+ return NT_STATUS_NO_MEMORY; >+ } >+ > *_pw = pw; > > return NT_STATUS_OK; >@@ -282,7 +246,6 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, > NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, > const char *cli_name, > const char *princ_name, >- struct PAC_LOGON_INFO *logon_info, > bool *is_mapped, > bool *mapped_to_guest, > char **ntuser, >-- >2.25.1 > > >From a687e5891ddfd64e32e94f83717a7b8bbf9c1c0a Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 8 Oct 2021 18:03:04 +0200 >Subject: [PATCH 150/262] CVE-2020-25717: s3:auth: simplify > make_session_info_krb5() by removing unused arguments > >This is only ever be called in standalone mode with an MIT realm, >so we don't have a PAC/info3 structure. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source3/auth/auth_generic.c | 2 +- > source3/auth/proto.h | 2 -- > source3/auth/user_krb5.c | 20 +------------------- > 3 files changed, 2 insertions(+), 22 deletions(-) > >diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c >index 8649dd87efcf..b429c5f9f04b 100644 >--- a/source3/auth/auth_generic.c >+++ b/source3/auth/auth_generic.c >@@ -227,7 +227,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, > > status = make_session_info_krb5(mem_ctx, > ntuser, ntdomain, username, pw, >- NULL, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */, >+ is_guest, is_mapped, > session_info); > if (!NT_STATUS_IS_OK(status)) { > DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n", >diff --git a/source3/auth/proto.h b/source3/auth/proto.h >index 46fae447347f..fb7f663512b6 100644 >--- a/source3/auth/proto.h >+++ b/source3/auth/proto.h >@@ -434,9 +434,7 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, > char *ntdomain, > char *username, > struct passwd *pw, >- const struct netr_SamInfo3 *info3, > bool mapped_to_guest, bool username_was_mapped, >- DATA_BLOB *session_key, > struct auth_session_info **session_info); > > /* The following definitions come from auth/auth_samba4.c */ >diff --git a/source3/auth/user_krb5.c b/source3/auth/user_krb5.c >index 7b69ca6c222e..b8f37cbeee05 100644 >--- a/source3/auth/user_krb5.c >+++ b/source3/auth/user_krb5.c >@@ -150,9 +150,7 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, > char *ntdomain, > char *username, > struct passwd *pw, >- const struct netr_SamInfo3 *info3, > bool mapped_to_guest, bool username_was_mapped, >- DATA_BLOB *session_key, > struct auth_session_info **session_info) > { > NTSTATUS status; >@@ -166,20 +164,6 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, > return status; > } > >- } else if (info3) { >- /* pass the unmapped username here since map_username() >- will be called again in make_server_info_info3() */ >- >- status = make_server_info_info3(mem_ctx, >- ntuser, ntdomain, >- &server_info, >- info3); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(1, ("make_server_info_info3 failed: %s!\n", >- nt_errstr(status))); >- return status; >- } >- > } else { > /* > * We didn't get a PAC, we have to make up the user >@@ -231,7 +215,7 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, > > server_info->nss_token |= username_was_mapped; > >- status = create_local_token(mem_ctx, server_info, session_key, ntuser, session_info); >+ status = create_local_token(mem_ctx, server_info, NULL, ntuser, session_info); > talloc_free(server_info); > if (!NT_STATUS_IS_OK(status)) { > DEBUG(10,("failed to create local token: %s\n", >@@ -261,9 +245,7 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, > char *ntdomain, > char *username, > struct passwd *pw, >- const struct netr_SamInfo3 *info3, > bool mapped_to_guest, bool username_was_mapped, >- DATA_BLOB *session_key, > struct auth_session_info **session_info) > { > return NT_STATUS_NOT_IMPLEMENTED; >-- >2.25.1 > > >From c57ec866b7a0b1dd7bb5da2510efcd6925d5963d Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Mon, 18 Oct 2021 14:07:41 +1300 >Subject: [PATCH 151/262] CVE-2020-25722 Add test for SPN deletion followed by > addition > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >[abartlet@samba.org Removed transaction hooks, these do nothing over > remote LDAP] >--- > selftest/knownfail.d/acl-spn | 1 + > source4/dsdb/tests/python/acl.py | 48 ++++++++++++++++++++++++++++++++ > 2 files changed, 49 insertions(+) > create mode 100644 selftest/knownfail.d/acl-spn > >diff --git a/selftest/knownfail.d/acl-spn b/selftest/knownfail.d/acl-spn >new file mode 100644 >index 000000000000..e68add920a61 >--- /dev/null >+++ b/selftest/knownfail.d/acl-spn >@@ -0,0 +1 @@ >+^samba4.ldap.acl.python.*AclSPNTests.test_delete_add_spn >diff --git a/source4/dsdb/tests/python/acl.py b/source4/dsdb/tests/python/acl.py >index 815422c26772..9c3a7be0ab6e 100755 >--- a/source4/dsdb/tests/python/acl.py >+++ b/source4/dsdb/tests/python/acl.py >@@ -2190,6 +2190,54 @@ class AclSPNTests(AclTests): > def test_spn_rodc(self): > self.dc_spn_test(self.rodcctx) > >+ def test_delete_add_spn(self): >+ # Grant Validated-SPN property. >+ mod = f'(OA;;SW;{security.GUID_DRS_VALIDATE_SPN};;{self.user_sid1})' >+ self.sd_utils.dacl_add_ace(self.computerdn, mod) >+ >+ spn_base = f'HOST/{self.computername}' >+ >+ allowed_spn = f'{spn_base}.{self.dcctx.dnsdomain}' >+ not_allowed_spn = f'{spn_base}/{self.dcctx.get_domain_name()}' >+ >+ # Ensure we are able to add an allowed SPN. >+ msg = Message(Dn(self.ldb_user1, self.computerdn)) >+ msg['servicePrincipalName'] = MessageElement(allowed_spn, >+ FLAG_MOD_ADD, >+ 'servicePrincipalName') >+ self.ldb_user1.modify(msg) >+ >+ # Ensure we are not able to add a disallowed SPN. >+ msg = Message(Dn(self.ldb_user1, self.computerdn)) >+ msg['servicePrincipalName'] = MessageElement(not_allowed_spn, >+ FLAG_MOD_ADD, >+ 'servicePrincipalName') >+ try: >+ self.ldb_user1.modify(msg) >+ except LdbError as e: >+ num, _ = e.args >+ self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail(f'able to add disallowed SPN {not_allowed_spn}') >+ >+ # Ensure that deleting an existing SPN followed by adding a disallowed >+ # SPN fails. >+ msg = Message(Dn(self.ldb_user1, self.computerdn)) >+ msg['0'] = MessageElement([], >+ FLAG_MOD_DELETE, >+ 'servicePrincipalName') >+ msg['1'] = MessageElement(not_allowed_spn, >+ FLAG_MOD_ADD, >+ 'servicePrincipalName') >+ try: >+ self.ldb_user1.modify(msg) >+ except LdbError as e: >+ num, _ = e.args >+ self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail(f'able to add disallowed SPN {not_allowed_spn}') >+ >+ > # tests SEC_ADS_LIST vs. SEC_ADS_LIST_OBJECT > @DynamicTestCase > class AclVisibiltyTests(AclTests): >-- >2.25.1 > > >From 6e14e90372b2df253fdacd578ab01679cbccaafb Mon Sep 17 00:00:00 2001 >From: Joseph Sutton <josephsutton@catalyst.net.nz> >Date: Fri, 8 Oct 2021 15:49:31 +1300 >Subject: [PATCH 152/262] CVE-2020-25722 s4:dsdb:tests: Add missing self.fail() > calls > >Without these calls the tests could pass if an expected error did not >occur. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14832 > >Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> > >[abartlet@samba.org Included in backport as changing ACLs while > ACL tests are not checking for unexpected success would be bad] >--- > source4/dsdb/tests/python/acl.py | 32 ++++++++++++++++++++++++++++++++ > 1 file changed, 32 insertions(+) > >diff --git a/source4/dsdb/tests/python/acl.py b/source4/dsdb/tests/python/acl.py >index 9c3a7be0ab6e..abe91942f4f1 100755 >--- a/source4/dsdb/tests/python/acl.py >+++ b/source4/dsdb/tests/python/acl.py >@@ -1647,6 +1647,8 @@ userPassword: thatsAcomplPASS1 > except LdbError as e31: > (num, _) = e31.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ pass # Not self.fail() as we normally want success. > > def test_reset_password3(self): > """Grant WP and see what happens (unicodePwd)""" >@@ -1708,6 +1710,8 @@ userPassword: thatsAcomplPASS1 > except LdbError as e34: > (num, _) = e34.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ pass # Not self.fail() as we normally want success > > > class AclExtendedTests(AclTests): >@@ -2024,6 +2028,8 @@ class AclSPNTests(AclTests): > except LdbError as e39: > (num, _) = e39.args > self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS) >+ else: >+ self.fail() > > mod = "(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;%s)" % str(self.user_sid1) > self.sd_utils.dacl_add_ace(ctx.acct_dn, mod) >@@ -2062,29 +2068,39 @@ class AclSPNTests(AclTests): > except LdbError as e40: > (num, _) = e40.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > try: > self.replace_spn(self.ldb_user1, ctx.acct_dn, "ldap/%s.%s/DomainDnsZones.%s" % > (ctx.myname, ctx.dnsdomain, ctx.dnsdomain)) > except LdbError as e41: > (num, _) = e41.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > try: > self.replace_spn(self.ldb_user1, ctx.acct_dn, "nosuchservice/%s/%s" % ("abcd", "abcd")) > except LdbError as e42: > (num, _) = e42.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > try: > self.replace_spn(self.ldb_user1, ctx.acct_dn, "GC/%s.%s/%s" % > (ctx.myname, ctx.dnsdomain, netbiosdomain)) > except LdbError as e43: > (num, _) = e43.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > try: > self.replace_spn(self.ldb_user1, ctx.acct_dn, "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s" % > (ctx.ntds_guid, ctx.dnsdomain)) > except LdbError as e44: > (num, _) = e44.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > > def test_computer_spn(self): > # with WP, any value can be set >@@ -2130,6 +2146,8 @@ class AclSPNTests(AclTests): > except LdbError as e45: > (num, _) = e45.args > self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS) >+ else: >+ self.fail() > > mod = "(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;%s)" % str(self.user_sid1) > self.sd_utils.dacl_add_ace(self.computerdn, mod) >@@ -2148,41 +2166,55 @@ class AclSPNTests(AclTests): > except LdbError as e46: > (num, _) = e46.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > try: > self.replace_spn(self.ldb_user1, self.computerdn, "HOST/%s.%s/%s" % > (self.computername, self.dcctx.dnsdomain, netbiosdomain)) > except LdbError as e47: > (num, _) = e47.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > try: > self.replace_spn(self.ldb_user1, self.computerdn, "HOST/%s/%s" % > (self.computername, self.dcctx.dnsdomain)) > except LdbError as e48: > (num, _) = e48.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > try: > self.replace_spn(self.ldb_user1, self.computerdn, "HOST/%s.%s/%s" % > (self.computername, self.dcctx.dnsdomain, self.dcctx.dnsdomain)) > except LdbError as e49: > (num, _) = e49.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > try: > self.replace_spn(self.ldb_user1, self.computerdn, "GC/%s.%s/%s" % > (self.computername, self.dcctx.dnsdomain, self.dcctx.dnsforest)) > except LdbError as e50: > (num, _) = e50.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > try: > self.replace_spn(self.ldb_user1, self.computerdn, "ldap/%s/%s" % (self.computername, netbiosdomain)) > except LdbError as e51: > (num, _) = e51.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > try: > self.replace_spn(self.ldb_user1, self.computerdn, "ldap/%s.%s/ForestDnsZones.%s" % > (self.computername, self.dcctx.dnsdomain, self.dcctx.dnsdomain)) > except LdbError as e52: > (num, _) = e52.args > self.assertEqual(num, ERR_CONSTRAINT_VIOLATION) >+ else: >+ self.fail() > > def test_spn_rwdc(self): > self.dc_spn_test(self.dcctx) >-- >2.25.1 > > >From cfcf3d1471e3f0abce64a67cf423b33986f720e9 Mon Sep 17 00:00:00 2001 >From: Nadezhda Ivanova <nivanova@symas.com> >Date: Mon, 25 Oct 2021 14:54:56 +0300 >Subject: [PATCH 153/262] CVE-2020-25722: s4-acl: test Control Access Rights > honor the Applies-to attribute > >Validate Writes and Control Access Rights should only grant access if the >object is of the type listed in the Right's appliesTo attribute. >Tests to verify this behavior > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14832 > >Signed-off-by: Nadezhda Ivanova <nivanova@symas.com> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > selftest/knownfail.d/bug-14832 | 1 + > source4/dsdb/tests/python/acl.py | 17 +++++++++++++++++ > 2 files changed, 18 insertions(+) > create mode 100644 selftest/knownfail.d/bug-14832 > >diff --git a/selftest/knownfail.d/bug-14832 b/selftest/knownfail.d/bug-14832 >new file mode 100644 >index 000000000000..059a1778e65f >--- /dev/null >+++ b/selftest/knownfail.d/bug-14832 >@@ -0,0 +1 @@ >+^samba4.ldap.acl.python\(.*\).__main__.AclSPNTests.test_user_spn\(.*\) >\ No newline at end of file >diff --git a/source4/dsdb/tests/python/acl.py b/source4/dsdb/tests/python/acl.py >index abe91942f4f1..53acb99c2965 100755 >--- a/source4/dsdb/tests/python/acl.py >+++ b/source4/dsdb/tests/python/acl.py >@@ -1926,6 +1926,8 @@ class AclSPNTests(AclTests): > self.computername = "testcomp8" > self.test_user = "spn_test_user8" > self.computerdn = "CN=%s,CN=computers,%s" % (self.computername, self.base_dn) >+ self.user_object = "user_with_spn" >+ self.user_object_dn = "CN=%s,CN=Users,%s" % (self.user_object, self.base_dn) > self.dc_dn = "CN=%s,OU=Domain Controllers,%s" % (self.dcname, self.base_dn) > self.site = "Default-First-Site-Name" > self.rodcctx = DCJoinContext(server=host, creds=creds, lp=lp, >@@ -1947,6 +1949,7 @@ class AclSPNTests(AclTests): > self.dcctx.cleanup_old_join() > delete_force(self.ldb_admin, "cn=%s,cn=computers,%s" % (self.computername, self.base_dn)) > delete_force(self.ldb_admin, self.get_user_dn(self.test_user)) >+ delete_force(self.ldb_admin, self.user_object_dn) > > del self.ldb_user1 > >@@ -2222,6 +2225,20 @@ class AclSPNTests(AclTests): > def test_spn_rodc(self): > self.dc_spn_test(self.rodcctx) > >+ def test_user_spn(self): >+ #grant SW to a regular user and try to set the spn on a user object >+ #should get ERR_INSUFFICIENT_ACCESS_RIGHTS, since Validate-SPN only applies to computer >+ self.ldb_admin.newuser(self.user_object, self.user_pass) >+ mod = "(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;%s)" % str(self.user_sid1) >+ self.sd_utils.dacl_add_ace(self.user_object_dn, mod) >+ try: >+ self.replace_spn(self.ldb_user1, self.user_object_dn, "nosuchservice/%s/%s" % ("abcd", "abcd")) >+ except LdbError as e60: >+ (num, _) = e60.args >+ self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS) >+ else: >+ self.fail() >+ > def test_delete_add_spn(self): > # Grant Validated-SPN property. > mod = f'(OA;;SW;{security.GUID_DRS_VALIDATE_SPN};;{self.user_sid1})' >-- >2.25.1 > > >From 359189b8034a190ff40aa7c9d2bb654b799c4aaa Mon Sep 17 00:00:00 2001 >From: Nadezhda Ivanova <nivanova@symas.com> >Date: Mon, 18 Oct 2021 14:27:59 +0300 >Subject: [PATCH 154/262] CVE-2020-25722: s4-acl: Make sure Control Access > Rights honor the Applies-to attribute > >Validate Writes and Control Access Rights only grant access if the >object is of the type listed in the Right's appliesTo attribute. For >example, even though a Validated-SPN access may be granted to a user >object in the SD, it should only pass if the object is of class >computer This patch enforces the appliesTo attribute classes for >access checks from within the ldb stack. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14832 > >Signed-off-by: Nadezhda Ivanova <nivanova@symas.com> >Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > selftest/knownfail.d/bug-14832 | 1 - > source4/dsdb/common/util.c | 11 +++ > source4/dsdb/samdb/ldb_modules/acl.c | 87 +++++++++++++++++++---- > source4/dsdb/samdb/ldb_modules/acl_util.c | 40 +++++++++++ > source4/dsdb/samdb/ldb_modules/dirsync.c | 13 +++- > source4/dsdb/samdb/ldb_modules/samldb.c | 56 ++++++++------- > 6 files changed, 168 insertions(+), 40 deletions(-) > delete mode 100644 selftest/knownfail.d/bug-14832 > >diff --git a/selftest/knownfail.d/bug-14832 b/selftest/knownfail.d/bug-14832 >deleted file mode 100644 >index 059a1778e65f..000000000000 >--- a/selftest/knownfail.d/bug-14832 >+++ /dev/null >@@ -1 +0,0 @@ >-^samba4.ldap.acl.python\(.*\).__main__.AclSPNTests.test_user_spn\(.*\) >\ No newline at end of file >diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c >index ef03782f5889..62e04d08003e 100644 >--- a/source4/dsdb/common/util.c >+++ b/source4/dsdb/common/util.c >@@ -1179,6 +1179,17 @@ struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) > return new_dn; > } > >+struct ldb_dn *samdb_extended_rights_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) >+{ >+ struct ldb_dn *new_dn; >+ >+ new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx)); >+ if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Extended-Rights")) { >+ talloc_free(new_dn); >+ return NULL; >+ } >+ return new_dn; >+} > /* > work out the domain sid for the current open ldb > */ >diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c >index b1bbf9360060..9cae15881de0 100644 >--- a/source4/dsdb/samdb/ldb_modules/acl.c >+++ b/source4/dsdb/samdb/ldb_modules/acl.c >@@ -698,7 +698,12 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, > return LDB_SUCCESS; > } > >- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), >+ ret = acl_check_extended_right(tmp_ctx, >+ module, >+ req, >+ objectclass, >+ sd, >+ acl_user_token(module), > GUID_DRS_VALIDATE_SPN, > SEC_ADS_SELF_WRITE, > sid); >@@ -911,7 +916,7 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req) > return ldb_next_request(module, req); > } > >-/* ckecks if modifications are allowed on "Member" attribute */ >+/* checks if modifications are allowed on "Member" attribute */ > static int acl_check_self_membership(TALLOC_CTX *mem_ctx, > struct ldb_module *module, > struct ldb_request *req, >@@ -925,6 +930,16 @@ static int acl_check_self_membership(TALLOC_CTX *mem_ctx, > struct ldb_context *ldb = ldb_module_get_ctx(module); > struct ldb_dn *user_dn; > struct ldb_message_element *member_el; >+ const struct ldb_message *msg = NULL; >+ >+ if (req->operation == LDB_MODIFY) { >+ msg = req->op.mod.message; >+ } else if (req->operation == LDB_ADD) { >+ msg = req->op.add.message; >+ } else { >+ return LDB_ERR_OPERATIONS_ERROR; >+ } >+ > /* if we have wp, we can do whatever we like */ > if (acl_check_access_on_attribute(module, > mem_ctx, >@@ -935,13 +950,13 @@ static int acl_check_self_membership(TALLOC_CTX *mem_ctx, > return LDB_SUCCESS; > } > /* if we are adding/deleting ourselves, check for self membership */ >- ret = dsdb_find_dn_by_sid(ldb, mem_ctx, >- &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX], >+ ret = dsdb_find_dn_by_sid(ldb, mem_ctx, >+ &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX], > &user_dn); > if (ret != LDB_SUCCESS) { > return ret; > } >- member_el = ldb_msg_find_element(req->op.mod.message, "member"); >+ member_el = ldb_msg_find_element(msg, "member"); > if (!member_el) { > return ldb_operr(ldb); > } >@@ -955,13 +970,18 @@ static int acl_check_self_membership(TALLOC_CTX *mem_ctx, > return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; > } > } >- ret = acl_check_extended_right(mem_ctx, sd, acl_user_token(module), >+ ret = acl_check_extended_right(mem_ctx, >+ module, >+ req, >+ objectclass, >+ sd, >+ acl_user_token(module), > GUID_DRS_SELF_MEMBERSHIP, > SEC_ADS_SELF_WRITE, > sid); > if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { > dsdb_acl_debug(sd, acl_user_token(module), >- req->op.mod.message->dn, >+ msg->dn, > true, > 10); > } >@@ -1021,6 +1041,9 @@ static int acl_check_password_rights( > * so we don't have to strict verification of the input. > */ > ret = acl_check_extended_right(tmp_ctx, >+ module, >+ req, >+ objectclass, > sd, > acl_user_token(module), > GUID_DRS_USER_CHANGE_PASSWORD, >@@ -1044,7 +1067,12 @@ static int acl_check_password_rights( > * the only caller is samdb_set_password_internal(), > * so we don't have to strict verification of the input. > */ >- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), >+ ret = acl_check_extended_right(tmp_ctx, >+ module, >+ req, >+ objectclass, >+ sd, >+ acl_user_token(module), > GUID_DRS_FORCE_CHANGE_PASSWORD, > SEC_ADS_CONTROL_ACCESS, > sid); >@@ -1097,7 +1125,12 @@ static int acl_check_password_rights( > if (rep_attr_cnt > 0) { > pav->pwd_reset = true; > >- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), >+ ret = acl_check_extended_right(tmp_ctx, >+ module, >+ req, >+ objectclass, >+ sd, >+ acl_user_token(module), > GUID_DRS_FORCE_CHANGE_PASSWORD, > SEC_ADS_CONTROL_ACCESS, > sid); >@@ -1107,7 +1140,12 @@ static int acl_check_password_rights( > if (add_attr_cnt != del_attr_cnt) { > pav->pwd_reset = true; > >- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), >+ ret = acl_check_extended_right(tmp_ctx, >+ module, >+ req, >+ objectclass, >+ sd, >+ acl_user_token(module), > GUID_DRS_FORCE_CHANGE_PASSWORD, > SEC_ADS_CONTROL_ACCESS, > sid); >@@ -1117,7 +1155,12 @@ static int acl_check_password_rights( > if (add_val_cnt == 1 && del_val_cnt == 1) { > pav->pwd_reset = false; > >- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), >+ ret = acl_check_extended_right(tmp_ctx, >+ module, >+ req, >+ objectclass, >+ sd, >+ acl_user_token(module), > GUID_DRS_USER_CHANGE_PASSWORD, > SEC_ADS_CONTROL_ACCESS, > sid); >@@ -1131,7 +1174,12 @@ static int acl_check_password_rights( > if (add_val_cnt == 1 && del_val_cnt == 0) { > pav->pwd_reset = true; > >- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), >+ ret = acl_check_extended_right(tmp_ctx, >+ module, >+ req, >+ objectclass, >+ sd, >+ acl_user_token(module), > GUID_DRS_FORCE_CHANGE_PASSWORD, > SEC_ADS_CONTROL_ACCESS, > sid); >@@ -1686,6 +1734,9 @@ static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx, > struct ldb_result *acl_res; > struct security_descriptor *sd = NULL; > struct dom_sid *sid = NULL; >+ const struct dsdb_schema *schema = NULL; >+ const struct dsdb_class *objectclass = NULL; >+ struct ldb_context *ldb = ldb_module_get_ctx(module); > static const char *acl_attrs[] = { > "nTSecurityDescriptor", > "objectClass", >@@ -1706,10 +1757,20 @@ static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx, > > ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd); > sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid"); >+ schema = dsdb_get_schema(ldb, req); >+ if (!schema) { >+ return LDB_ERR_OPERATIONS_ERROR; >+ } >+ objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]); > if (ret != LDB_SUCCESS || !sd) { > return ldb_operr(ldb_module_get_ctx(module)); > } >- return acl_check_extended_right(mem_ctx, sd, acl_user_token(module), >+ return acl_check_extended_right(mem_ctx, >+ module, >+ req, >+ objectclass, >+ sd, >+ acl_user_token(module), > GUID_DRS_REANIMATE_TOMBSTONE, > SEC_ADS_CONTROL_ACCESS, sid); > } >diff --git a/source4/dsdb/samdb/ldb_modules/acl_util.c b/source4/dsdb/samdb/ldb_modules/acl_util.c >index f917d99517a4..08a95c1c310e 100644 >--- a/source4/dsdb/samdb/ldb_modules/acl_util.c >+++ b/source4/dsdb/samdb/ldb_modules/acl_util.c >@@ -197,6 +197,9 @@ fail: > > /* checks for validated writes */ > int acl_check_extended_right(TALLOC_CTX *mem_ctx, >+ struct ldb_module *module, >+ struct ldb_request *req, >+ const struct dsdb_class *objectclass, > struct security_descriptor *sd, > struct security_token *token, > const char *ext_right, >@@ -208,6 +211,43 @@ int acl_check_extended_right(TALLOC_CTX *mem_ctx, > uint32_t access_granted; > struct object_tree *root = NULL; > TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); >+ static const char *no_attrs[] = { NULL }; >+ struct ldb_result *extended_rights_res = NULL; >+ struct ldb_dn *extended_rights_dn = NULL; >+ struct ldb_context *ldb = ldb_module_get_ctx(module); >+ int ret = 0; >+ >+ /* >+ * Find the extended right and check if applies to >+ * the objectclass of the object >+ */ >+ extended_rights_dn = samdb_extended_rights_dn(ldb, req); >+ if (!extended_rights_dn) { >+ ldb_set_errstring(ldb, >+ "access_check: CN=Extended-Rights dn could not be generated!"); >+ return LDB_ERR_OPERATIONS_ERROR; >+ } >+ >+ /* Note: we are checking only the structural object class. */ >+ ret = dsdb_module_search(module, req, &extended_rights_res, >+ extended_rights_dn, LDB_SCOPE_ONELEVEL, >+ no_attrs, >+ DSDB_FLAG_NEXT_MODULE | >+ DSDB_FLAG_AS_SYSTEM, >+ req, >+ "(&(rightsGuid=%s)(appliesTo=%s))", >+ ext_right, >+ GUID_string(tmp_ctx, >+ &(objectclass->schemaIDGUID))); >+ >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } else if (extended_rights_res->count == 0 ) { >+ ldb_debug(ldb, LDB_DEBUG_TRACE, >+ "acl_check_extended_right: Could not find appliesTo for %s\n", >+ ext_right); >+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; >+ } > > GUID_from_string(ext_right, &right); > >diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c >index 21555491159d..a58e290607c5 100644 >--- a/source4/dsdb/samdb/ldb_modules/dirsync.c >+++ b/source4/dsdb/samdb/ldb_modules/dirsync.c >@@ -1065,7 +1065,9 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req > if (!(dirsync_ctl->flags & LDAP_DIRSYNC_OBJECT_SECURITY)) { > struct dom_sid *sid; > struct security_descriptor *sd = NULL; >- const char *acl_attrs[] = { "nTSecurityDescriptor", "objectSid", NULL }; >+ const char *acl_attrs[] = { "nTSecurityDescriptor", "objectSid", "objectClass", NULL }; >+ const struct dsdb_schema *schema = NULL; >+ const struct dsdb_class *objectclass = NULL; > /* > * If we don't have the flag and if we have the "replicate directory change" granted > * then we upgrade ourself to system to not be blocked by the acl >@@ -1095,7 +1097,14 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req > if (ret != LDB_SUCCESS) { > return ret; > } >- ret = acl_check_extended_right(dsc, sd, acl_user_token(module), GUID_DRS_GET_CHANGES, SEC_ADS_CONTROL_ACCESS, sid); >+ schema = dsdb_get_schema(ldb, req); >+ if (!schema) { >+ return LDB_ERR_OPERATIONS_ERROR; >+ } >+ objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]); >+ ret = acl_check_extended_right(dsc, module, req, objectclass, >+ sd, acl_user_token(module), >+ GUID_DRS_GET_CHANGES, SEC_ADS_CONTROL_ACCESS, sid); > > if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { > return ret; >diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c >index 5352af1099f7..6db7840b0c1f 100644 >--- a/source4/dsdb/samdb/ldb_modules/samldb.c >+++ b/source4/dsdb/samdb/ldb_modules/samldb.c >@@ -2192,12 +2192,15 @@ static int samldb_check_user_account_control_objectclass_invariants( > return LDB_SUCCESS; > } > >-static int samldb_get_domain_secdesc(struct samldb_ctx *ac, >- struct security_descriptor **domain_sd) >+static int samldb_get_domain_secdesc_and_oc(struct samldb_ctx *ac, >+ struct security_descriptor **domain_sd, >+ const struct dsdb_class **objectclass) > { >- const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL}; >+ const char * const sd_attrs[] = {"ntSecurityDescriptor", "objectClass", NULL}; > struct ldb_result *res; > struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); >+ const struct dsdb_schema *schema = NULL; >+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); > int ret = dsdb_module_search_dn(ac->module, ac, &res, > domain_dn, > sd_attrs, >@@ -2210,6 +2213,11 @@ static int samldb_get_domain_secdesc(struct samldb_ctx *ac, > return ldb_module_operr(ac->module); > } > >+ schema = dsdb_get_schema(ldb, ac->req); >+ if (!schema) { >+ return ldb_module_operr(ac->module);; >+ } >+ *objectclass = dsdb_get_structural_oc_from_msg(schema, res->msgs[0]); > return dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(ac->module), > ac, res->msgs[0], domain_sd); > >@@ -2228,6 +2236,7 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, > bool need_acl_check = false; > struct security_token *user_token; > struct security_descriptor *domain_sd; >+ const struct dsdb_class *objectclass = NULL; > const struct uac_to_guid { > uint32_t uac; > uint32_t priv_to_change_from; >@@ -2313,7 +2322,7 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, > return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; > } > >- ret = samldb_get_domain_secdesc(ac, &domain_sd); >+ ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass); > if (ret != LDB_SUCCESS) { > return ret; > } >@@ -2344,7 +2353,11 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, > ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; > } > } else if (map[i].guid) { >- ret = acl_check_extended_right(ac, domain_sd, >+ ret = acl_check_extended_right(ac, >+ ac->module, >+ ac->req, >+ objectclass, >+ domain_sd, > user_token, > map[i].guid, > SEC_ADS_CONTROL_ACCESS, >@@ -2684,12 +2697,11 @@ static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac, > { > struct ldb_context *ldb = ldb_module_get_ctx(ac->module); > int ret = 0; >- struct ldb_result *res = NULL; >- const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL}; > struct security_token *user_token = NULL; > struct security_descriptor *domain_sd = NULL; > struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); > const char *operation = ""; >+ const struct dsdb_class *objectclass = NULL; > > if (dsdb_module_am_system(ac->module)) { > return LDB_SUCCESS; >@@ -2711,24 +2723,15 @@ static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac, > return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; > } > >- ret = dsdb_module_search_dn(ac->module, ac, &res, >- domain_dn, >- sd_attrs, >- DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, >- ac->req); >- if (ret != LDB_SUCCESS) { >- return ret; >- } >- if (res->count != 1) { >- return ldb_module_operr(ac->module); >- } >- >- ret = dsdb_get_sd_from_ldb_message(ldb, ac, res->msgs[0], &domain_sd); >+ ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass); > if (ret != LDB_SUCCESS) { > return ret; > } >- >- ret = acl_check_extended_right(ac, domain_sd, >+ ret = acl_check_extended_right(ac, >+ ac->module, >+ ac->req, >+ objectclass, >+ domain_sd, > user_token, > GUID_DRS_UNEXPIRE_PASSWORD, > SEC_ADS_CONTROL_ACCESS, >@@ -3758,16 +3761,21 @@ static int samldb_check_sensitive_attributes(struct samldb_ctx *ac) > el = ldb_msg_find_element(ac->msg, "msDS-SecondaryKrbTgtNumber"); > if (el) { > struct security_descriptor *domain_sd; >+ const struct dsdb_class *objectclass = NULL; > /* > * msDS-SecondaryKrbTgtNumber allows the creator to > * become an RODC, this is trusted as an RODC > * account > */ >- ret = samldb_get_domain_secdesc(ac, &domain_sd); >+ ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass); > if (ret != LDB_SUCCESS) { > return ret; > } >- ret = acl_check_extended_right(ac, domain_sd, >+ ret = acl_check_extended_right(ac, >+ ac->module, >+ ac->req, >+ objectclass, >+ domain_sd, > user_token, > GUID_DRS_DS_INSTALL_REPLICA, > SEC_ADS_CONTROL_ACCESS, >-- >2.25.1 > > >From 938887057406a303fa54ef2f8bd0393b49c07722 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 1 Nov 2021 17:19:29 +1300 >Subject: [PATCH 155/262] CVE-2020-25722 Check all elements in acl_check_spn() > not just the first one > >Thankfully we are aleady in a loop over all the message elements in >acl_modify() so this is an easy and safe change to make. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz> >--- > selftest/knownfail.d/acl-spn | 1 - > source4/dsdb/samdb/ldb_modules/acl.c | 31 +++++++++++++++++++++------- > 2 files changed, 23 insertions(+), 9 deletions(-) > delete mode 100644 selftest/knownfail.d/acl-spn > >diff --git a/selftest/knownfail.d/acl-spn b/selftest/knownfail.d/acl-spn >deleted file mode 100644 >index e68add920a61..000000000000 >--- a/selftest/knownfail.d/acl-spn >+++ /dev/null >@@ -1 +0,0 @@ >-^samba4.ldap.acl.python.*AclSPNTests.test_delete_add_spn >diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c >index 9cae15881de0..d0b3da4d9e8a 100644 >--- a/source4/dsdb/samdb/ldb_modules/acl.c >+++ b/source4/dsdb/samdb/ldb_modules/acl.c >@@ -653,9 +653,14 @@ success: > return LDB_SUCCESS; > } > >+/* >+ * Passing in 'el' is critical, we want to check all the values. >+ * >+ */ > static int acl_check_spn(TALLOC_CTX *mem_ctx, > struct ldb_module *module, > struct ldb_request *req, >+ const struct ldb_message_element *el, > struct security_descriptor *sd, > struct dom_sid *sid, > const struct dsdb_attribute *attr, >@@ -667,7 +672,6 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, > struct ldb_context *ldb = ldb_module_get_ctx(module); > struct ldb_result *acl_res; > struct ldb_result *netbios_res; >- struct ldb_message_element *el; > struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx); > uint32_t userAccountControl; > const char *samAccountName; >@@ -717,6 +721,23 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, > return ret; > } > >+ /* >+ * If we have "validated write spn", allow delete of any >+ * existing value (this keeps constrained delete to the same >+ * rules as unconstrained) >+ */ >+ if (req->operation == LDB_MODIFY) { >+ /* >+ * If not add or replace (eg delete), >+ * return success >+ */ >+ if ((el->flags >+ & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0) { >+ talloc_free(tmp_ctx); >+ return LDB_SUCCESS; >+ } >+ } >+ > ret = dsdb_module_search_dn(module, tmp_ctx, > &acl_res, req->op.mod.message->dn, > acl_attrs, >@@ -745,13 +766,6 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, > > netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL); > >- el = ldb_msg_find_element(req->op.mod.message, "servicePrincipalName"); >- if (!el) { >- talloc_free(tmp_ctx); >- return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, >- "Error finding element for servicePrincipalName."); >- } >- > /* NTDSDSA objectGuid of object we are checking SPN for */ > if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) { > ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx, >@@ -1510,6 +1524,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) > ret = acl_check_spn(tmp_ctx, > module, > req, >+ el, > sd, > sid, > attr, >-- >2.25.1 > > >From 3f5fe7deac9d1977f11e5e12def97362651e24b8 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 1 Nov 2021 17:21:16 +1300 >Subject: [PATCH 156/262] CVE-2020-25722 Check for all errors from > acl_check_extended_right() in acl_check_spn() > >We should not fail open on error. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz> >--- > source4/dsdb/samdb/ldb_modules/acl.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c >index d0b3da4d9e8a..712724909e3f 100644 >--- a/source4/dsdb/samdb/ldb_modules/acl.c >+++ b/source4/dsdb/samdb/ldb_modules/acl.c >@@ -712,7 +712,7 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, > SEC_ADS_SELF_WRITE, > sid); > >- if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { >+ if (ret != LDB_SUCCESS) { > dsdb_acl_debug(sd, acl_user_token(module), > req->op.mod.message->dn, > true, >-- >2.25.1 > > >From 4122e8adf9ad9288576f5b9941facf9cbaa6b62d Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Mon, 4 Oct 2021 12:56:42 +1300 >Subject: [PATCH 157/262] CVE-2020-25722 pytests: add reverse lookup dict for > LDB error codes > >You can give ldb_err() it a number, an LdbError, or a sequence of >numbers, and it will return the corresponding strings. Examples: > >ldb_err(68) # "LDB_ERR_ENTRY_ALREADY_EXISTS" >LDB_ERR_LUT[68] # "LDB_ERR_ENTRY_ALREADY_EXISTS" > >expected = (ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, > ldb.ERR_INVALID_CREDENTIALS) >try: > foo() >except ldb.LdbError as e: > self.fail(f"got {ldb_err(e)}, expected one of {ldb_err(expected)}") > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/__init__.py | 16 ++++++++++++++++ > 1 file changed, 16 insertions(+) > >diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py >index 14924528b0f9..388036939cd1 100644 >--- a/python/samba/tests/__init__.py >+++ b/python/samba/tests/__init__.py >@@ -64,6 +64,22 @@ BINDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), > > HEXDUMP_FILTER = bytearray([x if ((len(repr(chr(x))) == 3) and (x < 127)) else ord('.') for x in range(256)]) > >+LDB_ERR_LUT = {v: k for k,v in vars(ldb).items() if k.startswith('ERR_')} >+ >+def ldb_err(v): >+ if isinstance(v, ldb.LdbError): >+ v = v.args[0] >+ >+ if v in LDB_ERR_LUT: >+ return LDB_ERR_LUT[v] >+ >+ try: >+ return f"[{', '.join(LDB_ERR_LUT.get(x, x) for x in v)}]" >+ except TypeError as e: >+ print(e) >+ return v >+ >+ > def DynamicTestCase(cls): > cls.setUpDynamicTestCases() > return cls >-- >2.25.1 > > >From 962f30faedb4a3570dc1fa1536a7362eb14f58bc Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Sun, 24 Oct 2021 15:18:05 +1300 >Subject: [PATCH 158/262] CVE-2020-25722 pytest: assertRaisesLdbError invents a > message if you're lazy > >This makes it easier to convert tests that don't have good messages. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/tests/__init__.py | 2 ++ > 1 file changed, 2 insertions(+) > >diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py >index 388036939cd1..e04ddcb4ba8e 100644 >--- a/python/samba/tests/__init__.py >+++ b/python/samba/tests/__init__.py >@@ -317,6 +317,8 @@ class TestCase(unittest.TestCase): > > def assertRaisesLdbError(self, errcode, message, f, *args, **kwargs): > """Assert a function raises a particular LdbError.""" >+ if message is None: >+ message = f"{f.__name__}(*{args}, **{kwargs})" > try: > f(*args, **kwargs) > except ldb.LdbError as e: >-- >2.25.1 > > >From e617f6ac1a0a8ad4649a3d73c606dbebecda6f12 Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Wed, 11 Aug 2021 16:56:07 +1200 >Subject: [PATCH 159/262] CVE-2020-25722 s4/dsdb/cracknames: always free > tmp_ctx in spn_alias > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/dsdb/samdb/cracknames.c | 6 +++++- > 1 file changed, 5 insertions(+), 1 deletion(-) > >diff --git a/source4/dsdb/samdb/cracknames.c b/source4/dsdb/samdb/cracknames.c >index b4bd9d8f9c9a..7336778ec533 100644 >--- a/source4/dsdb/samdb/cracknames.c >+++ b/source4/dsdb/samdb/cracknames.c >@@ -99,10 +99,12 @@ static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, stru > > service_dn = ldb_dn_new(tmp_ctx, ldb_ctx, "CN=Directory Service,CN=Windows NT,CN=Services"); > if ( ! ldb_dn_add_base(service_dn, ldb_get_config_basedn(ldb_ctx))) { >+ talloc_free(tmp_ctx); > return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; > } > service_dn_str = ldb_dn_alloc_linearized(tmp_ctx, service_dn); > if ( ! service_dn_str) { >+ talloc_free(tmp_ctx); > return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; > } > >@@ -111,13 +113,15 @@ static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, stru > > if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { > DEBUG(1, ("ldb_search: dn: %s not found: %s\n", service_dn_str, ldb_errstring(ldb_ctx))); >+ talloc_free(tmp_ctx); > return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; > } else if (ret == LDB_ERR_NO_SUCH_OBJECT) { > DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str)); >+ talloc_free(tmp_ctx); > return DRSUAPI_DS_NAME_STATUS_NOT_FOUND; > } else if (res->count != 1) { >- talloc_free(res); > DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str)); >+ talloc_free(tmp_ctx); > return DRSUAPI_DS_NAME_STATUS_NOT_FOUND; > } > >-- >2.25.1 > > >From 5fad50381f35ba20c0a0716f5b359bd600197729 Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Tue, 10 Aug 2021 23:02:36 +0000 >Subject: [PATCH 160/262] CVE-2020-25722 s4/cracknames: lookup_spn_alias > doesn't need krb5 context > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/dsdb/samdb/cracknames.c | 7 +++---- > 1 file changed, 3 insertions(+), 4 deletions(-) > >diff --git a/source4/dsdb/samdb/cracknames.c b/source4/dsdb/samdb/cracknames.c >index 7336778ec533..235276bc4c87 100644 >--- a/source4/dsdb/samdb/cracknames.c >+++ b/source4/dsdb/samdb/cracknames.c >@@ -72,9 +72,9 @@ static WERROR dns_domain_from_principal(TALLOC_CTX *mem_ctx, struct smb_krb5_con > > info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY; > return WERR_OK; >-} >+} > >-static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, struct ldb_context *ldb_ctx, >+static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(struct ldb_context *ldb_ctx, > TALLOC_CTX *mem_ctx, > const char *alias_from, > char **alias_to) >@@ -219,8 +219,7 @@ static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_c > dns_name = (const char *)component->data; > > /* MAP it */ >- namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context, >- sam_ctx, mem_ctx, >+ namestatus = LDB_lookup_spn_alias(sam_ctx, mem_ctx, > service, &new_service); > > if (namestatus == DRSUAPI_DS_NAME_STATUS_NOT_FOUND) { >-- >2.25.1 > > >From a25a8fd3a07dfc22324348c32cd8b23d5bfdce6b Mon Sep 17 00:00:00 2001 >From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Date: Wed, 28 Jul 2021 05:38:50 +0000 >Subject: [PATCH 161/262] CVE-2020-25722 samba-tool spn: accept -H for database > url > >Following the convention and making testing easier > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 > >Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> >Reviewed-by: Andrew Bartlett <abartlet@samba.org> >--- > python/samba/netcmd/spn.py | 33 ++++++++++++++++++++++----------- > 1 file changed, 22 insertions(+), 11 deletions(-) > >diff --git a/python/samba/netcmd/spn.py b/python/samba/netcmd/spn.py >index f0069460e3ef..46e9c59272af 100644 >--- a/python/samba/netcmd/spn.py >+++ b/python/samba/netcmd/spn.py >@@ -18,7 +18,6 @@ > > import samba.getopt as options > import ldb >-from samba import provision > from samba.samdb import SamDB > from samba.auth import system_session > from samba.netcmd.common import _get_user_realm_domain >@@ -40,14 +39,20 @@ class cmd_spn_list(Command): > "credopts": options.CredentialsOptions, > "versionopts": options.VersionOptions, > } >+ takes_options = [ >+ Option("-H", "--URL", help="LDB URL for database or target server", >+ type=str, metavar="URL", dest="H"), >+ ] > > takes_args = ["user"] > >- def run(self, user, credopts=None, sambaopts=None, versionopts=None): >+ def run(self, user, H=None, >+ credopts=None, >+ sambaopts=None, >+ versionopts=None): > lp = sambaopts.get_loadparm() > creds = credopts.get_credentials(lp) >- paths = provision.provision_paths_from_lp(lp, lp.get("realm")) >- sam = SamDB(paths.samdb, session_info=system_session(), >+ sam = SamDB(H, session_info=system_session(), > credentials=creds, lp=lp) > # TODO once I understand how, use the domain info to naildown > # to the correct domain >@@ -82,17 +87,20 @@ class cmd_spn_add(Command): > "versionopts": options.VersionOptions, > } > takes_options = [ >+ Option("-H", "--URL", help="LDB URL for database or target server", >+ type=str, metavar="URL", dest="H"), > Option("--force", help="Force the addition of the spn" > " even it exists already", action="store_true"), >- ] >+ ] > takes_args = ["name", "user"] > >- def run(self, name, user, force=False, credopts=None, sambaopts=None, >+ def run(self, name, user, H=None, force=False, >+ credopts=None, >+ sambaopts=None, > versionopts=None): > lp = sambaopts.get_loadparm() > creds = credopts.get_credentials(lp) >- paths = provision.provision_paths_from_lp(lp, lp.get("realm")) >- sam = SamDB(paths.samdb, session_info=system_session(), >+ sam = SamDB(H, session_info=system_session(), > credentials=creds, lp=lp) > res = sam.search( > expression="servicePrincipalName=%s" % ldb.binary_encode(name), >@@ -141,15 +149,18 @@ class cmd_spn_delete(Command): > "credopts": options.CredentialsOptions, > "versionopts": options.VersionOptions, > } >+ takes_options = [ >+ Option("-H", "--URL", help="LDB URL for database or target server", >+ type=str, metavar="URL", dest="H"), >+ ] > > takes_args = ["name", "user?"] > >- def run(self, name, user=None, credopts=None, sambaopts=None, >+ def run(self, name, user=None, H=None, credopts=None, sambaopts=None, > versionopts=None): > lp = sambaopts.get_loadparm() > creds = credopts.get_credentials(lp) >- paths = provision.provision_paths_from_lp(lp, lp.get("realm")) >- sam = SamDB(paths.samdb, session_info=system_session(), >+ sam = SamDB(H, session_info=system_session(), > credentials=creds, lp=lp) > res = sam.search( > expression="servicePrincipalName=%s" % ldb.binary_encode(name), >-- >2.25.1 > > >From 0bdd9f794b771b93900a404b0f94ac4e783d4039 Mon Sep 17 00:00:00 2001 >Fr