[SCM] Samba Shared Repository - branch v4-10-test updated
Karolin Seeger
kseeger at samba.org
Tue Dec 10 09:25:22 UTC 2019
The branch, v4-10-test has been updated
via 8f9a2afd469 Merge tag 'samba-4.10.11' into v4-10-test
via d644dfea6f2 VERSION: Disable GIT_SNAPSHOT for the 4.10.11 release.
via aa4577474f1 WHATSNEW: Add release notes for Samba 4.10.11.
via 8330f54718e CVE-2019-14870: mit-kdc: enforce delegation_not_allowed flag
via 3ec39df607f CVE-2019-14870: heimdal: enforce delegation_not_allowed in S4U2Self
via 534fd4b6ec3 CVE-2019-14870: heimdal: add S4U test for delegation_not_allowed
via c706fb4430d samba-tool: add user-sensitive command to set not-delegated flag
via d38677abd92 s4-torture: Reduce flapping in SambaToolDrsTests.test_samba_tool_replicate_local
via 329b78ed92c CVE-2019-14861: Test to demonstrate the bug
via 181feb7a6be CVE-2019-14861: s4-rpc/dnsserver: Avoid crash in ldb_qsort() via dcesrv_DnssrvEnumRecords)
via 1cc564ada17 CVE-2019-14861: s4-rpc_server: Remove special case for @ in dns_build_tree()
via a67944da822 CVE-2019-14861: s4-rpc/dnsserver: Confirm sort behaviour in dcesrv_DnssrvEnumRecords
via 97f0deb4e38 VERSION: Re-enable GIT_SNAPSHOT.
via 9378520acaa VERSION: Bump version up to 4.10.11.
from cc58e4b1899 heimdal-build: avoid hard-coded /usr/include/heimdal in asn1_compile-generated code.
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-10-test
- Log -----------------------------------------------------------------
commit 8f9a2afd4696df34432c86d5e7b09be0f0cea048
Merge: cc58e4b1899 d644dfea6f2
Author: Karolin Seeger <kseeger at samba.org>
Date: Tue Dec 10 10:24:44 2019 +0100
Merge tag 'samba-4.10.11' into v4-10-test
samba: tag release samba-4.10.11
-----------------------------------------------------------------------
Summary of changes:
WHATSNEW.txt | 66 ++++++++++-
python/samba/netcmd/user.py | 58 ++++++++++
python/samba/tests/dcerpc/dnsserver.py | 148 ++++++++++++++++++++++++
selftest/flapping.d/dnsserver | 3 +
source4/heimdal/kdc/krb5tgs.c | 58 ++++++----
source4/kdc/mit_samba.c | 5 +
source4/kdc/sdb_to_kdb.c | 17 +--
source4/rpc_server/dnsserver/dcerpc_dnsserver.c | 21 ++--
source4/rpc_server/dnsserver/dnsdata.c | 28 ++---
source4/rpc_server/dnsserver/dnsserver.h | 4 +-
source4/selftest/tests.py | 1 +
source4/torture/drs/python/samba_tool_drs.py | 3 +-
testprogs/blackbox/test_s4u_heimdal.sh | 73 ++++++++++++
13 files changed, 418 insertions(+), 67 deletions(-)
create mode 100644 selftest/flapping.d/dnsserver
create mode 100755 testprogs/blackbox/test_s4u_heimdal.sh
Changeset truncated at 500 lines:
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 83a4f3b994d..6b3fbc88d50 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,3 +1,65 @@
+ ===============================
+ Release Notes for Samba 4.10.11
+ December 10, 2019
+ ===============================
+
+
+This is a security release in order to address the following defects:
+
+o CVE-2019-14861: Samba AD DC zone-named record Denial of Service in DNS
+ management server (dnsserver).
+o CVE-2019-14870: DelegationNotAllowed not being enforced in protocol transition
+ on Samba AD DC.
+
+
+=======
+Details
+=======
+
+o CVE-2019-14861:
+ An authenticated user can crash the DCE/RPC DNS management server by creating
+ records with matching the zone name.
+
+o CVE-2019-14870:
+ The DelegationNotAllowed Kerberos feature restriction was not being applied
+ when processing protocol transition requests (S4U2Self), in the AD DC KDC.
+
+For more details and workarounds, please refer to the security advisories.
+
+
+Changes since 4.10.10:
+----------------------
+
+o Andrew Bartlett <abartlet at samba.org>
+ * BUG 14138: CVE-2019-14861: Fix DNSServer RPC server crash.
+
+o Isaac Boukris <iboukris at gmail.com>
+ * BUG 14187: CVE-2019-14870: DelegationNotAllowed not being enforced.
+
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical IRC channel on irc.freenode.net.
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored. All bug reports should
+be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
+database (https://bugzilla.samba.org/).
+
+
+======================================================================
+== Our Code, Our Bugs, Our Responsibility.
+== The Samba Team
+======================================================================
+
+
+Release notes for older releases follow:
+----------------------------------------
+
===============================
Release Notes for Samba 4.10.10
October 29, 2019
@@ -69,8 +131,8 @@ database (https://bugzilla.samba.org/).
======================================================================
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
+
==============================
Release Notes for Samba 4.10.9
diff --git a/python/samba/netcmd/user.py b/python/samba/netcmd/user.py
index 8ead8e583f3..7bf2bbc011c 100644
--- a/python/samba/netcmd/user.py
+++ b/python/samba/netcmd/user.py
@@ -2668,6 +2668,63 @@ class cmd_user_move(Command):
(username, full_new_parent_dn))
+class cmd_user_sensitive(Command):
+ """Set/unset or show UF_NOT_DELEGATED for an account."""
+
+ synopsis = "%prog <accountname> [(show|on|off)] [options]"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "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 = ["accountname", "cmd"]
+
+ def run(self, accountname, cmd, H=None, credopts=None, sambaopts=None,
+ versionopts=None):
+
+ if cmd not in ("show", "on", "off"):
+ raise CommandError("invalid argument: '%s' (choose from 'show', 'on', 'off')" % cmd)
+
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp, fallback_machine=True)
+ sam = SamDB(url=H, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ search_filter = "sAMAccountName=%s" % ldb.binary_encode(accountname)
+ flag = dsdb.UF_NOT_DELEGATED;
+
+ if cmd == "show":
+ res = sam.search(scope=ldb.SCOPE_SUBTREE, expression=search_filter,
+ attrs=["userAccountControl"])
+ if len(res) == 0:
+ raise Exception("Unable to find account where '%s'" % search_filter)
+
+ uac = int(res[0].get("userAccountControl")[0])
+
+ self.outf.write("Account-DN: %s\n" % str(res[0].dn))
+ self.outf.write("UF_NOT_DELEGATED: %s\n" % bool(uac & flag))
+
+ return
+
+ if cmd == "on":
+ on = True
+ elif cmd == "off":
+ on = False
+
+ try:
+ sam.toggle_userAccountFlags(search_filter, flag, flags_str="Not-Delegated",
+ on=on, strict=True)
+ except Exception as err:
+ raise CommandError(err)
+
+
class cmd_user(SuperCommand):
"""User management."""
@@ -2686,3 +2743,4 @@ class cmd_user(SuperCommand):
subcommands["edit"] = cmd_user_edit()
subcommands["show"] = cmd_user_show()
subcommands["move"] = cmd_user_move()
+ subcommands["sensitive"] = cmd_user_sensitive()
diff --git a/python/samba/tests/dcerpc/dnsserver.py b/python/samba/tests/dcerpc/dnsserver.py
index 0da9614d066..c6a150c876f 100644
--- a/python/samba/tests/dcerpc/dnsserver.py
+++ b/python/samba/tests/dcerpc/dnsserver.py
@@ -156,6 +156,154 @@ class DnsserverTests(RpcInterfaceTestCase):
None)
super(DnsserverTests, self).tearDown()
+ def test_enum_is_sorted(self):
+ """
+ Confirm the zone is sorted
+ """
+
+ record_str = "192.168.50.50"
+ record_type_str = "A"
+ self.add_record(self.custom_zone, "atestrecord-1", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-2", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-3", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-4", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-0", record_type_str, record_str)
+
+ # This becomes an extra A on the zone itself by server-side magic
+ self.add_record(self.custom_zone, self.custom_zone, record_type_str, record_str)
+
+ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ self.custom_zone,
+ "@",
+ None,
+ self.record_type_int(record_type_str),
+ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA,
+ None,
+ None)
+
+ self.assertEqual(len(result.rec), 6)
+ self.assertEqual(result.rec[0].dnsNodeName.str, "")
+ self.assertEqual(result.rec[1].dnsNodeName.str, "atestrecord-0")
+ self.assertEqual(result.rec[2].dnsNodeName.str, "atestrecord-1")
+ self.assertEqual(result.rec[3].dnsNodeName.str, "atestrecord-2")
+ self.assertEqual(result.rec[4].dnsNodeName.str, "atestrecord-3")
+ self.assertEqual(result.rec[5].dnsNodeName.str, "atestrecord-4")
+
+ def test_enum_is_sorted_with_zone_dup(self):
+ """
+ Confirm the zone is sorted
+ """
+
+ record_str = "192.168.50.50"
+ record_type_str = "A"
+ self.add_record(self.custom_zone, "atestrecord-1", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-2", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-3", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-4", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-0", record_type_str, record_str)
+
+ # This triggers a bug in old Samba
+ self.add_record(self.custom_zone, self.custom_zone + "1", record_type_str, record_str)
+
+ dn, record = self.get_record_from_db(self.custom_zone, self.custom_zone + "1")
+
+ new_dn = ldb.Dn(self.samdb, str(dn))
+ new_dn.set_component(0, "dc", self.custom_zone)
+ self.samdb.rename(dn, new_dn)
+
+ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ self.custom_zone,
+ "@",
+ None,
+ self.record_type_int(record_type_str),
+ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA,
+ None,
+ None)
+
+ self.assertEqual(len(result.rec), 7)
+ self.assertEqual(result.rec[0].dnsNodeName.str, "")
+ self.assertEqual(result.rec[1].dnsNodeName.str, "atestrecord-0")
+ self.assertEqual(result.rec[2].dnsNodeName.str, "atestrecord-1")
+ self.assertEqual(result.rec[3].dnsNodeName.str, "atestrecord-2")
+ self.assertEqual(result.rec[4].dnsNodeName.str, "atestrecord-3")
+ self.assertEqual(result.rec[5].dnsNodeName.str, "atestrecord-4")
+
+ # Windows doesn't reload the zone fast enough, but doesn't
+ # have the bug anyway, it will sort last on both names (where
+ # it should)
+ if result.rec[6].dnsNodeName.str != (self.custom_zone + "1"):
+ self.assertEqual(result.rec[6].dnsNodeName.str, self.custom_zone)
+
+ def test_enum_is_sorted_children_prefix_first(self):
+ """
+ Confirm the zone returns the selected prefix first but no more
+ as Samba is flappy for the full sort
+ """
+
+ record_str = "192.168.50.50"
+ record_type_str = "A"
+ self.add_record(self.custom_zone, "atestrecord-1.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-2.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-3.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-4.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-0.a.b", record_type_str, record_str)
+
+ # Not expected to be returned
+ self.add_record(self.custom_zone, "atestrecord-0.b.b", record_type_str, record_str)
+
+ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ self.custom_zone,
+ "a.b",
+ None,
+ self.record_type_int(record_type_str),
+ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA,
+ None,
+ None)
+
+ self.assertEqual(len(result.rec), 6)
+ self.assertEqual(result.rec[0].dnsNodeName.str, "")
+
+ def test_enum_is_sorted_children(self):
+ """
+ Confirm the zone is sorted
+ """
+
+ record_str = "192.168.50.50"
+ record_type_str = "A"
+ self.add_record(self.custom_zone, "atestrecord-1.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-2.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-3.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-4.a.b", record_type_str, record_str)
+ self.add_record(self.custom_zone, "atestrecord-0.a.b", record_type_str, record_str)
+
+ # Not expected to be returned
+ self.add_record(self.custom_zone, "atestrecord-0.b.b", record_type_str, record_str)
+
+ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+ 0,
+ self.server,
+ self.custom_zone,
+ "a.b",
+ None,
+ self.record_type_int(record_type_str),
+ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA,
+ None,
+ None)
+
+ self.assertEqual(len(result.rec), 6)
+ self.assertEqual(result.rec[0].dnsNodeName.str, "")
+ self.assertEqual(result.rec[1].dnsNodeName.str, "atestrecord-0")
+ self.assertEqual(result.rec[2].dnsNodeName.str, "atestrecord-1")
+ self.assertEqual(result.rec[3].dnsNodeName.str, "atestrecord-2")
+ self.assertEqual(result.rec[4].dnsNodeName.str, "atestrecord-3")
+ self.assertEqual(result.rec[5].dnsNodeName.str, "atestrecord-4")
+
# This test fails against Samba (but passes against Windows),
# because Samba does not return the record when we enum records.
# Records can be given DNS_RANK_NONE when the zone they are in
diff --git a/selftest/flapping.d/dnsserver b/selftest/flapping.d/dnsserver
new file mode 100644
index 00000000000..bf2dc99ce11
--- /dev/null
+++ b/selftest/flapping.d/dnsserver
@@ -0,0 +1,3 @@
+# This is not stable in samba due to a bug
+^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_enum_is_sorted_children
+^samba.tests.dcerpc.dnsserver.python2.samba.tests.dcerpc.dnsserver.DnsserverTests.test_enum_is_sorted_children
diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index ff7d93138c0..ee3ac3d8f53 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -1975,30 +1975,42 @@ server_lookup:
if (ret)
goto out;
+ ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
+ NULL, &s4u2self_impersonated_clientdb,
+ &s4u2self_impersonated_client);
+ if (ret) {
+ const char *msg;
+
+ /*
+ * If the client belongs to the same realm as our krbtgt, it
+ * should exist in the local database.
+ *
+ */
+
+ if (ret == HDB_ERR_NOENTRY)
+ ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ msg = krb5_get_error_message(context, ret);
+ kdc_log(context, config, 1,
+ "S2U4Self principal to impersonate %s not found in database: %s",
+ tpn, msg);
+ krb5_free_error_message(context, msg);
+ goto out;
+ }
+
+ /* Ignore pw_end attributes (as Windows does),
+ * since S4U2Self is not password authentication. */
+ free(s4u2self_impersonated_client->entry.pw_end);
+ s4u2self_impersonated_client->entry.pw_end = NULL;
+
+ ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
+ NULL, NULL, FALSE);
+ if (ret)
+ goto out;
+
/* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
if(rspac.data) {
krb5_pac p = NULL;
krb5_data_free(&rspac);
- ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
- NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
- if (ret) {
- const char *msg;
-
- /*
- * If the client belongs to the same realm as our krbtgt, it
- * should exist in the local database.
- *
- */
-
- if (ret == HDB_ERR_NOENTRY)
- ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
- msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 1,
- "S2U4Self principal to impersonate %s not found in database: %s",
- tpn, msg);
- krb5_free_error_message(context, msg);
- goto out;
- }
ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, &p);
if (ret) {
kdc_log(context, config, 0, "PAC generation failed for -- %s",
@@ -2034,10 +2046,12 @@ server_lookup:
/*
* If the service isn't trusted for authentication to
- * delegation, remove the forward flag.
+ * delegation or if the impersonate client is disallowed
+ * forwardable, remove the forwardable flag.
*/
- if (client->entry.flags.trusted_for_delegation) {
+ if (client->entry.flags.trusted_for_delegation &&
+ s4u2self_impersonated_client->entry.flags.forwardable) {
str = "[forwardable]";
} else {
b->kdc_options.forwardable = 0;
diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index 54dcd545ea1..5a4f6e73e97 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -304,6 +304,11 @@ fetch_referral_principal:
sdb_free_entry(&sentry);
+ if ((kflags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) == 0) {
+ kentry->attributes &= ~KRB5_KDB_DISALLOW_FORWARDABLE;
+ kentry->attributes &= ~KRB5_KDB_DISALLOW_PROXIABLE;
+ }
+
done:
krb5_free_principal(ctx->context, referral_principal);
referral_principal = NULL;
diff --git a/source4/kdc/sdb_to_kdb.c b/source4/kdc/sdb_to_kdb.c
index 1411b0f5f66..2981f180333 100644
--- a/source4/kdc/sdb_to_kdb.c
+++ b/source4/kdc/sdb_to_kdb.c
@@ -36,18 +36,13 @@ static int SDBFlags_to_kflags(const struct SDBFlags *s,
if (s->initial) {
*k |= KRB5_KDB_DISALLOW_TGT_BASED;
}
- /*
- * Do not set any disallow rules for forwardable, proxiable,
- * renewable, postdate and server.
- *
- * The KDC will take care setting the flags based on the incoming
- * ticket.
- */
- if (s->forwardable) {
- ;
+ /* The forwardable and proxiable flags are set according to client and
+ * server attributes. */
+ if (!s->forwardable) {
+ *k |= KRB5_KDB_DISALLOW_FORWARDABLE;
}
- if (s->proxiable) {
- ;
+ if (!s->proxiable) {
+ *k |= KRB5_KDB_DISALLOW_PROXIABLE;
}
if (s->renewable) {
;
diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
index f8a8f0bae61..910de9a1efd 100644
--- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
+++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
@@ -1758,6 +1758,7 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
struct DNS_RPC_RECORDS_ARRAY *recs;
char **add_names = NULL;
char *rname;
+ const char *preference_name = NULL;
int add_count = 0;
int i, ret, len;
WERROR status;
@@ -1774,6 +1775,7 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
LDB_SCOPE_ONELEVEL, attrs,
"(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))");
+ preference_name = "@";
} else {
char *encoded_name
= ldb_binary_encode_string(tmp_ctx, name);
@@ -1781,6 +1783,7 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
LDB_SCOPE_ONELEVEL, attrs,
"(&(objectClass=dnsNode)(|(name=%s)(name=*.%s))(!(dNSTombstoned=TRUE)))",
encoded_name, encoded_name);
+ preference_name = name;
}
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
@@ -1794,16 +1797,18 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
recs = talloc_zero(mem_ctx, struct DNS_RPC_RECORDS_ARRAY);
W_ERROR_HAVE_NO_MEMORY_AND_FREE(recs, tmp_ctx);
- /* Sort the names, so that the first record is the parent record */
- ldb_qsort(res->msgs, res->count, sizeof(struct ldb_message *), name,
- (ldb_qsort_cmp_fn_t)dns_name_compare);
+ /*
+ * Sort the names, so that the records are in order by the child
+ * component below "name".
+ *
+ * A full tree sort is not required, so we pass in "name" so
+ * we know which level to sort, as only direct children are
+ * eventually returned
+ */
+ LDB_TYPESAFE_QSORT(res->msgs, res->count, name, dns_name_compare);
/* Build a tree of name components from dns name */
- if (strcasecmp(name, z->name) == 0) {
- tree = dns_build_tree(tmp_ctx, "@", res);
- } else {
- tree = dns_build_tree(tmp_ctx, name, res);
- }
--
Samba Shared Repository
More information about the samba-cvs
mailing list