summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarolin Seeger <kseeger@samba.org>2019-12-10 10:25:47 +0100
committerKarolin Seeger <kseeger@samba.org>2019-12-10 10:25:47 +0100
commite81ef10bbf5579e24a7eaa33a775d3da74dd6dd0 (patch)
tree9eda32549a0cb2267ba06f6e569fb2b883e6f9ec
parent91f39dbda151f6a2768b6e5eff59f931f303721f (diff)
parent7fc8563c2f6381c0389cdbb8c833e9bb89ec068b (diff)
downloadsamba-e81ef10bbf5579e24a7eaa33a775d3da74dd6dd0.tar.gz
Merge tag 'samba-4.11.3' into v4-11-test
samba: tag release samba-4.11.3
-rw-r--r--WHATSNEW.txt66
-rw-r--r--python/samba/netcmd/user.py58
-rw-r--r--python/samba/tests/dcerpc/dnsserver.py148
-rw-r--r--selftest/flapping.d/dnsserver2
-rw-r--r--source4/heimdal/kdc/krb5tgs.c58
-rw-r--r--source4/kdc/mit_samba.c5
-rw-r--r--source4/kdc/sdb_to_kdb.c17
-rw-r--r--source4/rpc_server/dnsserver/dcerpc_dnsserver.c21
-rw-r--r--source4/rpc_server/dnsserver/dnsdata.c28
-rw-r--r--source4/rpc_server/dnsserver/dnsserver.h4
-rwxr-xr-xsource4/selftest/tests.py1
-rw-r--r--source4/torture/drs/python/samba_tool_drs.py3
-rwxr-xr-xtestprogs/blackbox/test_s4u_heimdal.sh73
13 files changed, 417 insertions, 67 deletions
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 8c6db3b3034..8bafa38b47c 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,4 +1,66 @@
==============================
+ Release Notes for Samba 4.11.3
+ 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.11.2:
+---------------------
+
+o Andrew Bartlett <abartlet@samba.org>
+ * BUG 14138: CVE-2019-14861: Fix DNSServer RPC server crash.
+
+o Isaac Boukris <iboukris@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.11.2
October 29, 2019
==============================
@@ -69,8 +131,8 @@ database (https://bugzilla.samba.org/).
======================================================================
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
+
==============================
Release Notes for Samba 4.11.1
diff --git a/python/samba/netcmd/user.py b/python/samba/netcmd/user.py
index 121050a26e6..3fd8e6fb7be 100644
--- a/python/samba/netcmd/user.py
+++ b/python/samba/netcmd/user.py
@@ -2642,6 +2642,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."""
@@ -2660,3 +2717,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..9b33e8522a3
--- /dev/null
+++ b/selftest/flapping.d/dnsserver
@@ -0,0 +1,2 @@
+# This is not stable in samba due to a bug
+^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_enum_is_sorted_children \ No newline at end of file
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 993e5dc4e56..b6389f2328a 100644
--- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
+++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
@@ -1763,6 +1763,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;
@@ -1779,6 +1780,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);
@@ -1786,6 +1788,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);
@@ -1799,16 +1802,18 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
recs = talloc_zero(mem_ctx, struct DNS_RPC_RECORDS_ARRAY);
W_ERROR_HAVE_NO_MEMORY_AND_FREE(recs, tmp_ctx);
- /* Sort the names, so that the first record is the parent record */
- ldb_qsort(res->msgs, res->count, sizeof(struct ldb_message *), name,
- (ldb_qsort_cmp_fn_t)dns_name_compare);
+ /*
+ * Sort the names, so that the records are in order by the child
+ * component below "name".
+ *
+ * A full tree sort is not required, so we pass in "name" so
+ * we know which level to sort, as only direct children are
+ * eventually returned
+ */
+ LDB_TYPESAFE_QSORT(res->msgs, res->count, name, dns_name_compare);
/* Build a tree of name components from dns name */
- if (strcasecmp(name, z->name) == 0) {
- tree = dns_build_tree(tmp_ctx, "@", res);
- } else {
- tree = dns_build_tree(tmp_ctx, name, res);
- }
+ tree = dns_build_tree(tmp_ctx, preference_name, res);
W_ERROR_HAVE_NO_MEMORY_AND_FREE(tree, tmp_ctx);
/* Find the parent record in the tree */
diff --git a/source4/rpc_server/dnsserver/dnsdata.c b/source4/rpc_server/dnsserver/dnsdata.c
index 2dc098a64a0..47d6f5d5c88 100644
--- a/source4/rpc_server/dnsserver/dnsdata.c
+++ b/source4/rpc_server/dnsserver/dnsdata.c
@@ -801,10 +801,11 @@ struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ld
goto failed;
}
- if (strcmp(ptr, "@") == 0) {
- base->data = res->msgs[i];
- continue;
- } else if (strcasecmp(ptr, name) == 0) {
+ /*
+ * This might be the sub-domain in the zone being
+ * requested, or @ for the root of the zone
+ */
+ if (strcasecmp(ptr, name) == 0) {
base->data = res->msgs[i];
continue;
}
@@ -1065,8 +1066,8 @@ WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
}
-int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
- char *search_name)
+int dns_name_compare(struct ldb_message * const *m1, struct ldb_message * const *m2,
+ const char *search_name)
{
const char *name1, *name2;
const char *ptr1, *ptr2;
@@ -1077,21 +1078,6 @@ int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m
return 0;
}
- /* '@' record and the search_name record gets preference */
- if (name1[0] == '@') {
- return -1;
- }
- if (search_name && strcasecmp(name1, search_name) == 0) {
- return -1;
- }
-
- if (name2[0] == '@') {
- return 1;
- }
- if (search_name && strcasecmp(name2, search_name) == 0) {
- return 1;
- }
-
/* Compare the last components of names.
* If search_name is not NULL, compare the second last components of names */
ptr1 = strrchr(name1, '.');
diff --git a/source4/rpc_server/dnsserver/dnsserver.h b/source4/rpc_server/dnsserver/dnsserver.h
index a8307ef836a..2e46e7c66a4 100644
--- a/source4/rpc_server/dnsserver/dnsserver.h
+++ b/source4/rpc_server/dnsserver/dnsserver.h
@@ -188,8 +188,8 @@ struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx, struct DNS_ADDR_
int dns_split_name_components(TALLOC_CTX *mem_ctx, const char *name, char ***components);
char *dns_split_node_name(TALLOC_CTX *mem_ctx, const char *node_name, const char *zone_name);
-int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
- char *search_name);
+int dns_name_compare(struct ldb_message * const *m1, struct ldb_message * const *m2,
+ const char *search_name);
bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2);
void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 1772611eb53..2bc4561b87a 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -455,6 +455,7 @@ if have_heimdal_support:
plantestsuite("samba4.blackbox.kinit_trust(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_kinit_trusts_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external", "arcfour-hmac-md5"])
plantestsuite("samba4.blackbox.export.keytab(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_export_keytab_heimdal.sh"), '$SERVER', '$USERNAME', '$REALM', '$DOMAIN', "$PREFIX", smbclient4])
plantestsuite("samba4.blackbox.kpasswd(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kpasswd_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', "$PREFIX/ad_dc_ntvfs"])
+ plantestsuite("samba4.blackbox.krb5.s4u", "fl2008r2dc:local", [os.path.join(bbdir, "test_s4u_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', configuration])
else:
plantestsuite("samba4.blackbox.kinit(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration])
plantestsuite("samba4.blackbox.kinit(fl2000dc:local)", "fl2000dc:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration])
diff --git a/source4/torture/drs/python/samba_tool_drs.py b/source4/torture/drs/python/samba_tool_drs.py
index 76cc86f832e..988f1dc7a3c 100644
--- a/source4/torture/drs/python/samba_tool_drs.py
+++ b/source4/torture/drs/python/samba_tool_drs.py
@@ -210,6 +210,7 @@ class SambaToolDrsTests(drs_base.DrsBaseTestCase):
self._disable_inbound_repl(self.dnsname_dc1)
self._disable_inbound_repl(self.dnsname_dc2)
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1)
self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2)
# add an object with link on dc1
@@ -232,7 +233,7 @@ class SambaToolDrsTests(drs_base.DrsBaseTestCase):
(obj_1, link_1) = get_num_obj_links(out)
- self.assertEqual(obj_1, 2)
+ self.assertGreaterEqual(obj_1, 2)
self.assertEqual(link_1, 1)
# pull that change with --local into local db from dc2: shouldn't send link or object
diff --git a/testprogs/blackbox/test_s4u_heimdal.sh b/testprogs/blackbox/test_s4u_heimdal.sh
new file mode 100755
index 00000000000..0e12c7ec096
--- /dev/null
+++ b/testprogs/blackbox/test_s4u_heimdal.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+if [ $# -lt 5 ]; then
+cat <<EOF
+Usage: test_kinit.sh SERVER USERNAME PASSWORD REALM DOMAIN PREFIX
+EOF
+exit 1;
+fi
+
+SERVER=$1
+USERNAME=$2
+PASSWORD=$3
+REALM=$4
+DOMAIN=$5
+PREFIX=$6
+shift 6
+failed=0
+
+
+samba_tool="$VALGRIND $PYTHON $BINDIR/samba-tool"
+
+samba4kinit=kinit
+if test -x $BINDIR/samba4kinit; then
+ samba4kinit=$BINDIR/samba4kinit
+fi
+
+samba4kgetcred=kgetcred
+if test -x $BINDIR/samba4kgetcred; then
+ samba4kgetcred=$BINDIR/samba4kgetcred
+fi
+
+. `dirname $0`/subunit.sh
+. `dirname $0`/common_test_fns.inc
+
+ocache="$PREFIX/tmpoutcache"
+KRB5CCNAME_PATH="$PREFIX/tmpccache"
+KRB5CCNAME="FILE:$KRB5CCNAME_PATH"
+export KRB5CCNAME
+rm -rf $KRB5CCNAME_PATH
+
+princ=test_impersonate_princ
+impersonator=test_impersonator
+target="CIFS/$SERVER.$REALM"
+
+
+testit "add impersonator principal" $samba_tool user add $impersonator $PASSWORD || failed=`expr $failed + 1`
+testit "become a service" $samba_tool spn add "HOST/$impersonator" $impersonator || failed=`expr $failed + 1`
+
+testit "set TrustedToAuthForDelegation" $samba_tool delegation for-any-protocol $impersonator on || failed=`expr $failed + 1`
+testit "add msDS-AllowedToDelegateTo" $samba_tool delegation add-service $impersonator $target || failed=`expr $failed + 1`
+
+testit "add a new principal" $samba_tool user add $princ --random-password || failed=`expr $failed + 1`
+testit "set not-delegated flag" $samba_tool user sensitive $princ on || failed=`expr $failed + 1`
+
+
+echo $PASSWORD > $PREFIX/tmppassfile
+testit "kinit with password" $samba4kinit -f --password-file=$PREFIX/tmppassfile $impersonator || failed=`expr $failed + 1`
+
+testit "test S4U2Self with normal user" $samba4kgetcred --out-cache=$ocache --forwardable --impersonate=${USERNAME} $impersonator || failed=`expr $failed + 1`
+testit "test S4U2Proxy with normal user" $samba4kgetcred --out-cache=$ocache --delegation-credential-cache=${ocache} $target || failed=`expr $failed + 1`
+
+testit "test S4U2Self with sensitive user" $samba4kgetcred --out-cache=$ocache --forwardable --impersonate=$princ $impersonator || failed=`expr $failed + 1`
+testit_expect_failure "test S4U2Proxy with sensitive user" $samba4kgetcred --out-cache=$ocache --delegation-credential-cache=${ocache} $target || failed=`expr $failed + 1`
+
+rm -f $ocache
+testit "unset not-delegated flag" $samba_tool user sensitive $princ off || failed=`expr $failed + 1`
+
+testit "test S4U2Self after unsetting ND flag" $samba4kgetcred --out-cache=$ocache --forwardable --impersonate=$princ $impersonator || failed=`expr $failed + 1`
+testit "test S4U2Proxy after unsetting ND flag" $samba4kgetcred --out-cache=$ocache --delegation-credential-cache=${ocache} $target || failed=`expr $failed + 1`
+
+
+rm -f $ocache $PREFIX/tmpccache tmppassfile
+exit $failed