Blob Blame History Raw
From 9aa816f5017bd38cbb9af2af5a7c385647e4f76d Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab@samba.org>
Date: Tue, 7 Jan 2020 19:25:53 +0200
Subject: [PATCH 01/45] s3-rpcserver: fix security level check for
 DsRGetForestTrustInformation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Harmonize _netr_DsRGetForestTrustInformation with source4/ logic which
didn't change since DCE RPC channel refactoring.

With the current code we return RPC faul as can be seen in the logs:

2019/12/11 17:12:55.463081,  1, pid=20939, effective(1284200000, 1284200000), real(1284200000, 0), class=rpc_parse] ../librpc/ndr/ndr.c:471(ndr_print_function_debug)
       netr_DsRGetForestTrustInformation: struct netr_DsRGetForestTrustInformation
          in: struct netr_DsRGetForestTrustInformation
              server_name              : *
                  server_name              : '\\some-dc.example.com'
              trusted_domain_name      : NULL
              flags                    : 0x00000000 (0)
[2019/12/11 17:12:55.463122,  4, pid=20939, effective(1284200000, 1284200000), real(1284200000, 0), class=rpc_srv] ../source3/rpc_server/srv_pipe.c:1561(api_rpcTNP)
  api_rpcTNP: fault(5) return.

This is due to this check in processing a request:
        if (!(p->pipe_bound && (p->auth.auth_type != DCERPC_AUTH_TYPE_NONE)
                       && (p->auth.auth_level != DCERPC_AUTH_LEVEL_NONE))) {
                p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
                return WERR_ACCESS_DENIED;
        }

and since we get AuthZ response,

  Successful AuthZ: [netlogon,ncacn_np] user [EXAMPLE]\[admin] [S-1-5-21-1234567-890123456-500] at [Wed, 11 Dec 2019 17:12:55.461164 UTC]
  Remote host [ipv4:Y.Y.Y.Y:59017] local host [ipv4:X.X.X.X:445]
[2019/12/11 17:12:55.461584,  4, pid=20939, effective(0, 0), real(0, 0)] ../lib/audit_logging/audit_logging.c:141(audit_log_json)
  JSON Authorization: {"timestamp": "2019-12-11T17:12:55.461491+0000",
   "type": "Authorization", "Authorization": {"version": {"major": 1, "minor": 1},
   "localAddress": "ipv4:X.X.X.X:445", "remoteAddress": "ipv4:Y.Y.Y.Y:59017",
   "serviceDescription": "netlogon", "authType": "ncacn_np",
   "domain": "EXAMPLE", "account": "admin", "sid": "S-1-5-21-1234567-890123456-500",
   "sessionId": "c5a2386f-f2cc-4241-9a9e-d104cf5859d5", "logonServer": "SOME-DC",
   "transportProtection": "SMB", "accountFlags": "0x00000010"}}

this means we are actually getting anonymous DCE/RPC access to netlogon
on top of authenticated SMB connection. In such case we have exactly
auth_type set to DCERPC_AUTH_TYPE_NONE and auth_level set to
DCERPC_AUTH_LEVEL_NONE in the pipe->auth. Thus, returning an error.

Update the code to follow the same security level check as in s4 variant
of the call.

Signed-off-by: Alexander Bokovoy <ab@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>

Autobuild-User(master): Günther Deschner <gd@samba.org>
Autobuild-Date(master): Mon Jan 13 15:05:28 UTC 2020 on sn-devel-184

(cherry picked from commit c6d880a115095c336b8b74f45854a99abb1bbb87)
---
 source3/rpc_server/netlogon/srv_netlog_nt.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index d799ba4feef..87613b99fde 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -2425,10 +2425,10 @@ WERROR _netr_DsRGetForestTrustInformation(struct pipes_struct *p,
 {
 	NTSTATUS status;
 	struct lsa_ForestTrustInformation *info, **info_ptr;
+	enum security_user_level security_level;
 
-	if (!(p->pipe_bound && (p->auth.auth_type != DCERPC_AUTH_TYPE_NONE)
-		       && (p->auth.auth_level != DCERPC_AUTH_LEVEL_NONE))) {
-		p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
+	security_level = security_session_user_level(p->session_info, NULL);
+	if (security_level < SECURITY_USER) {
 		return WERR_ACCESS_DENIED;
 	}
 
-- 
2.29.2


From e71fddb9ad5275a222d96bdcee06571a9a8c73c8 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Wed, 27 May 2020 16:50:45 +0200
Subject: [PATCH 02/45] Add a test to check dNSHostName with netbios aliases

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396

Signed-off-by: Isaac Boukris <iboukris@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 selftest/knownfail.d/nb_alias_dnshostname |  2 ++
 testprogs/blackbox/test_net_ads.sh        | 14 ++++++++++++++
 2 files changed, 16 insertions(+)
 create mode 100644 selftest/knownfail.d/nb_alias_dnshostname

diff --git a/selftest/knownfail.d/nb_alias_dnshostname b/selftest/knownfail.d/nb_alias_dnshostname
new file mode 100644
index 00000000000..3c14e9931b9
--- /dev/null
+++ b/selftest/knownfail.d/nb_alias_dnshostname
@@ -0,0 +1,2 @@
+^samba4.blackbox.net_ads.nb_alias check dNSHostName
+^samba4.blackbox.net_ads.nb_alias check main SPN
diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh
index 95c0cf76f90..6073ea972f9 100755
--- a/testprogs/blackbox/test_net_ads.sh
+++ b/testprogs/blackbox/test_net_ads.sh
@@ -220,6 +220,20 @@ testit_grep "dns alias addl" $dns_alias2 $VALGRIND $net_tool ads search -P samac
 ##Goodbye...
 testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
 
+# netbios aliases tests
+testit "join nb_alias" $VALGRIND $net_tool --option=netbiosaliases=nb_alias1,nb_alias2 ads join -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
+
+testit "testjoin nb_alias" $VALGRIND $net_tool ads testjoin || failed=`expr $failed + 1`
+
+testit_grep "nb_alias check dNSHostName" $fqdn $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ dNSHostName || failed=`expr $failed + 1`
+testit_grep "nb_alias check main SPN" ${uc_netbios}.${lc_realm} $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ servicePrincipalName || failed=`expr $failed + 1`
+
+testit_grep "nb_alias1 SPN" nb_alias1 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ servicePrincipalName || failed=`expr $failed + 1`
+testit_grep "nb_alias2 SPN" nb_alias2 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ servicePrincipalName || failed=`expr $failed + 1`
+
+##Goodbye...
+testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
+
 #
 # Test createcomputer option of 'net ads join'
 #
-- 
2.29.2


From e80e373485818eb7faebf5c9aae10d82fbc4e2e2 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Wed, 27 May 2020 15:52:46 +0200
Subject: [PATCH 03/45] Fix accidental overwrite of dnsHostName by the last
 netbios alias

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396

Signed-off-by: Isaac Boukris <iboukris@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 selftest/knownfail.d/nb_alias_dnshostname | 2 --
 source3/libnet/libnet_join.c              | 5 +++--
 2 files changed, 3 insertions(+), 4 deletions(-)
 delete mode 100644 selftest/knownfail.d/nb_alias_dnshostname

diff --git a/selftest/knownfail.d/nb_alias_dnshostname b/selftest/knownfail.d/nb_alias_dnshostname
deleted file mode 100644
index 3c14e9931b9..00000000000
--- a/selftest/knownfail.d/nb_alias_dnshostname
+++ /dev/null
@@ -1,2 +0,0 @@
-^samba4.blackbox.net_ads.nb_alias check dNSHostName
-^samba4.blackbox.net_ads.nb_alias check main SPN
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 9d4f656ffec..a31011b0ff8 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -507,6 +507,7 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
 	ADS_STATUS status;
 	ADS_MODLIST mods;
 	fstring my_fqdn;
+	fstring my_alias;
 	const char **spn_array = NULL;
 	size_t num_spns = 0;
 	char *spn = NULL;
@@ -587,11 +588,11 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
 		/*
 		 * Add HOST/netbiosname.domainname
 		 */
-		fstr_sprintf(my_fqdn, "%s.%s",
+		fstr_sprintf(my_alias, "%s.%s",
 			     *netbios_aliases,
 			     lp_dnsdomain());
 
-		spn = talloc_asprintf(frame, "HOST/%s", my_fqdn);
+		spn = talloc_asprintf(frame, "HOST/%s", my_alias);
 		if (spn == NULL) {
 			status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
 			goto done;
-- 
2.29.2


From 7ca5f9b2956ec41777837a7e14800a4345505ed6 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Thu, 24 Oct 2019 19:04:51 +0300
Subject: [PATCH 04/45] Refactor ads_keytab_add_entry() to make it iterable

so we can more easily add msDS-AdditionalDnsHostName entries.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396

Signed-off-by: Isaac Boukris <iboukris@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 source3/libads/kerberos_keytab.c | 197 +++++++++++++++++--------------
 1 file changed, 107 insertions(+), 90 deletions(-)

diff --git a/source3/libads/kerberos_keytab.c b/source3/libads/kerberos_keytab.c
index 97d5535041c..0f450a09df5 100644
--- a/source3/libads/kerberos_keytab.c
+++ b/source3/libads/kerberos_keytab.c
@@ -228,18 +228,16 @@ out:
 	return ok;
 }
 
-/**********************************************************************
- Adds a single service principal, i.e. 'host' to the system keytab
-***********************************************************************/
-
-int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
+static int add_kt_entry_etypes(krb5_context context, TALLOC_CTX *tmpctx,
+			       ADS_STRUCT *ads, const char *salt_princ_s,
+			       krb5_keytab keytab, krb5_kvno kvno,
+			       const char *srvPrinc, const char *my_fqdn,
+			       krb5_data *password, bool update_ads)
 {
 	krb5_error_code ret = 0;
-	krb5_context context = NULL;
-	krb5_keytab keytab = NULL;
-	krb5_data password;
-	krb5_kvno kvno;
-        krb5_enctype enctypes[6] = {
+	char *princ_s = NULL;
+	char *short_princ_s = NULL;
+	krb5_enctype enctypes[6] = {
 		ENCTYPE_DES_CBC_CRC,
 		ENCTYPE_DES_CBC_MD5,
 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
@@ -251,65 +249,7 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
 		ENCTYPE_ARCFOUR_HMAC,
 		0
 	};
-	char *princ_s = NULL;
-	char *short_princ_s = NULL;
-	char *salt_princ_s = NULL;
-	char *password_s = NULL;
-	char *my_fqdn;
-	TALLOC_CTX *tmpctx = NULL;
-	int i;
-
-	ret = smb_krb5_init_context_common(&context);
-	if (ret) {
-		DBG_ERR("kerberos init context failed (%s)\n",
-			error_message(ret));
-		return -1;
-	}
-
-	ret = ads_keytab_open(context, &keytab);
-	if (ret != 0) {
-		goto out;
-	}
-
-	/* retrieve the password */
-	if (!secrets_init()) {
-		DEBUG(1, (__location__ ": secrets_init failed\n"));
-		ret = -1;
-		goto out;
-	}
-	password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
-	if (!password_s) {
-		DEBUG(1, (__location__ ": failed to fetch machine password\n"));
-		ret = -1;
-		goto out;
-	}
-	ZERO_STRUCT(password);
-	password.data = password_s;
-	password.length = strlen(password_s);
-
-	/* we need the dNSHostName value here */
-	tmpctx = talloc_init(__location__);
-	if (!tmpctx) {
-		DEBUG(0, (__location__ ": talloc_init() failed!\n"));
-		ret = -1;
-		goto out;
-	}
-
-	my_fqdn = ads_get_dnshostname(ads, tmpctx, lp_netbios_name());
-	if (!my_fqdn) {
-		DEBUG(0, (__location__ ": unable to determine machine "
-			  "account's dns name in AD!\n"));
-		ret = -1;
-		goto out;
-	}
-
-	/* make sure we have a single instance of a the computer account */
-	if (!ads_has_samaccountname(ads, tmpctx, lp_netbios_name())) {
-		DEBUG(0, (__location__ ": unable to determine machine "
-			  "account's short name in AD!\n"));
-		ret = -1;
-		goto out;
-	}
+	size_t i;
 
 	/* Construct our principal */
 	if (strchr_m(srvPrinc, '@')) {
@@ -358,22 +298,6 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
 		}
 	}
 
-	kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
-	if (kvno == -1) {
-		/* -1 indicates failure, everything else is OK */
-		DEBUG(1, (__location__ ": ads_get_machine_kvno failed to "
-			 "determine the system's kvno.\n"));
-		ret = -1;
-		goto out;
-	}
-
-	salt_princ_s = kerberos_secrets_fetch_salt_princ();
-	if (salt_princ_s == NULL) {
-		DBG_WARNING("kerberos_secrets_fetch_salt_princ() failed\n");
-		ret = -1;
-		goto out;
-	}
-
 	for (i = 0; enctypes[i]; i++) {
 
 		/* add the fqdn principal to the keytab */
@@ -383,11 +307,11 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
 					    princ_s,
 					    salt_princ_s,
 					    enctypes[i],
-					    &password,
+					    password,
 					    false,
 					    false);
 		if (ret) {
-			DEBUG(1, (__location__ ": Failed to add entry to keytab\n"));
+			DBG_WARNING("Failed to add entry to keytab\n");
 			goto out;
 		}
 
@@ -399,16 +323,109 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
 						    short_princ_s,
 						    salt_princ_s,
 						    enctypes[i],
-						    &password,
+						    password,
 						    false,
 						    false);
 			if (ret) {
-				DEBUG(1, (__location__
-					  ": Failed to add short entry to keytab\n"));
+				DBG_WARNING("Failed to add short entry to keytab\n");
 				goto out;
 			}
 		}
 	}
+out:
+	return ret;
+}
+
+/**********************************************************************
+ Adds a single service principal, i.e. 'host' to the system keytab
+***********************************************************************/
+
+int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
+{
+	krb5_error_code ret = 0;
+	krb5_context context = NULL;
+	krb5_keytab keytab = NULL;
+	krb5_data password;
+	krb5_kvno kvno;
+	char *salt_princ_s = NULL;
+	char *password_s = NULL;
+	char *my_fqdn;
+	TALLOC_CTX *tmpctx = NULL;
+
+	ret = smb_krb5_init_context_common(&context);
+	if (ret) {
+		DBG_ERR("kerberos init context failed (%s)\n",
+			error_message(ret));
+		return -1;
+	}
+
+	ret = ads_keytab_open(context, &keytab);
+	if (ret != 0) {
+		goto out;
+	}
+
+	/* retrieve the password */
+	if (!secrets_init()) {
+		DBG_WARNING("secrets_init failed\n");
+		ret = -1;
+		goto out;
+	}
+	password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+	if (!password_s) {
+		DBG_WARNING("failed to fetch machine password\n");
+		ret = -1;
+		goto out;
+	}
+	ZERO_STRUCT(password);
+	password.data = password_s;
+	password.length = strlen(password_s);
+
+	/* we need the dNSHostName value here */
+	tmpctx = talloc_init(__location__);
+	if (!tmpctx) {
+		DBG_ERR("talloc_init() failed!\n");
+		ret = -1;
+		goto out;
+	}
+
+	my_fqdn = ads_get_dnshostname(ads, tmpctx, lp_netbios_name());
+	if (!my_fqdn) {
+		DBG_ERR("unable to determine machine account's dns name in "
+			"AD!\n");
+		ret = -1;
+		goto out;
+	}
+
+	/* make sure we have a single instance of a the computer account */
+	if (!ads_has_samaccountname(ads, tmpctx, lp_netbios_name())) {
+		DBG_ERR("unable to determine machine account's short name in "
+			"AD!\n");
+		ret = -1;
+		goto out;
+	}
+
+	kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
+	if (kvno == -1) {
+		/* -1 indicates failure, everything else is OK */
+		DBG_WARNING("ads_get_machine_kvno failed to determine the "
+			    "system's kvno.\n");
+		ret = -1;
+		goto out;
+	}
+
+	salt_princ_s = kerberos_secrets_fetch_salt_princ();
+	if (salt_princ_s == NULL) {
+		DBG_WARNING("kerberos_secrets_fetch_salt_princ() failed\n");
+		ret = -1;
+		goto out;
+	}
+
+	ret = add_kt_entry_etypes(context, tmpctx, ads, salt_princ_s, keytab,
+				  kvno, srvPrinc, my_fqdn, &password,
+				  update_ads);
+	if (ret != 0) {
+		goto out;
+	}
 
 out:
 	SAFE_FREE(salt_princ_s);
-- 
2.29.2


From 087d6dd4c4f25860643ab5920a1b2c0c70e5551b Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Wed, 27 May 2020 17:55:12 +0200
Subject: [PATCH 05/45] Add a test for msDS-AdditionalDnsHostName entries in
 keytab

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396

Signed-off-by: Isaac Boukris <iboukris@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 selftest/knownfail.d/dns_alias_keytab | 2 ++
 testprogs/blackbox/test_net_ads.sh    | 9 +++++++++
 2 files changed, 11 insertions(+)
 create mode 100644 selftest/knownfail.d/dns_alias_keytab

diff --git a/selftest/knownfail.d/dns_alias_keytab b/selftest/knownfail.d/dns_alias_keytab
new file mode 100644
index 00000000000..216592e1210
--- /dev/null
+++ b/selftest/knownfail.d/dns_alias_keytab
@@ -0,0 +1,2 @@
+^samba4.blackbox.net_ads.dns alias1 check keytab
+^samba4.blackbox.net_ads.dns alias2 check keytab
diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh
index 6073ea972f9..a40b477a173 100755
--- a/testprogs/blackbox/test_net_ads.sh
+++ b/testprogs/blackbox/test_net_ads.sh
@@ -217,6 +217,15 @@ testit_grep "dns alias SPN" $dns_alias2 $VALGRIND $net_tool ads search -P samacc
 testit_grep "dns alias addl" $dns_alias1 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ msDS-AdditionalDnsHostName || failed=`expr $failed + 1`
 testit_grep "dns alias addl" $dns_alias2 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ msDS-AdditionalDnsHostName || failed=`expr $failed + 1`
 
+dedicated_keytab_file="$PREFIX_ABS/test_dns_aliases_dedicated_krb5.keytab"
+
+testit "dns alias create_keytab" $VALGRIND $net_tool ads keytab create --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
+
+testit_grep "dns alias1 check keytab" "host/${dns_alias1}@$REALM" $net_tool ads keytab list --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
+testit_grep "dns alias2 check keytab" "host/${dns_alias2}@$REALM" $net_tool ads keytab list --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
+
+rm -f $dedicated_keytab_file
+
 ##Goodbye...
 testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
 
-- 
2.29.2


From 1ae32dddad89cdb75ae2c8fb3e7378ce6f5ad6af Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Wed, 27 May 2020 15:36:28 +0200
Subject: [PATCH 06/45] Add msDS-AdditionalDnsHostName entries to the keytab

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396

Signed-off-by: Isaac Boukris <iboukris@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
---
 selftest/knownfail.d/dns_alias_keytab |  2 --
 source3/libads/ads_proto.h            |  5 +++
 source3/libads/kerberos_keytab.c      | 21 +++++++++++++
 source3/libads/ldap.c                 | 45 +++++++++++++++++++++++++++
 4 files changed, 71 insertions(+), 2 deletions(-)
 delete mode 100644 selftest/knownfail.d/dns_alias_keytab

diff --git a/selftest/knownfail.d/dns_alias_keytab b/selftest/knownfail.d/dns_alias_keytab
deleted file mode 100644
index 216592e1210..00000000000
--- a/selftest/knownfail.d/dns_alias_keytab
+++ /dev/null
@@ -1,2 +0,0 @@
-^samba4.blackbox.net_ads.dns alias1 check keytab
-^samba4.blackbox.net_ads.dns alias2 check keytab
diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h
index 495ef5d3325..cd9c1082681 100644
--- a/source3/libads/ads_proto.h
+++ b/source3/libads/ads_proto.h
@@ -137,6 +137,11 @@ ADS_STATUS ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx,
 					enum ads_extended_dn_flags flags,
 					struct dom_sid *sid);
 char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
+ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx,
+                                            ADS_STRUCT *ads,
+                                            const char *machine_name,
+                                            char ***hostnames_array,
+                                            size_t *num_hostnames);
 char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
 bool ads_has_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name );
 ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name,
diff --git a/source3/libads/kerberos_keytab.c b/source3/libads/kerberos_keytab.c
index 0f450a09df5..818ec884a03 100644
--- a/source3/libads/kerberos_keytab.c
+++ b/source3/libads/kerberos_keytab.c
@@ -351,6 +351,8 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
 	char *password_s = NULL;
 	char *my_fqdn;
 	TALLOC_CTX *tmpctx = NULL;
+	char **hostnames_array = NULL;
+	size_t num_hostnames = 0;
 
 	ret = smb_krb5_init_context_common(&context);
 	if (ret) {
@@ -427,6 +429,25 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
 		goto out;
 	}
 
+	if (ADS_ERR_OK(ads_get_additional_dns_hostnames(tmpctx, ads,
+							lp_netbios_name(),
+							&hostnames_array,
+							&num_hostnames))) {
+		size_t i;
+
+		for (i = 0; i < num_hostnames; i++) {
+
+			ret = add_kt_entry_etypes(context, tmpctx, ads,
+						  salt_princ_s, keytab,
+						  kvno, srvPrinc,
+						  hostnames_array[i],
+						  &password, update_ads);
+			if (ret != 0) {
+				goto out;
+			}
+		}
+	}
+
 out:
 	SAFE_FREE(salt_princ_s);
 	TALLOC_FREE(tmpctx);
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index db2b72ab1b5..02a628ee0e6 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -1377,6 +1377,7 @@ char *ads_parent_dn(const char *dn)
 		"unicodePwd",
 
 		/* Additional attributes Samba checks */
+		"msDS-AdditionalDnsHostName",
 		"msDS-SupportedEncryptionTypes",
 		"nTSecurityDescriptor",
 
@@ -3663,6 +3664,50 @@ out:
 /********************************************************************
 ********************************************************************/
 
+ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx,
+					    ADS_STRUCT *ads,
+					    const char *machine_name,
+					    char ***hostnames_array,
+					    size_t *num_hostnames)
+{
+	ADS_STATUS status;
+	LDAPMessage *res = NULL;
+	int count;
+
+	status = ads_find_machine_acct(ads,
+				       &res,
+				       machine_name);
+	if (!ADS_ERR_OK(status)) {
+		DEBUG(1,("Host Account for %s not found... skipping operation.\n",
+			 machine_name));
+		return status;
+	}
+
+	count = ads_count_replies(ads, res);
+	if (count != 1) {
+		status = ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+		goto done;
+	}
+
+	*hostnames_array = ads_pull_strings(ads, mem_ctx, res,
+					    "msDS-AdditionalDnsHostName",
+					    num_hostnames);
+	if (*hostnames_array == NULL) {
+		DEBUG(1, ("Host account for %s does not have msDS-AdditionalDnsHostName.\n",
+			  machine_name));
+		status = ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+		goto done;
+	}
+
+done:
+	ads_msgfree(ads, res);
+
+	return status;
+}
+
+/********************************************************************
+********************************************************************/
+
 char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
 {
 	LDAPMessage *res = NULL;
-- 
2.29.2


From 939b9265a533393189ef3c513e77b2cb009a51d5 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Wed, 27 May 2020 15:54:12 +0200
Subject: [PATCH 07/45] Add net-ads-join dnshostname=fqdn option

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396

Signed-off-by: Isaac Boukris <iboukris@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>

Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org>
Autobuild-Date(master): Fri May 29 13:33:28 UTC 2020 on sn-devel-184
---
 docs-xml/manpages/net.8.xml        |  7 ++++++-
 source3/libnet/libnet_join.c       |  7 ++++++-
 source3/librpc/idl/libnet_join.idl |  1 +
 source3/utils/net_ads.c            |  9 ++++++++-
 testprogs/blackbox/test_net_ads.sh | 15 +++++++++++++++
 5 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/docs-xml/manpages/net.8.xml b/docs-xml/manpages/net.8.xml
index 37dfa2af694..69e18df8b6c 100644
--- a/docs-xml/manpages/net.8.xml
+++ b/docs-xml/manpages/net.8.xml
@@ -454,7 +454,7 @@ The remote server must be specified with the -S option.
 
 <refsect2>
 <title>[RPC|ADS] JOIN [TYPE] [--no-dns-updates] [-U username[%password]]
-[createupn=UPN] [createcomputer=OU] [machinepass=PASS]
+[dnshostname=FQDN] [createupn=UPN] [createcomputer=OU] [machinepass=PASS]
 [osName=string osVer=string] [options]</title>
 
 <para>
@@ -469,6 +469,11 @@ be created.</para>
 joining the domain.
 </para>
 
+<para>
+[FQDN] (ADS only) set the dnsHosName attribute during the join.
+The default format is netbiosname.dnsdomain.
+</para>
+
 <para>
 [UPN] (ADS only) set the principalname attribute during the join.  The default
 format is host/netbiosname@REALM.
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index a31011b0ff8..de558be4f91 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -546,7 +546,12 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
 		goto done;
 	}
 
-	fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name, lp_dnsdomain());
+	if (r->in.dnshostname != NULL) {
+		fstr_sprintf(my_fqdn, "%s", r->in.dnshostname);
+	} else {
+		fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
+			     lp_dnsdomain());
+	}
 
 	if (!strlower_m(my_fqdn)) {
 		status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
diff --git a/source3/librpc/idl/libnet_join.idl b/source3/librpc/idl/libnet_join.idl
index e45034d40da..03d919863b5 100644
--- a/source3/librpc/idl/libnet_join.idl
+++ b/source3/librpc/idl/libnet_join.idl
@@ -37,6 +37,7 @@ interface libnetjoin
 		[in] string os_servicepack,
 		[in] boolean8 create_upn,
 		[in] string upn,
+		[in] string dnshostname,
 		[in] boolean8 modify_config,
 		[in,unique] ads_struct *ads,
 		[in] boolean8 debug,
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index 07a22098fb1..3cf8fbbf7c8 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -1710,6 +1710,8 @@ static int net_ads_join_usage(struct net_context *c, int argc, const char **argv
 {
 	d_printf(_("net ads join [--no-dns-updates] [options]\n"
 	           "Valid options:\n"));
+	d_printf(_("   dnshostname=FQDN      Set the dnsHostName attribute during the join.\n"
+		   "                         The default is in the form netbiosname.dnsdomain\n"));
 	d_printf(_("   createupn[=UPN]       Set the userPrincipalName attribute during the join.\n"
 		   "                         The default UPN is in the form host/netbiosname@REALM.\n"));
 	d_printf(_("   createcomputer=OU     Precreate the computer account in a specific OU.\n"
@@ -1830,6 +1832,7 @@ int net_ads_join(struct net_context *c, int argc, const char **argv)
 	const char *domain = lp_realm();
 	WERROR werr = WERR_NERR_SETUPNOTJOINED;
 	bool createupn = false;
+	const char *dnshostname = NULL;
 	const char *machineupn = NULL;
 	const char *machine_password = NULL;
 	const char *create_in_ou = NULL;
@@ -1870,7 +1873,10 @@ int net_ads_join(struct net_context *c, int argc, const char **argv)
 	/* process additional command line args */
 
 	for ( i=0; i<argc; i++ ) {
-		if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
+		if ( !strncasecmp_m(argv[i], "dnshostname", strlen("dnshostname")) ) {
+			dnshostname = get_string_param(argv[i]);
+		}
+		else if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
 			createupn = true;
 			machineupn = get_string_param(argv[i]);
 		}
@@ -1938,6 +1944,7 @@ int net_ads_join(struct net_context *c, int argc, const char **argv)
 	r->in.domain_name_type	= domain_name_type;
 	r->in.create_upn	= createupn;
 	r->in.upn		= machineupn;
+	r->in.dnshostname	= dnshostname;
 	r->in.account_ou	= create_in_ou;
 	r->in.os_name		= os_name;
 	r->in.os_version	= os_version;
diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh
index a40b477a173..85257f445d8 100755
--- a/testprogs/blackbox/test_net_ads.sh
+++ b/testprogs/blackbox/test_net_ads.sh
@@ -277,6 +277,21 @@ rm -f $dedicated_keytab_file
 
 testit "leave+createupn" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
 
+#
+# Test dnshostname option of 'net ads join'
+#
+testit "join+dnshostname" $VALGRIND $net_tool ads join -U$DC_USERNAME%$DC_PASSWORD dnshostname="alt.hostname.$HOSTNAME" || failed=`expr $failed + 1`
+
+testit_grep "check dnshostname opt" "dNSHostName: alt.hostname.$HOSTNAME" $ldbsearch -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER.$REALM -s base -b "CN=$HOSTNAME,CN=Computers,$base_dn" || failed=`expr $failed + 1`
+
+testit "create_keytab+dnshostname" $VALGRIND $net_tool ads keytab create --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
+
+testit_grep "check dnshostname+keytab" "host/alt.hostname.$HOSTNAME@$REALM" $net_tool ads keytab list --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
+
+rm -f $dedicated_keytab_file
+
+testit "leave+dnshostname" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
+
 rm -rf $BASEDIR/$WORKDIR
 
 exit $failed
-- 
2.29.2


From 25a6679a5260dafde7a7d2aed9bfe43eaf083b1c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Sep 2020 16:04:57 +0200
Subject: [PATCH 08/45] CVE-2020-1472(ZeroLogon): libcli/auth: add
 netlogon_creds_random_challenge()

It's good to have just a single isolated function that will generate
random challenges, in future we can add some logic in order to
avoid weak values, which are likely to be rejected by a server.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 libcli/auth/credentials.c | 8 ++++++++
 libcli/auth/proto.h       | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c
index b6c8ba281ba..dbbef9e7a3c 100644
--- a/libcli/auth/credentials.c
+++ b/libcli/auth/credentials.c
@@ -26,9 +26,17 @@
 #include "libcli/auth/libcli_auth.h"
 #include "../libcli/security/dom_sid.h"
 
+
+void netlogon_creds_random_challenge(struct netr_Credential *challenge)
+{
+	ZERO_STRUCTP(challenge);
+	generate_random_buffer(challenge->data, sizeof(challenge->data));
+}
+
 static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
 				      const struct netr_Credential *in,
 				      struct netr_Credential *out)
+
 {
 	if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
 		AES_KEY key;
diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h
index 82febe74440..82797d453ed 100644
--- a/libcli/auth/proto.h
+++ b/libcli/auth/proto.h
@@ -11,6 +11,8 @@
 
 /* The following definitions come from /home/jeremy/src/samba/git/master/source3/../source4/../libcli/auth/credentials.c  */
 
+void netlogon_creds_random_challenge(struct netr_Credential *challenge);
+
 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key);
 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key);
 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass);
-- 
2.29.2


From 1e8ad7efe35d8b79fef387ff709d6a499565c39a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Sep 2020 16:07:30 +0200
Subject: [PATCH 09/45] CVE-2020-1472(ZeroLogon): s4:torture/rpc: make use of
 netlogon_creds_random_challenge()

This will avoid getting flakey tests once our server starts to
reject weak challenges.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source4/torture/rpc/lsa.c      |  2 +-
 source4/torture/rpc/netlogon.c | 34 ++++++++++++----------------------
 2 files changed, 13 insertions(+), 23 deletions(-)

diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c
index 21cc16afbaf..7bdc0cf679a 100644
--- a/source4/torture/rpc/lsa.c
+++ b/source4/torture/rpc/lsa.c
@@ -2847,7 +2847,7 @@ static bool check_pw_with_ServerAuthenticate3(struct dcerpc_pipe *p,
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
 		"ServerReqChallenge failed");
diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
index 026d86d50e4..e11014922f8 100644
--- a/source4/torture/rpc/netlogon.c
+++ b/source4/torture/rpc/netlogon.c
@@ -160,7 +160,7 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx,
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
 		"ServerReqChallenge failed");
@@ -229,7 +229,7 @@ bool test_SetupCredentials2ex(struct dcerpc_pipe *p, struct torture_context *tct
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
 		"ServerReqChallenge failed");
@@ -318,7 +318,7 @@ bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx,
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
 		"ServerReqChallenge failed");
@@ -390,7 +390,7 @@ bool test_SetupCredentialsDowngrade(struct torture_context *tctx,
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
 		"ServerReqChallenge failed");
@@ -1278,7 +1278,7 @@ static bool test_ServerReqChallengeGlobal(struct torture_context *tctx,
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
 		"ServerReqChallenge failed on b1");
@@ -1367,7 +1367,7 @@ static bool test_ServerReqChallengeReuseGlobal(struct torture_context *tctx,
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
 		"ServerReqChallenge failed on b1");
@@ -1456,7 +1456,7 @@ static bool test_ServerReqChallengeReuseGlobal2(struct torture_context *tctx,
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
 		"ServerReqChallenge failed on b1");
@@ -1546,7 +1546,7 @@ static bool test_ServerReqChallengeReuseGlobal3(struct torture_context *tctx,
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
 		"ServerReqChallenge failed on b1");
@@ -1638,8 +1638,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx,
 	r.in.credentials = &credentials1_random;
 	r.out.return_credentials = &credentials_discard;
 
-	generate_random_buffer(credentials1_random.data,
-			       sizeof(credentials1_random.data));
+	netlogon_creds_random_challenge(&credentials1_random);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
 		"ServerReqChallenge failed on b1");
@@ -1651,7 +1650,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx,
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
 		"ServerReqChallenge failed on b1");
@@ -1662,16 +1661,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx,
 	r.in.credentials = &credentials1_random;
 	r.out.return_credentials = &credentials_discard;
 
-	generate_random_buffer(credentials1_random.data,
-			       sizeof(credentials1_random.data));
-
-	r.in.server_name = NULL;
-	r.in.computer_name = "CHALTEST3";
-	r.in.credentials = &credentials1_random;
-	r.out.return_credentials = &credentials_discard;
-
-	generate_random_buffer(credentials1_random.data,
-			       sizeof(credentials1_random.data));
+	netlogon_creds_random_challenge(&credentials1_random);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
 		"ServerReqChallenge failed on b1");
@@ -1747,7 +1737,7 @@ static bool test_ServerReqChallengeReuse(struct torture_context *tctx,
 	r.in.credentials = &credentials1;
 	r.out.return_credentials = &credentials2;
 
-	generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+	netlogon_creds_random_challenge(&credentials1);
 
 	torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
 		"ServerReqChallenge");
-- 
2.29.2


From 74ee204ad4647d0d7a2097124652cbcd43406c7d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Sep 2020 16:08:38 +0200
Subject: [PATCH 10/45] CVE-2020-1472(ZeroLogon): libcli/auth: make use of
 netlogon_creds_random_challenge() in netlogon_creds_cli.c

This will avoid getting rejected by the server if we generate
a weak challenge.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 817d2cd041a..0f6ca11ff96 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -1177,8 +1177,7 @@ static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
 
 	TALLOC_FREE(state->creds);
 
-	generate_random_buffer(state->client_challenge.data,
-			       sizeof(state->client_challenge.data));
+	netlogon_creds_random_challenge(&state->client_challenge);
 
 	subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
 						state->binding_handle,
-- 
2.29.2


From 10196846d019d0e2ccef51f32ddd39fc17ca60aa Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Sep 2020 16:10:53 +0200
Subject: [PATCH 11/45] CVE-2020-1472(ZeroLogon): s3:rpc_server:netlogon: make
 use of netlogon_creds_random_challenge()

This is not strictly needed, but makes things more clear.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source3/rpc_server/netlogon/srv_netlog_nt.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index 87613b99fde..86b2f343e82 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -840,8 +840,7 @@ NTSTATUS _netr_ServerReqChallenge(struct pipes_struct *p,
 
 	pipe_state->client_challenge = *r->in.credentials;
 
-	generate_random_buffer(pipe_state->server_challenge.data,
-			       sizeof(pipe_state->server_challenge.data));
+	netlogon_creds_random_challenge(&pipe_state->server_challenge);
 
 	*r->out.return_credentials = pipe_state->server_challenge;
 
-- 
2.29.2


From 215aca6d11b900ee3cf11568d27bce77e0567653 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Sep 2020 16:10:53 +0200
Subject: [PATCH 12/45] CVE-2020-1472(ZeroLogon): s4:rpc_server:netlogon: make
 use of netlogon_creds_random_challenge()

This is not strictly needed, but makes things more clear.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index 023adfd99e9..de260d8051d 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -90,8 +90,7 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal
 
 	pipe_state->client_challenge = *r->in.credentials;
 
-	generate_random_buffer(pipe_state->server_challenge.data,
-			       sizeof(pipe_state->server_challenge.data));
+	netlogon_creds_random_challenge(&pipe_state->server_challenge);
 
 	*r->out.return_credentials = pipe_state->server_challenge;
 
-- 
2.29.2


From 4551bf623426e8c543b287807d447feb69bb0f09 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Sep 2020 16:15:26 +0200
Subject: [PATCH 13/45] CVE-2020-1472(ZeroLogon): libcli/auth: add
 netlogon_creds_is_random_challenge() to avoid weak values

This is the check Windows is using, so we won't generate challenges,
which are rejected by Windows DCs (and future Samba DCs).

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 libcli/auth/credentials.c | 23 ++++++++++++++++++++++-
 libcli/auth/proto.h       |  1 +
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c
index dbbef9e7a3c..64b424c099f 100644
--- a/libcli/auth/credentials.c
+++ b/libcli/auth/credentials.c
@@ -27,10 +27,31 @@
 #include "../libcli/security/dom_sid.h"
 
 
+bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge)
+{
+	/*
+	 * If none of the first 5 bytes of the client challenge is unique, the
+	 * server MUST fail session-key negotiation without further processing
+	 * of the following steps.
+	 */
+
+	if (challenge->data[1] == challenge->data[0] &&
+	    challenge->data[2] == challenge->data[0] &&
+	    challenge->data[3] == challenge->data[0] &&
+	    challenge->data[4] == challenge->data[0])
+	{
+		return false;
+	}
+
+	return true;
+}
+
 void netlogon_creds_random_challenge(struct netr_Credential *challenge)
 {
 	ZERO_STRUCTP(challenge);
-	generate_random_buffer(challenge->data, sizeof(challenge->data));
+	while (!netlogon_creds_is_random_challenge(challenge)) {
+		generate_random_buffer(challenge->data, sizeof(challenge->data));
+	}
 }
 
 static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h
index 82797d453ed..ad768682b9f 100644
--- a/libcli/auth/proto.h
+++ b/libcli/auth/proto.h
@@ -11,6 +11,7 @@
 
 /* The following definitions come from /home/jeremy/src/samba/git/master/source3/../source4/../libcli/auth/credentials.c  */
 
+bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge);
 void netlogon_creds_random_challenge(struct netr_Credential *challenge);
 
 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key);
-- 
2.29.2


From f7e09421ace8fe60c0110770d909800d21ae6c8e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Sep 2020 16:17:29 +0200
Subject: [PATCH 14/45] CVE-2020-1472(ZeroLogon): libcli/auth: reject weak
 client challenges in netlogon_creds_server_init()

This implements the note from MS-NRPC 3.1.4.1 Session-Key Negotiation:

 7. If none of the first 5 bytes of the client challenge is unique, the
    server MUST fail session-key negotiation without further processing of
    the following steps.

It lets ./zerologon_tester.py from
https://github.com/SecuraBV/CVE-2020-1472.git
report: "Attack failed. Target is probably patched."

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>

[dbagnall@samba.org, abartlet@samba.org: wscript_build backport
differs because 4.10 has no gnutls dependency]
---
 libcli/auth/credentials.c | 16 ++++++++++++++++
 libcli/auth/wscript_build |  2 +-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c
index 64b424c099f..e2bc82809b7 100644
--- a/libcli/auth/credentials.c
+++ b/libcli/auth/credentials.c
@@ -25,6 +25,7 @@
 #include "../lib/crypto/crypto.h"
 #include "libcli/auth/libcli_auth.h"
 #include "../libcli/security/dom_sid.h"
+#include "lib/util/util_str_escape.h"
 
 
 bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge)
@@ -451,6 +452,7 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me
 {
 
 	struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+	bool ok;
 
 	if (!creds) {
 		return NULL;
@@ -463,6 +465,20 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me
 	dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
 	dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
 
+	ok = netlogon_creds_is_random_challenge(client_challenge);
+	if (!ok) {
+		DBG_WARNING("CVE-2020-1472(ZeroLogon): "
+			    "non-random client challenge rejected for "
+			    "client_account[%s] client_computer_name[%s]\n",
+			    log_escape(mem_ctx, client_account),
+			    log_escape(mem_ctx, client_computer_name));
+		dump_data(DBGLVL_WARNING,
+			  client_challenge->data,
+			  sizeof(client_challenge->data));
+		talloc_free(creds);
+		return NULL;
+	}
+
 	creds->computer_name = talloc_strdup(creds, client_computer_name);
 	if (!creds->computer_name) {
 		talloc_free(creds);
diff --git a/libcli/auth/wscript_build b/libcli/auth/wscript_build
index d319d9b879e..394505d166d 100644
--- a/libcli/auth/wscript_build
+++ b/libcli/auth/wscript_build
@@ -18,7 +18,7 @@ bld.SAMBA_SUBSYSTEM('NTLM_CHECK',
 
 bld.SAMBA_SUBSYSTEM('LIBCLI_AUTH',
 	source='credentials.c session.c smbencrypt.c smbdes.c',
-	public_deps='MSRPC_PARSE',
+	public_deps='MSRPC_PARSE util_str_escape',
 	public_headers='credentials.h:domain_credentials.h'
 	)
 
-- 
2.29.2


From 6bc86fb69bf50c89a334fd2dcbce6999a2360fb7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Sep 2020 19:20:25 +0200
Subject: [PATCH 15/45] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon:
 protect netr_ServerPasswordSet2 against unencrypted passwords

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 60 ++++++++++++++++++-
 1 file changed, 59 insertions(+), 1 deletion(-)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index de260d8051d..acbf077c6c7 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -722,7 +722,10 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal
 	struct NL_PASSWORD_VERSION version = {};
 	const uint32_t *new_version = NULL;
 	NTSTATUS nt_status;
-	DATA_BLOB new_password;
+	DATA_BLOB new_password = data_blob_null;
+	size_t confounder_len;
+	DATA_BLOB dec_blob = data_blob_null;
+	DATA_BLOB enc_blob = data_blob_null;
 	int ret;
 	struct samr_CryptPassword password_buf;
 
@@ -780,6 +783,61 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal
 		return NT_STATUS_WRONG_PASSWORD;
 	}
 
+	/*
+	 * Make sure the length field was encrypted,
+	 * otherwise we are under attack.
+	 */
+	if (new_password.length == r->in.new_password->length) {
+		DBG_WARNING("Length[%zu] field not encrypted\n",
+			    new_password.length);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
+	/*
+	 * We don't allow empty passwords for machine accounts.
+	 */
+	if (new_password.length < 2) {
+		DBG_WARNING("Empty password Length[%zu]\n",
+			    new_password.length);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
+	/*
+	 * Make sure the confounder part of CryptPassword
+	 * buffer was encrypted, otherwise we are under attack.
+	 */
+	confounder_len = 512 - new_password.length;
+	enc_blob = data_blob_const(r->in.new_password->data, confounder_len);
+	dec_blob = data_blob_const(password_buf.data, confounder_len);
+	if (data_blob_cmp(&dec_blob, &enc_blob) == 0) {
+		DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n",
+			    confounder_len);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
+	/*
+	 * Check that the password part was actually encrypted,
+	 * otherwise we are under attack.
+	 */
+	enc_blob = data_blob_const(r->in.new_password->data + confounder_len,
+				   new_password.length);
+	dec_blob = data_blob_const(password_buf.data + confounder_len,
+				   new_password.length);
+	if (data_blob_cmp(&dec_blob, &enc_blob) == 0) {
+		DBG_WARNING("Password buffer not encrypted Length[%zu]\n",
+			    new_password.length);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
+	/*
+	 * don't allow zero buffers
+	 */
+	if (all_zero(new_password.data, new_password.length)) {
+		DBG_WARNING("Password zero buffer Length[%zu]\n",
+			    new_password.length);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
 	/* fetch the old password hashes (at least one of both has to exist) */
 
 	ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs,
-- 
2.29.2


From 1f8dec1cbb37f3406d999425590f8a923586ccac Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 16 Sep 2020 12:53:50 -0700
Subject: [PATCH 16/45] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon:
 protect netr_ServerPasswordSet2 against unencrypted passwords

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Jeremy Allison <jra@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source3/rpc_server/netlogon/srv_netlog_nt.c | 98 +++++++++++++++++++--
 1 file changed, 92 insertions(+), 6 deletions(-)

diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index 86b2f343e82..fd9127b386f 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -1326,9 +1326,14 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p,
 {
 	NTSTATUS status;
 	struct netlogon_creds_CredentialState *creds = NULL;
-	DATA_BLOB plaintext;
+	DATA_BLOB plaintext = data_blob_null;
+	DATA_BLOB new_password = data_blob_null;
+	size_t confounder_len;
+	DATA_BLOB dec_blob = data_blob_null;
+	DATA_BLOB enc_blob = data_blob_null;
 	struct samr_CryptPassword password_buf;
 	struct _samr_Credentials_t cr = { CRED_TYPE_PLAIN_TEXT, {0}};
+	bool ok;
 
 	become_root();
 	status = netr_creds_server_step_check(p, p->mem_ctx,
@@ -1364,18 +1369,99 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p,
 		netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
 	}
 
-	if (!decode_pw_buffer(p->mem_ctx,
-			      password_buf.data,
-			      (char**) &plaintext.data,
-			      &plaintext.length,
-			      CH_UTF16)) {
+	if (!extract_pw_from_buffer(p->mem_ctx, password_buf.data, &new_password)) {
 		DEBUG(2,("_netr_ServerPasswordSet2: unable to extract password "
 			 "from a buffer. Rejecting auth request as a wrong password\n"));
 		TALLOC_FREE(creds);
 		return NT_STATUS_WRONG_PASSWORD;
 	}
 
+	/*
+	 * Make sure the length field was encrypted,
+	 * otherwise we are under attack.
+	 */
+	if (new_password.length == r->in.new_password->length) {
+		DBG_WARNING("Length[%zu] field not encrypted\n",
+			new_password.length);
+		TALLOC_FREE(creds);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
+	/*
+	 * We don't allow empty passwords for machine accounts.
+	 */
+	if (new_password.length < 2) {
+		DBG_WARNING("Empty password Length[%zu]\n",
+			new_password.length);
+		TALLOC_FREE(creds);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
+	/*
+	 * Make sure the confounder part of CryptPassword
+	 * buffer was encrypted, otherwise we are under attack.
+	 */
+	confounder_len = 512 - new_password.length;
+	enc_blob = data_blob_const(r->in.new_password->data, confounder_len);
+	dec_blob = data_blob_const(password_buf.data, confounder_len);
+	if (data_blob_cmp(&dec_blob, &enc_blob) == 0) {
+		DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n",
+			    confounder_len);
+		TALLOC_FREE(creds);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
+	/*
+	 * Check that the password part was actually encrypted,
+	 * otherwise we are under attack.
+	 */
+	enc_blob = data_blob_const(r->in.new_password->data + confounder_len,
+				   new_password.length);
+	dec_blob = data_blob_const(password_buf.data + confounder_len,
+				   new_password.length);
+	if (data_blob_cmp(&dec_blob, &enc_blob) == 0) {
+		DBG_WARNING("Password buffer not encrypted Length[%zu]\n",
+			    new_password.length);
+		TALLOC_FREE(creds);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
+	/*
+	 * don't allow zero buffers
+	 */
+	if (all_zero(new_password.data, new_password.length)) {
+		DBG_WARNING("Password zero buffer Length[%zu]\n",
+			    new_password.length);
+		TALLOC_FREE(creds);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
+	/* Convert from UTF16 -> plaintext. */
+	ok = convert_string_talloc(p->mem_ctx,
+				CH_UTF16,
+				CH_UNIX,
+				new_password.data,
+				new_password.length,
+				(void *)&plaintext.data,
+				&plaintext.length);
+	if (!ok) {
+		DBG_WARNING("unable to extract password from a buffer. "
+			    "Rejecting auth request as a wrong password\n");
+		TALLOC_FREE(creds);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
+	/*
+	 * We don't allow empty passwords for machine accounts.
+	 */
+
 	cr.creds.password = (const char*) plaintext.data;
+	if (strlen(cr.creds.password) == 0) {
+		DBG_WARNING("Empty plaintext password\n");
+		TALLOC_FREE(creds);
+		return NT_STATUS_WRONG_PASSWORD;
+	}
+
 	status = netr_set_machine_account_password(p->mem_ctx,
 						   p->session_info,
 						   p->msg_ctx,
-- 
2.29.2


From 2ad269be74481789ded62a3dcb538709c6d6e291 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Sep 2020 10:18:45 +0200
Subject: [PATCH 17/45] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon:
 refactor dcesrv_netr_creds_server_step_check()

We should debug more details about the failing request.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 45 ++++++++++++++-----
 1 file changed, 33 insertions(+), 12 deletions(-)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index acbf077c6c7..b4326a4ecaa 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -623,26 +623,47 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
 	NTSTATUS nt_status;
 	int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx);
 	bool schannel_global_required = (schannel == true);
+	struct netlogon_creds_CredentialState *creds = NULL;
+	enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
+	uint16_t opnum = dce_call->pkt.u.request.opnum;
+	const char *opname = "<unknown>";
 
-	if (schannel_global_required) {
-		enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
-
-		dcesrv_call_auth_info(dce_call, &auth_type, NULL);
-
-		if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
-			DBG_ERR("[%s] is not using schannel\n",
-				computer_name);
-			return NT_STATUS_ACCESS_DENIED;
-		}
+	if (opnum < ndr_table_netlogon.num_calls) {
+		opname = ndr_table_netlogon.calls[opnum].name;
 	}
 
+	dcesrv_call_auth_info(dce_call, &auth_type, NULL);
+
 	nt_status = schannel_check_creds_state(mem_ctx,
 					       dce_call->conn->dce_ctx->lp_ctx,
 					       computer_name,
 					       received_authenticator,
 					       return_authenticator,
-					       creds_out);
-	return nt_status;
+					       &creds);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		ZERO_STRUCTP(return_authenticator);
+		return nt_status;
+	}
+
+	if (schannel_global_required) {
+		if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+			*creds_out = creds;
+			return NT_STATUS_OK;
+		}
+
+		DBG_ERR("CVE-2020-1472(ZeroLogon): "
+			"%s request (opnum[%u]) without schannel from "
+			"client_account[%s] client_computer_name[%s]\n",
+			opname, opnum,
+			log_escape(mem_ctx, creds->account_name),
+			log_escape(mem_ctx, creds->computer_name));
+		TALLOC_FREE(creds);
+		ZERO_STRUCTP(return_authenticator);
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	*creds_out = creds;
+	return NT_STATUS_OK;
 }
 
 /*
-- 
2.29.2


From 57941290adb9a2fd4be9aa4a70f879a684b38dfd Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 16 Sep 2020 10:56:53 +0200
Subject: [PATCH 18/45] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon:
 support "server require schannel:WORKSTATION$ = no"

This allows to add expections for individual workstations, when using "server schannel = yes".
"server schannel = auto" is very insecure and will be removed soon.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index b4326a4ecaa..e7bafb31e83 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -623,6 +623,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
 	NTSTATUS nt_status;
 	int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx);
 	bool schannel_global_required = (schannel == true);
+	bool schannel_required = schannel_global_required;
 	struct netlogon_creds_CredentialState *creds = NULL;
 	enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
 	uint16_t opnum = dce_call->pkt.u.request.opnum;
@@ -645,7 +646,13 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
 		return nt_status;
 	}
 
-	if (schannel_global_required) {
+	schannel_required = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx,
+					    NULL,
+					    "server require schannel",
+					    creds->account_name,
+					    schannel_global_required);
+
+	if (schannel_required) {
 		if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
 			*creds_out = creds;
 			return NT_STATUS_OK;
-- 
2.29.2


From 779b37e825fe406892ff77be18c098d314cd387d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Thu, 17 Sep 2020 13:37:26 +0200
Subject: [PATCH 19/45] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: log
 warnings about unsecure configurations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This should give admins wawrnings until they have a secure
configuration.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Günther Deschner <gd@samba.org>
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 66 ++++++++++++++++++-
 1 file changed, 63 insertions(+), 3 deletions(-)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index e7bafb31e83..7668a9eb923 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -624,10 +624,12 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
 	int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx);
 	bool schannel_global_required = (schannel == true);
 	bool schannel_required = schannel_global_required;
+	const char *explicit_opt = NULL;
 	struct netlogon_creds_CredentialState *creds = NULL;
 	enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
 	uint16_t opnum = dce_call->pkt.u.request.opnum;
 	const char *opname = "<unknown>";
+	static bool warned_global_once = false;
 
 	if (opnum < ndr_table_netlogon.num_calls) {
 		opname = ndr_table_netlogon.calls[opnum].name;
@@ -646,11 +648,18 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
 		return nt_status;
 	}
 
-	schannel_required = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx,
+	/*
+	 * We don't use lpcfg_parm_bool(), as we
+	 * need the explicit_opt pointer in order to
+	 * adjust the debug messages.
+	 */
+	explicit_opt = lpcfg_get_parametric(dce_call->conn->dce_ctx->lp_ctx,
 					    NULL,
 					    "server require schannel",
-					    creds->account_name,
-					    schannel_global_required);
+					    creds->account_name);
+	if (explicit_opt != NULL) {
+		schannel_required = lp_bool(explicit_opt);
+	}
 
 	if (schannel_required) {
 		if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
@@ -664,11 +673,62 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
 			opname, opnum,
 			log_escape(mem_ctx, creds->account_name),
 			log_escape(mem_ctx, creds->computer_name));
+		DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option "
+			"'server require schannel:%s = no' is needed! \n",
+			log_escape(mem_ctx, creds->account_name));
 		TALLOC_FREE(creds);
 		ZERO_STRUCTP(return_authenticator);
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
+	if (!schannel_global_required && !warned_global_once) {
+		/*
+		 * We want admins to notice their misconfiguration!
+		 */
+		DBG_ERR("CVE-2020-1472(ZeroLogon): "
+			"Please configure 'server schannel = yes', "
+			"See https://bugzilla.samba.org/show_bug.cgi?id=14497\n");
+		warned_global_once = true;
+	}
+
+	if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+		DBG_ERR("CVE-2020-1472(ZeroLogon): "
+			"%s request (opnum[%u]) WITH schannel from "
+			"client_account[%s] client_computer_name[%s]\n",
+			opname, opnum,
+			log_escape(mem_ctx, creds->account_name),
+			log_escape(mem_ctx, creds->computer_name));
+		DBG_ERR("CVE-2020-1472(ZeroLogon): "
+			"Option 'server require schannel:%s = no' not needed!?\n",
+			log_escape(mem_ctx, creds->account_name));
+
+		*creds_out = creds;
+		return NT_STATUS_OK;
+	}
+
+
+	if (explicit_opt != NULL) {
+		DBG_INFO("CVE-2020-1472(ZeroLogon): "
+			 "%s request (opnum[%u]) without schannel from "
+			 "client_account[%s] client_computer_name[%s]\n",
+			 opname, opnum,
+			 log_escape(mem_ctx, creds->account_name),
+			 log_escape(mem_ctx, creds->computer_name));
+		DBG_INFO("CVE-2020-1472(ZeroLogon): "
+			 "Option 'server require schannel:%s = no' still needed!\n",
+			 log_escape(mem_ctx, creds->account_name));
+	} else {
+		DBG_ERR("CVE-2020-1472(ZeroLogon): "
+			"%s request (opnum[%u]) without schannel from "
+			"client_account[%s] client_computer_name[%s]\n",
+			opname, opnum,
+			log_escape(mem_ctx, creds->account_name),
+			log_escape(mem_ctx, creds->computer_name));
+		DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option "
+			"'server require schannel:%s = no' might be needed!\n",
+			log_escape(mem_ctx, creds->account_name));
+	}
+
 	*creds_out = creds;
 	return NT_STATUS_OK;
 }
-- 
2.29.2


From 60b83fbda31c53c592a02f0ed43356a912021021 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
Date: Thu, 17 Sep 2020 14:57:22 +0200
Subject: [PATCH 20/45] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon:
 refactor dcesrv_netr_creds_server_step_check()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

We should debug more details about the failing request.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Günther Deschner <gd@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source3/rpc_server/netlogon/srv_netlog_nt.c | 43 +++++++++++++++++----
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index fd9127b386f..8541571b459 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -48,6 +48,7 @@
 #include "../lib/tsocket/tsocket.h"
 #include "lib/param/param.h"
 #include "libsmb/dsgetdcname.h"
+#include "lib/util/util_str_escape.h"
 
 extern userdom_struct current_user_info;
 
@@ -1073,19 +1074,21 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
 	NTSTATUS status;
 	bool schannel_global_required = (lp_server_schannel() == true) ? true:false;
 	struct loadparm_context *lp_ctx;
+	struct netlogon_creds_CredentialState *creds = NULL;
+	enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
+	uint16_t opnum = p->opnum;
+	const char *opname = "<unknown>";
 
 	if (creds_out != NULL) {
 		*creds_out = NULL;
 	}
 
-	if (schannel_global_required) {
-		if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
-			DBG_ERR("[%s] is not using schannel\n",
-				computer_name);
-			return NT_STATUS_ACCESS_DENIED;
-		}
+	if (opnum < ndr_table_netlogon.num_calls) {
+		opname = ndr_table_netlogon.calls[opnum].name;
 	}
 
+	auth_type = p->auth.auth_type;
+
 	lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
 	if (lp_ctx == NULL) {
 		DEBUG(0, ("loadparm_init_s3 failed\n"));
@@ -1094,9 +1097,33 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
 
 	status = schannel_check_creds_state(mem_ctx, lp_ctx,
 					    computer_name, received_authenticator,
-					    return_authenticator, creds_out);
+					    return_authenticator, &creds);
 	talloc_unlink(mem_ctx, lp_ctx);
-	return status;
+
+	if (!NT_STATUS_IS_OK(status)) {
+		ZERO_STRUCTP(return_authenticator);
+		return status;
+	}
+
+	if (schannel_global_required) {
+		if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+			*creds_out = creds;
+			return NT_STATUS_OK;
+		}
+
+		DBG_ERR("CVE-2020-1472(ZeroLogon): "
+			"%s request (opnum[%u]) without schannel from "
+			"client_account[%s] client_computer_name[%s]\n",
+			opname, opnum,
+			log_escape(mem_ctx, creds->account_name),
+			log_escape(mem_ctx, creds->computer_name));
+		TALLOC_FREE(creds);
+		ZERO_STRUCTP(return_authenticator);
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	*creds_out = creds;
+	return NT_STATUS_OK;
 }
 
 
-- 
2.29.2


From c0a188b2696edb8f3ae9f7f56a820b11358bad98 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
Date: Thu, 17 Sep 2020 14:23:16 +0200
Subject: [PATCH 21/45] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon:
 support "server require schannel:WORKSTATION$ = no"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This allows to add expections for individual workstations, when using "server schannel = yes".
"server schannel = auto" is very insecure and will be removed soon.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Günther Deschner <gd@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source3/rpc_server/netlogon/srv_netlog_nt.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index 8541571b459..f9b10103bd5 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -1073,6 +1073,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
 {
 	NTSTATUS status;
 	bool schannel_global_required = (lp_server_schannel() == true) ? true:false;
+	bool schannel_required = schannel_global_required;
 	struct loadparm_context *lp_ctx;
 	struct netlogon_creds_CredentialState *creds = NULL;
 	enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
@@ -1105,7 +1106,11 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
 		return status;
 	}
 
-	if (schannel_global_required) {
+	schannel_required = lp_parm_bool(GLOBAL_SECTION_SNUM,
+					 "server require schannel",
+					 creds->account_name,
+					 schannel_global_required);
+	if (schannel_required) {
 		if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
 			*creds_out = creds;
 			return NT_STATUS_OK;
-- 
2.29.2


From c9550b81b55316cf5d667502885fc248a5999fb5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
Date: Thu, 17 Sep 2020 14:42:52 +0200
Subject: [PATCH 22/45] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: log
 warnings about unsecure configurations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Günther Deschner <gd@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 source3/rpc_server/netlogon/srv_netlog_nt.c | 70 +++++++++++++++++++--
 1 file changed, 66 insertions(+), 4 deletions(-)

diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index f9b10103bd5..7f6704adbda 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -1074,11 +1074,13 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
 	NTSTATUS status;
 	bool schannel_global_required = (lp_server_schannel() == true) ? true:false;
 	bool schannel_required = schannel_global_required;
+	const char *explicit_opt = NULL;
 	struct loadparm_context *lp_ctx;
 	struct netlogon_creds_CredentialState *creds = NULL;
 	enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
 	uint16_t opnum = p->opnum;
 	const char *opname = "<unknown>";
+	static bool warned_global_once = false;
 
 	if (creds_out != NULL) {
 		*creds_out = NULL;
@@ -1106,10 +1108,20 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
 		return status;
 	}
 
-	schannel_required = lp_parm_bool(GLOBAL_SECTION_SNUM,
-					 "server require schannel",
-					 creds->account_name,
-					 schannel_global_required);
+	/*
+	 * We don't use lp_parm_bool(), as we
+	 * need the explicit_opt pointer in order to
+	 * adjust the debug messages.
+	 */
+
+	explicit_opt = lp_parm_const_string(GLOBAL_SECTION_SNUM,
+					    "server require schannel",
+					    creds->account_name,
+					    NULL);
+	if (explicit_opt != NULL) {
+		schannel_required = lp_bool(explicit_opt);
+	}
+
 	if (schannel_required) {
 		if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
 			*creds_out = creds;
@@ -1122,11 +1134,61 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
 			opname, opnum,
 			log_escape(mem_ctx, creds->account_name),
 			log_escape(mem_ctx, creds->computer_name));
+		DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option "
+			"'server require schannel:%s = no' is needed! \n",
+			log_escape(mem_ctx, creds->account_name));
 		TALLOC_FREE(creds);
 		ZERO_STRUCTP(return_authenticator);
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
+	if (!schannel_global_required && !warned_global_once) {
+		/*
+		 * We want admins to notice their misconfiguration!
+		 */
+		DBG_ERR("CVE-2020-1472(ZeroLogon): "
+			"Please configure 'server schannel = yes', "
+			"See https://bugzilla.samba.org/show_bug.cgi?id=14497\n");
+		warned_global_once = true;
+	}
+
+	if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+		DBG_ERR("CVE-2020-1472(ZeroLogon): "
+			"%s request (opnum[%u]) WITH schannel from "
+			"client_account[%s] client_computer_name[%s]\n",
+			opname, opnum,
+			log_escape(mem_ctx, creds->account_name),
+			log_escape(mem_ctx, creds->computer_name));
+		DBG_ERR("CVE-2020-1472(ZeroLogon): "
+			"Option 'server require schannel:%s = no' not needed!?\n",
+			log_escape(mem_ctx, creds->account_name));
+
+		*creds_out = creds;
+		return NT_STATUS_OK;
+	}
+
+	if (explicit_opt != NULL) {
+		DBG_INFO("CVE-2020-1472(ZeroLogon): "
+			 "%s request (opnum[%u]) without schannel from "
+			 "client_account[%s] client_computer_name[%s]\n",
+			 opname, opnum,
+			 log_escape(mem_ctx, creds->account_name),
+			 log_escape(mem_ctx, creds->computer_name));
+		DBG_INFO("CVE-2020-1472(ZeroLogon): "
+			 "Option 'server require schannel:%s = no' still needed!\n",
+			 log_escape(mem_ctx, creds->account_name));
+	} else {
+		DBG_ERR("CVE-2020-1472(ZeroLogon): "
+			"%s request (opnum[%u]) without schannel from "
+			"client_account[%s] client_computer_name[%s]\n",
+			opname, opnum,
+			log_escape(mem_ctx, creds->account_name),
+			log_escape(mem_ctx, creds->computer_name));
+		DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option "
+			"'server require schannel:%s = no' might be needed!\n",
+			log_escape(mem_ctx, creds->account_name));
+	}
+
 	*creds_out = creds;
 	return NT_STATUS_OK;
 }
-- 
2.29.2


From 63f03e2e29e81f890a5d88c726cced6d3e7bbf5d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Thu, 17 Sep 2020 17:27:54 +0200
Subject: [PATCH 23/45] CVE-2020-1472(ZeroLogon): docs-xml: document 'server
 require schannel:COMPUTERACCOUNT'

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 .../smbdotconf/security/serverschannel.xml    | 69 +++++++++++++++----
 1 file changed, 54 insertions(+), 15 deletions(-)

diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml
index 489492d79b1..b682d086f76 100644
--- a/docs-xml/smbdotconf/security/serverschannel.xml
+++ b/docs-xml/smbdotconf/security/serverschannel.xml
@@ -7,26 +7,65 @@
 <description>
 
     <para>
-	This option is deprecated with Samba 4.8 and will be removed in future.
-	At the same time the default changed to yes, which will be the
-	hardcoded behavior in future. If you have the need for the behavior of "auto"
-	to be kept, please file a bug at https://bugzilla.samba.org.
+	This option is deprecated and will be removed in future,
+	as it is a security problem if not set to "yes" (which will be
+	the hardcoded behavior in future).
     </para>
 
     <para>
-	This controls whether the server offers or even demands the use of the netlogon schannel.
-	<smbconfoption name="server schannel">no</smbconfoption> does not offer the schannel, <smbconfoption
-	name="server schannel">auto</smbconfoption> offers the schannel but does not enforce it, and <smbconfoption
-	name="server schannel">yes</smbconfoption> denies access if the client is not able to speak netlogon schannel.
-	This is only the case for Windows NT4 before SP4.
-	</para>
-
+	Samba will complain in the log files at log level 0,
+	about the security problem if the option is not set to "yes".
+    </para>
     <para>
-	Please note that with this set to <literal>no</literal>, you will have to apply the WindowsXP
-	<filename>WinXP_SignOrSeal.reg</filename> registry patch found in the docs/registry subdirectory of the Samba distribution tarball.
-	</para>
+	See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497
+    </para>
+
+    <para>If you still have legacy domain members use the <smbconfoption name="server require schannel:COMPUTERACCOUNT"/> option.
+    </para>
+
+    <para>This option yields precedence to the <smbconfoption name="server require schannel:COMPUTERACCOUNT"/> option.</para>
+
 </description>
 
 <value type="default">yes</value>
-<value type="example">auto</value>
+</samba:parameter>
+
+<samba:parameter name="server require schannel:COMPUTERACCOUNT"
+                 context="G"
+                 type="string"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+
+    <para>If you still have legacy domain members, which required "server schannel = auto" before,
+	it is possible to specify explicit expection per computer account
+	by using 'server require schannel:COMPUTERACCOUNT = no' as option.
+	Note that COMPUTERACCOUNT has to be the sAMAccountName value of
+	the computer account (including the trailing '$' sign).
+    </para>
+
+    <para>
+	Samba will complain in the log files at log level 0,
+	about the security problem if the option is not set to "no",
+	but the related computer is actually using the netlogon
+	secure channel (schannel) feature.
+    </para>
+
+    <para>
+	Samba will warn in the log files at log level 5,
+	if a setting is still needed for the specified computer account.
+    </para>
+
+    <para>
+	See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497
+    </para>
+
+    <para>This option takes precedence to the <smbconfoption name="server schannel"/> option.</para>
+
+    <programlisting>
+	server require schannel:LEGACYCOMPUTER1$ = no
+	server require schannel:NASBOX$ = no
+	server require schannel:LEGACYCOMPUTER2$ = no
+    </programlisting>
+</description>
+
 </samba:parameter>
-- 
2.29.2


From 8a40da45b7f4e7a9110daf010383c4fce30bd9b6 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary@catalyst.net.nz>
Date: Fri, 18 Sep 2020 12:39:54 +1200
Subject: [PATCH 24/45] CVE-2020-1472(ZeroLogon): s4 torture rpc: Test empty
 machine acct pwd

Ensure that an empty machine account password can't be set by
netr_ServerPasswordSet2

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
---
 source4/torture/rpc/netlogon.c | 64 +++++++++++++++-------------------
 1 file changed, 29 insertions(+), 35 deletions(-)

diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
index e11014922f8..0ba45f0c1da 100644
--- a/source4/torture/rpc/netlogon.c
+++ b/source4/torture/rpc/netlogon.c
@@ -719,45 +719,39 @@ static bool test_SetPassword2_with_flags(struct torture_context *tctx,
 
 	cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED);
 
-	if (!torture_setting_bool(tctx, "dangerous", false)) {
-		torture_comment(tctx,
-			"Not testing ability to set password to '', enable dangerous tests to perform this test\n");
+	/*
+	 * As a consequence of CVE-2020-1472(ZeroLogon)
+	 * Samba explicitly disallows the setting of an empty machine account
+	 * password.
+	 *
+	 * Note that this may fail against Windows, and leave a machine account
+	 * with an empty password.
+	 */
+	password = "";
+	encode_pw_buffer(password_buf.data, password, STR_UNICODE);
+	if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+		netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
 	} else {
-		/* by changing the machine password to ""
-		 * we check if the server uses password restrictions
-		 * for ServerPasswordSet2
-		 * (win2k3 accepts "")
-		 */
-		password = "";
-		encode_pw_buffer(password_buf.data, password, STR_UNICODE);
-		if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
-			netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
-		} else {
-			netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
-		}
-		memcpy(new_password.data, password_buf.data, 512);
-		new_password.length = IVAL(password_buf.data, 512);
-
-		torture_comment(tctx,
-			"Testing ServerPasswordSet2 on machine account\n");
-		torture_comment(tctx,
-			"Changing machine account password to '%s'\n", password);
-
-		netlogon_creds_client_authenticator(creds, &credential);
-
-		torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
-			"ServerPasswordSet2 failed");
-		torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet2 failed");
+		netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+	}
+	memcpy(new_password.data, password_buf.data, 512);
+	new_password.length = IVAL(password_buf.data, 512);
 
-		if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
-			torture_comment(tctx, "Credential chaining failed\n");
-		}
+	torture_comment(tctx,
+		"Testing ServerPasswordSet2 on machine account\n");
+	torture_comment(tctx,
+		"Changing machine account password to '%s'\n", password);
 
-		cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED);
-	}
+	netlogon_creds_client_authenticator(creds, &credential);
 
-	torture_assert(tctx, test_SetupCredentials(p, tctx, machine_credentials, &creds),
-		"ServerPasswordSet failed to actually change the password");
+	torture_assert_ntstatus_ok(
+		tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+		"ServerPasswordSet2 failed");
+	torture_assert_ntstatus_equal(
+		tctx,
+		r.out.result,
+		NT_STATUS_WRONG_PASSWORD,
+		"ServerPasswordSet2 did not return NT_STATUS_WRONG_PASSWORD");
 
 	/* now try a random password */
 	password = generate_random_password(tctx, 8, 255);
-- 
2.29.2


From 341a448cb69557410fa79dbb8a3d4adbab79d5b6 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary@catalyst.net.nz>
Date: Fri, 18 Sep 2020 15:57:34 +1200
Subject: [PATCH 25/45] CVE-2020-1472(ZeroLogon): s4 torture rpc: repeated
 bytes in client challenge

Ensure that client challenges with the first 5 bytes identical are
rejected.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>

[abartlet@samba.org: backported from master as test order was flipped]
---
 source4/torture/rpc/netlogon.c | 335 +++++++++++++++++++++++++++++++++
 1 file changed, 335 insertions(+)

diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
index 0ba45f0c1da..97c16688bc9 100644
--- a/source4/torture/rpc/netlogon.c
+++ b/source4/torture/rpc/netlogon.c
@@ -480,6 +480,325 @@ bool test_SetupCredentialsPipe(const struct dcerpc_pipe *p1,
 	return true;
 }
 
+static bool test_ServerReqChallenge(
+	struct torture_context *tctx,
+	struct dcerpc_pipe *p,
+	struct cli_credentials *credentials)
+{
+	struct netr_ServerReqChallenge r;
+	struct netr_Credential credentials1, credentials2, credentials3;
+	const char *machine_name;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct netr_ServerAuthenticate2 a;
+	uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+	uint32_t out_negotiate_flags = 0;
+	const struct samr_Password *mach_password = NULL;
+	enum netr_SchannelType sec_chan_type = 0;
+	struct netlogon_creds_CredentialState *creds = NULL;
+	const char *account_name = NULL;
+
+	machine_name = cli_credentials_get_workstation(credentials);
+	mach_password = cli_credentials_get_nt_hash(credentials, tctx);
+	account_name = cli_credentials_get_username(credentials);
+	sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
+
+	torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+	r.in.server_name = NULL;
+	r.in.computer_name = machine_name;
+	r.in.credentials = &credentials1;
+	r.out.return_credentials = &credentials2;
+
+	netlogon_creds_random_challenge(&credentials1);
+
+	torture_assert_ntstatus_ok(
+		tctx,
+		dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+		"ServerReqChallenge failed");
+	torture_assert_ntstatus_ok(
+		tctx,
+		r.out.result,
+		"ServerReqChallenge failed");
+	a.in.server_name = NULL;
+	a.in.account_name = account_name;
+	a.in.secure_channel_type = sec_chan_type;
+	a.in.computer_name = machine_name;
+	a.in.negotiate_flags = &in_negotiate_flags;
+	a.out.negotiate_flags = &out_negotiate_flags;
+	a.in.credentials = &credentials3;
+	a.out.return_credentials = &credentials3;
+
+	creds = netlogon_creds_client_init(tctx, a.in.account_name,
+					   a.in.computer_name,
+					   a.in.secure_channel_type,
+					   &credentials1, &credentials2,
+					   mach_password, &credentials3,
+					   in_negotiate_flags);
+
+	torture_assert(tctx, creds != NULL, "memory allocation");
+
+	torture_comment(tctx, "Testing ServerAuthenticate2\n");
+
+	torture_assert_ntstatus_ok(
+		tctx,
+		dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
+		"ServerAuthenticate2 failed");
+	torture_assert_ntstatus_equal(
+		tctx,
+		a.out.result,
+		NT_STATUS_OK,
+		"ServerAuthenticate2 unexpected");
+
+	return true;
+}
+
+static bool test_ServerReqChallenge_zero_challenge(
+	struct torture_context *tctx,
+	struct dcerpc_pipe *p,
+	struct cli_credentials *credentials)
+{
+	struct netr_ServerReqChallenge r;
+	struct netr_Credential credentials1, credentials2, credentials3;
+	const char *machine_name;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct netr_ServerAuthenticate2 a;
+	uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+	uint32_t out_negotiate_flags = 0;
+	const struct samr_Password *mach_password = NULL;
+	enum netr_SchannelType sec_chan_type = 0;
+	struct netlogon_creds_CredentialState *creds = NULL;
+	const char *account_name = NULL;
+
+	machine_name = cli_credentials_get_workstation(credentials);
+	mach_password = cli_credentials_get_nt_hash(credentials, tctx);
+	account_name = cli_credentials_get_username(credentials);
+	sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
+
+	torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+	r.in.server_name = NULL;
+	r.in.computer_name = machine_name;
+	r.in.credentials = &credentials1;
+	r.out.return_credentials = &credentials2;
+
+	/*
+	 * Set the client challenge to zero, this should fail
+	 * CVE-2020-1472(ZeroLogon)
+	 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
+	 */
+	ZERO_STRUCT(credentials1);
+
+	torture_assert_ntstatus_ok(
+		tctx,
+		dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+		"ServerReqChallenge failed");
+	torture_assert_ntstatus_ok(
+		tctx,
+		r.out.result,
+		"ServerReqChallenge failed");
+	a.in.server_name = NULL;
+	a.in.account_name = account_name;
+	a.in.secure_channel_type = sec_chan_type;
+	a.in.computer_name = machine_name;
+	a.in.negotiate_flags = &in_negotiate_flags;
+	a.out.negotiate_flags = &out_negotiate_flags;
+	a.in.credentials = &credentials3;
+	a.out.return_credentials = &credentials3;
+
+	creds = netlogon_creds_client_init(tctx, a.in.account_name,
+					   a.in.computer_name,
+					   a.in.secure_channel_type,
+					   &credentials1, &credentials2,
+					   mach_password, &credentials3,
+					   in_negotiate_flags);
+
+	torture_assert(tctx, creds != NULL, "memory allocation");
+
+	torture_comment(tctx, "Testing ServerAuthenticate2\n");
+
+	torture_assert_ntstatus_ok(
+		tctx,
+		dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
+		"ServerAuthenticate2 failed");
+	torture_assert_ntstatus_equal(
+		tctx,
+		a.out.result,
+		NT_STATUS_ACCESS_DENIED,
+		"ServerAuthenticate2 unexpected");
+
+	return true;
+}
+
+static bool test_ServerReqChallenge_5_repeats(
+	struct torture_context *tctx,
+	struct dcerpc_pipe *p,
+	struct cli_credentials *credentials)
+{
+	struct netr_ServerReqChallenge r;
+	struct netr_Credential credentials1, credentials2, credentials3;
+	const char *machine_name;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct netr_ServerAuthenticate2 a;
+	uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+	uint32_t out_negotiate_flags = 0;
+	const struct samr_Password *mach_password = NULL;
+	enum netr_SchannelType sec_chan_type = 0;
+	struct netlogon_creds_CredentialState *creds = NULL;
+	const char *account_name = NULL;
+
+	machine_name = cli_credentials_get_workstation(credentials);
+	mach_password = cli_credentials_get_nt_hash(credentials, tctx);
+	account_name = cli_credentials_get_username(credentials);
+	sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
+
+	torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+	r.in.server_name = NULL;
+	r.in.computer_name = machine_name;
+	r.in.credentials = &credentials1;
+	r.out.return_credentials = &credentials2;
+
+	/*
+	 * Set the first 5 bytes of the client challenge to the same value,
+	 * this should fail CVE-2020-1472(ZeroLogon)
+	 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
+	 */
+	credentials1.data[0] = 'A';
+	credentials1.data[1] = 'A';
+	credentials1.data[2] = 'A';
+	credentials1.data[3] = 'A';
+	credentials1.data[4] = 'A';
+	credentials1.data[5] = 'B';
+	credentials1.data[6] = 'C';
+	credentials1.data[7] = 'D';
+
+	torture_assert_ntstatus_ok(
+		tctx,
+		dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+		"ServerReqChallenge failed");
+	torture_assert_ntstatus_ok(
+		tctx,
+		r.out.result,
+		"ServerReqChallenge failed");
+	a.in.server_name = NULL;
+	a.in.account_name = account_name;
+	a.in.secure_channel_type = sec_chan_type;
+	a.in.computer_name = machine_name;
+	a.in.negotiate_flags = &in_negotiate_flags;
+	a.out.negotiate_flags = &out_negotiate_flags;
+	a.in.credentials = &credentials3;
+	a.out.return_credentials = &credentials3;
+
+	creds = netlogon_creds_client_init(tctx, a.in.account_name,
+					   a.in.computer_name,
+					   a.in.secure_channel_type,
+					   &credentials1, &credentials2,
+					   mach_password, &credentials3,
+					   in_negotiate_flags);
+
+	torture_assert(tctx, creds != NULL, "memory allocation");
+
+	torture_comment(tctx, "Testing ServerAuthenticate2\n");
+
+	torture_assert_ntstatus_ok(
+		tctx,
+		dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
+		"ServerAuthenticate2 failed");
+	torture_assert_ntstatus_equal(
+		tctx,
+		a.out.result,
+		NT_STATUS_ACCESS_DENIED,
+		"ServerAuthenticate2 unexpected");
+
+	return true;
+}
+
+static bool test_ServerReqChallenge_4_repeats(
+	struct torture_context *tctx,
+	struct dcerpc_pipe *p,
+	struct cli_credentials *credentials)
+{
+	struct netr_ServerReqChallenge r;
+	struct netr_Credential credentials1, credentials2, credentials3;
+	const char *machine_name;
+	struct dcerpc_binding_handle *b = p->binding_handle;
+	struct netr_ServerAuthenticate2 a;
+	uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+	uint32_t out_negotiate_flags = 0;
+	const struct samr_Password *mach_password = NULL;
+	enum netr_SchannelType sec_chan_type = 0;
+	struct netlogon_creds_CredentialState *creds = NULL;
+	const char *account_name = NULL;
+
+	machine_name = cli_credentials_get_workstation(credentials);
+	mach_password = cli_credentials_get_nt_hash(credentials, tctx);
+	account_name = cli_credentials_get_username(credentials);
+	sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
+
+	torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+	r.in.server_name = NULL;
+	r.in.computer_name = machine_name;
+	r.in.credentials = &credentials1;
+	r.out.return_credentials = &credentials2;
+
+        /*
+         * Set the first 4 bytes of the client challenge to the same
+         * value, this should pass as 5 bytes identical are needed to
+         * fail for CVE-2020-1472(ZeroLogon)
+         *
+	 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
+	 */
+	credentials1.data[0] = 'A';
+	credentials1.data[1] = 'A';
+	credentials1.data[2] = 'A';
+	credentials1.data[3] = 'A';
+	credentials1.data[4] = 'B';
+	credentials1.data[5] = 'C';
+	credentials1.data[6] = 'D';
+	credentials1.data[7] = 'E';
+
+	torture_assert_ntstatus_ok(
+		tctx,
+		dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+		"ServerReqChallenge failed");
+	torture_assert_ntstatus_ok(
+		tctx,
+		r.out.result,
+		"ServerReqChallenge failed");
+	a.in.server_name = NULL;
+	a.in.account_name = account_name;
+	a.in.secure_channel_type = sec_chan_type;
+	a.in.computer_name = machine_name;
+	a.in.negotiate_flags = &in_negotiate_flags;
+	a.out.negotiate_flags = &out_negotiate_flags;
+	a.in.credentials = &credentials3;
+	a.out.return_credentials = &credentials3;
+
+	creds = netlogon_creds_client_init(tctx, a.in.account_name,
+					   a.in.computer_name,
+					   a.in.secure_channel_type,
+					   &credentials1, &credentials2,
+					   mach_password, &credentials3,
+					   in_negotiate_flags);
+
+	torture_assert(tctx, creds != NULL, "memory allocation");
+
+	torture_comment(tctx, "Testing ServerAuthenticate2\n");
+
+	torture_assert_ntstatus_ok(
+		tctx,
+		dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
+		"ServerAuthenticate2 failed");
+	torture_assert_ntstatus_equal(
+		tctx,
+		a.out.result,
+		NT_STATUS_OK,
+		"ServerAuthenticate2 unexpected");
+
+	return true;
+}
+
 /*
   try a change password for our machine account
 */
@@ -4949,6 +5268,22 @@ struct torture_suite *torture_rpc_netlogon(TALLOC_CTX *mem_ctx)
 	torture_rpc_tcase_add_test(tcase, "lsa_over_netlogon", test_lsa_over_netlogon);
 	torture_rpc_tcase_add_test_creds(tcase, "SetupCredentialsDowngrade", test_SetupCredentialsDowngrade);
 
+	torture_rpc_tcase_add_test_creds(
+		tcase,
+		"ServerReqChallenge",
+		test_ServerReqChallenge);
+	torture_rpc_tcase_add_test_creds(
+		tcase,
+		"ServerReqChallenge_zero_challenge",
+		test_ServerReqChallenge_zero_challenge);
+	torture_rpc_tcase_add_test_creds(
+		tcase,
+		"ServerReqChallenge_5_repeats",
+		test_ServerReqChallenge_5_repeats);
+	torture_rpc_tcase_add_test_creds(
+		tcase,
+		"ServerReqChallenge_4_repeats",
+		test_ServerReqChallenge_4_repeats);
 	return suite;
 }
 
-- 
2.29.2


From 268303632f79d7395b452172c06b25ad68fe35fb Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Fri, 10 Jul 2020 15:09:33 -0700
Subject: [PATCH 26/45] s4: torture: Add smb2.notify.handle-permissions test.

Add knownfail entry.

CVE-2020-14318

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14434

Signed-off-by: Jeremy Allison <jra@samba.org>
(cherry picked from commit f100bd2f2e4f047942002a992c99104227a17f81)
---
 .../smb2_notify_handle_permissions            |  2 +
 source4/torture/smb2/notify.c                 | 80 +++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 selftest/knownfail.d/smb2_notify_handle_permissions

diff --git a/selftest/knownfail.d/smb2_notify_handle_permissions b/selftest/knownfail.d/smb2_notify_handle_permissions
new file mode 100644
index 00000000000..c0ec8fc8153
--- /dev/null
+++ b/selftest/knownfail.d/smb2_notify_handle_permissions
@@ -0,0 +1,2 @@
+^samba3.smb2.notify.handle-permissions
+
diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c
index ebb4f8a4f8e..b017491c8fb 100644
--- a/source4/torture/smb2/notify.c
+++ b/source4/torture/smb2/notify.c
@@ -2569,6 +2569,83 @@ done:
 	return ok;
 }
 
+/*
+  Test asking for a change notify on a handle without permissions.
+*/
+
+#define BASEDIR_HPERM BASEDIR "_HPERM"
+
+static bool torture_smb2_notify_handle_permissions(
+		struct torture_context *torture,
+		struct smb2_tree *tree)
+{
+	bool ret = true;
+	NTSTATUS status;
+	union smb_notify notify;
+	union smb_open io;
+	struct smb2_handle h1 = {{0}};
+	struct smb2_request *req;
+
+	smb2_deltree(tree, BASEDIR_HPERM);
+	smb2_util_rmdir(tree, BASEDIR_HPERM);
+
+	torture_comment(torture,
+		"TESTING CHANGE NOTIFY "
+		"ON A HANDLE WITHOUT PERMISSIONS\n");
+
+	/*
+	  get a handle on the directory
+	*/
+	ZERO_STRUCT(io.smb2);
+	io.generic.level = RAW_OPEN_SMB2;
+	io.smb2.in.create_flags = 0;
+	io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+	io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+	io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+				NTCREATEX_SHARE_ACCESS_WRITE;
+	io.smb2.in.alloc_size = 0;
+	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+	io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+	io.smb2.in.security_flags = 0;
+	io.smb2.in.fname = BASEDIR_HPERM;
+
+	status = smb2_create(tree, torture, &io.smb2);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h1 = io.smb2.out.file.handle;
+
+	/* ask for a change notify,
+	   on file or directory name changes */
+	ZERO_STRUCT(notify.smb2);
+	notify.smb2.level = RAW_NOTIFY_SMB2;
+	notify.smb2.in.buffer_size = 1000;
+	notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+	notify.smb2.in.file.handle = h1;
+	notify.smb2.in.recursive = true;
+
+	req = smb2_notify_send(tree, &notify.smb2);
+	torture_assert_goto(torture,
+			req != NULL,
+			ret,
+			done,
+			"smb2_notify_send failed\n");
+
+	/*
+	 * Cancel it, we don't really want to wait.
+	 */
+	smb2_cancel(req);
+	status = smb2_notify_recv(req, torture, &notify.smb2);
+	/* Handle h1 doesn't have permissions for ChangeNotify. */
+	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+done:
+	if (!smb2_util_handle_empty(h1)) {
+		smb2_util_close(tree, h1);
+	}
+	smb2_deltree(tree, BASEDIR_HPERM);
+	return ret;
+}
+
 /*
    basic testing of SMB2 change notify
 */
@@ -2602,6 +2679,9 @@ struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx)
 				     torture_smb2_notify_rmdir3);
 	torture_suite_add_2smb2_test(suite, "rmdir4",
 				     torture_smb2_notify_rmdir4);
+	torture_suite_add_1smb2_test(suite,
+				    "handle-permissions",
+				    torture_smb2_notify_handle_permissions);
 
 	suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
 
-- 
2.29.2


From 448d4e99f8883a07589264cfca474c3dff8b5942 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 7 Jul 2020 18:25:23 -0700
Subject: [PATCH 27/45] s3: smbd: Ensure change notifies can't get set unless
 the directory handle is open for SEC_DIR_LIST.

Remove knownfail entry.

CVE-2020-14318

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14434

Signed-off-by: Jeremy Allison <jra@samba.org>
(cherry picked from commit f43ecce46a89c6380317fbb5f2ae38f48d3d42c8)
---
 selftest/knownfail.d/smb2_notify_handle_permissions | 2 --
 source3/smbd/notify.c                               | 8 ++++++++
 2 files changed, 8 insertions(+), 2 deletions(-)
 delete mode 100644 selftest/knownfail.d/smb2_notify_handle_permissions

diff --git a/selftest/knownfail.d/smb2_notify_handle_permissions b/selftest/knownfail.d/smb2_notify_handle_permissions
deleted file mode 100644
index c0ec8fc8153..00000000000
--- a/selftest/knownfail.d/smb2_notify_handle_permissions
+++ /dev/null
@@ -1,2 +0,0 @@
-^samba3.smb2.notify.handle-permissions
-
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index 44c0b09432e..d23c03bce41 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -283,6 +283,14 @@ NTSTATUS change_notify_create(struct files_struct *fsp, uint32_t filter,
 	char fullpath[len+1];
 	NTSTATUS status = NT_STATUS_NOT_IMPLEMENTED;
 
+	/*
+	 * Setting a changenotify needs READ/LIST access
+	 * on the directory handle.
+	 */
+	if (!(fsp->access_mask & SEC_DIR_LIST)) {
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
 	if (fsp->notify != NULL) {
 		DEBUG(1, ("change_notify_create: fsp->notify != NULL, "
 			  "fname = %s\n", fsp->fsp_name->base_name));
-- 
2.29.2


From 041c86926999594f13b884522b1d9fcc65f92a52 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl@samba.org>
Date: Thu, 9 Jul 2020 21:49:25 +0200
Subject: [PATCH 28/45] CVE-2020-14323 winbind: Fix invalid lookupsids DoS

A lookupsids request without extra_data will lead to "state->domain==NULL",
which makes winbindd_lookupsids_recv trying to dereference it.

Reported by Bas Alberts of the GitHub Security Lab Team as GHSL-2020-134

Bug: https://bugzilla.samba.org/show_bug.cgi?id=14436
Signed-off-by: Volker Lendecke <vl@samba.org>
(cherry picked from commit f17967ad73e9c1d2bd6e0b7c181f08079d2a8214)
---
 source3/winbindd/winbindd_lookupsids.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/winbindd/winbindd_lookupsids.c b/source3/winbindd/winbindd_lookupsids.c
index d28b5fa9f01..a289fd86f0f 100644
--- a/source3/winbindd/winbindd_lookupsids.c
+++ b/source3/winbindd/winbindd_lookupsids.c
@@ -47,7 +47,7 @@ struct tevent_req *winbindd_lookupsids_send(TALLOC_CTX *mem_ctx,
 	DEBUG(3, ("lookupsids\n"));
 
 	if (request->extra_len == 0) {
-		tevent_req_done(req);
+		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 		return tevent_req_post(req, ev);
 	}
 	if (request->extra_data.data[request->extra_len-1] != '\0') {
-- 
2.29.2


From e6e77a3a503f9223ecbc2d32a1d24e20f834659f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl@samba.org>
Date: Thu, 9 Jul 2020 21:48:57 +0200
Subject: [PATCH 29/45] CVE-2020-14323 torture4: Add a simple test for invalid
 lookup_sids winbind call

We can't add this test before the fix, add it to knownfail and have the fix
remove the knownfail entry again. As this crashes winbind, many tests after
this one will fail.

Reported by Bas Alberts of the GitHub Security Lab Team as GHSL-2020-134

Bug: https://bugzilla.samba.org/show_bug.cgi?id=14436
Signed-off-by: Volker Lendecke <vl@samba.org>
(cherry picked from commit d0ca2a63aaedf123205337aaa211426175ffcebf)
---
 source4/torture/winbind/struct_based.c | 27 ++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/source4/torture/winbind/struct_based.c b/source4/torture/winbind/struct_based.c
index 9745b621ca9..71f248c0d61 100644
--- a/source4/torture/winbind/struct_based.c
+++ b/source4/torture/winbind/struct_based.c
@@ -1110,6 +1110,29 @@ static bool torture_winbind_struct_lookup_name_sid(struct torture_context *tortu
 	return true;
 }
 
+static bool torture_winbind_struct_lookup_sids_invalid(
+	struct torture_context *torture)
+{
+	struct winbindd_request req = {0};
+	struct winbindd_response rep = {0};
+	bool strict = torture_setting_bool(torture, "strict mode", false);
+	bool ok;
+
+	torture_comment(torture,
+			"Running WINBINDD_LOOKUP_SIDS (struct based)\n");
+
+	ok = true;
+	DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPSIDS, &req, &rep,
+			      NSS_STATUS_NOTFOUND,
+			      strict,
+			      ok=false,
+			      talloc_asprintf(
+				      torture,
+				      "invalid lookupsids succeeded"));
+
+	return ok;
+}
+
 struct torture_suite *torture_winbind_struct_init(TALLOC_CTX *ctx)
 {
 	struct torture_suite *suite = torture_suite_create(ctx, "struct");
@@ -1132,6 +1155,10 @@ struct torture_suite *torture_winbind_struct_init(TALLOC_CTX *ctx)
 	torture_suite_add_simple_test(suite, "getpwent", torture_winbind_struct_getpwent);
 	torture_suite_add_simple_test(suite, "endpwent", torture_winbind_struct_endpwent);
 	torture_suite_add_simple_test(suite, "lookup_name_sid", torture_winbind_struct_lookup_name_sid);
+	torture_suite_add_simple_test(
+		suite,
+		"lookup_sids_invalid",
+		torture_winbind_struct_lookup_sids_invalid);
 
 	suite->description = talloc_strdup(suite, "WINBIND - struct based protocol tests");
 
-- 
2.29.2


From 2b4763940d1826a2b4e5eaa1e2df338004cd9af0 Mon Sep 17 00:00:00 2001
From: Laurent Menase <laurent.menase@hpe.com>
Date: Wed, 20 May 2020 12:31:53 +0200
Subject: [PATCH 30/45] winbind: Fix a memleak

Bug: https://bugzilla.samba.org/show_bug.cgi?id=14388
Signed-off-by: Laurent Menase <laurent.menase@hpe.com>
Reviewed-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Noel Power <noel.power@suse.com>

Autobuild-User(master): Volker Lendecke <vl@samba.org>
Autobuild-Date(master): Mon Sep 14 13:33:13 UTC 2020 on sn-devel-184

(cherry picked from commit 8f868b0ea0b4795668f7bc0b028cd85686b249fb)
---
 source3/winbindd/winbindd_ads.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c
index 556b4523866..325ba1abd82 100644
--- a/source3/winbindd/winbindd_ads.c
+++ b/source3/winbindd/winbindd_ads.c
@@ -405,6 +405,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
 	DBG_NOTICE("ads query_user_list gave %d entries\n", count);
 
 done:
+	ads_msgfree(ads, res);
 	return status;
 }
 
-- 
2.29.2


From accc423a4eb9170ab0dbe4b2ba90ce83790e7a16 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Mon, 17 Aug 2020 13:39:58 +0200
Subject: [PATCH 31/45] s3:tests: Add test for 'valid users = DOMAIN\%U'

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14467

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
(cherry picked from commit 53b6dd951249052772e1ffcf651b7efd0963b931)
(cherry picked from commit 20d3cf455c631c6cea6d471333779cc15d0e8d8a)
---
 selftest/knownfail.d/samba3.substiutions   | 1 +
 selftest/target/Samba3.pm                  | 4 ++++
 source3/script/tests/test_substitutions.sh | 5 +++++
 3 files changed, 10 insertions(+)
 create mode 100644 selftest/knownfail.d/samba3.substiutions

diff --git a/selftest/knownfail.d/samba3.substiutions b/selftest/knownfail.d/samba3.substiutions
new file mode 100644
index 00000000000..f116d3b2fcf
--- /dev/null
+++ b/selftest/knownfail.d/samba3.substiutions
@@ -0,0 +1 @@
+^samba3.substitutions.Test.login.to.share.with.substitution.for.valid.users
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 75960dbc790..9e4da0e6a08 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -423,6 +423,10 @@ sub setup_ad_member
 	path = $share_dir/D_%D/u_%u/g_%g
 	writeable = yes
 
+[sub_valid_users]
+	path = $share_dir
+	valid users = ADDOMAIN/%U
+
 ";
 
 	my $ret = $self->provision($prefix, $dcvars->{DOMAIN},
diff --git a/source3/script/tests/test_substitutions.sh b/source3/script/tests/test_substitutions.sh
index 1a46f11c85d..c813a8f9def 100755
--- a/source3/script/tests/test_substitutions.sh
+++ b/source3/script/tests/test_substitutions.sh
@@ -34,4 +34,9 @@ SMB_UNC="//$SERVER/sub_dug2"
 test_smbclient "Test login to share with substitution (Dug)" \
 	"ls" "$SMB_UNC" "-U$USERNAME%$PASSWORD" || failed=$(expr $failed + 1)
 
+SMB_UNC="//$SERVER/sub_valid_users"
+
+test_smbclient "Test login to share with substitution for valid users" \
+	"ls" "$SMB_UNC" "-U$USERNAME%$PASSWORD" || failed=$(expr $failed + 1)
+
 exit $failed
-- 
2.29.2


From 1c594e3734e3ffd2dfc615897ac95792878f2df4 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Mon, 17 Aug 2020 14:12:48 +0200
Subject: [PATCH 32/45] s3:smbd: Fix %U substitutions if it contains a domain
 name

'valid users = DOMAIN\%U' worked with Samba 3.6 and broke in a newer
version.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14467

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
(cherry picked from commit 5de7c91e6d4e98f438157a7675c8582cabdd828d)
(cherry picked from commit 60ddb7b20071b00f0cd7f1cb818022220eb0c279)
---
 selftest/knownfail.d/samba3.substiutions |  1 -
 source3/smbd/share_access.c              | 18 +++++++++++++++++-
 2 files changed, 17 insertions(+), 2 deletions(-)
 delete mode 100644 selftest/knownfail.d/samba3.substiutions

diff --git a/selftest/knownfail.d/samba3.substiutions b/selftest/knownfail.d/samba3.substiutions
deleted file mode 100644
index f116d3b2fcf..00000000000
--- a/selftest/knownfail.d/samba3.substiutions
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.substitutions.Test.login.to.share.with.substitution.for.valid.users
diff --git a/source3/smbd/share_access.c b/source3/smbd/share_access.c
index 3cbf7f318a2..0705e197975 100644
--- a/source3/smbd/share_access.c
+++ b/source3/smbd/share_access.c
@@ -79,7 +79,23 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx,
 	enum lsa_SidType type;
 
 	if (username != NULL) {
-		name = talloc_sub_basic(mem_ctx, username, domain, name);
+		size_t domain_len = strlen(domain);
+
+		/* Check if username starts with domain name */
+		if (domain_len > 0) {
+			const char *sep = lp_winbind_separator();
+			int cmp = strncasecmp_m(username, domain, domain_len);
+			if (cmp == 0 && sep[0] == username[domain_len]) {
+				/* Move after the winbind separator */
+				domain_len += 1;
+			} else {
+				domain_len = 0;
+			}
+		}
+		name = talloc_sub_basic(mem_ctx,
+					username + domain_len,
+					domain,
+					name);
 	}
 	if (sharename != NULL) {
 		name = talloc_string_sub(mem_ctx, name, "%S", sharename);
-- 
2.29.2


From d93ddae23e1b378f771134e93d1b15e61e2278af Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Thu, 9 Jul 2020 11:48:26 +0200
Subject: [PATCH 33/45] docs: Fix documentation for require_membership_of of
 pam_winbind

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14358

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Alexander Bokovoy <ab@samba.org>
(cherry picked from commit 4c74db6978c682f8ba4e74a6ee8157cfcbb54971)
---
 docs-xml/manpages/pam_winbind.8.xml | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/docs-xml/manpages/pam_winbind.8.xml b/docs-xml/manpages/pam_winbind.8.xml
index a9a227f1647..a61fb2d58e5 100644
--- a/docs-xml/manpages/pam_winbind.8.xml
+++ b/docs-xml/manpages/pam_winbind.8.xml
@@ -84,9 +84,11 @@
 		If this option is set, pam_winbind will only succeed if the user is a member of the given SID or NAME. A SID
 		can be either a group-SID, an alias-SID or even an user-SID. It is also possible to give a NAME instead of the
 		SID. That name must have the form: <parameter>MYDOMAIN\mygroup</parameter> or
-		<parameter>MYDOMAIN\myuser</parameter>.  pam_winbind will, in that case, lookup the SID internally. Note that
-		NAME may not contain any spaces. It is thus recommended to only use SIDs. You can verify the list of SIDs a
-		user is a member of with <command>wbinfo --user-sids=SID</command>.
+		<parameter>MYDOMAIN\myuser</parameter> (where '\' character corresponds to the value of
+		<parameter>winbind separator</parameter> parameter). It is also possible to use a UPN in the form
+		<parameter>user@REALM</parameter> or <parameter>group@REALM</parameter>. pam_winbind will, in that case, lookup
+		the SID internally. Note that NAME may not contain any spaces. It is thus recommended to only use SIDs. You can
+		verify the list of SIDs a user is a member of with <command>wbinfo --user-sids=SID</command>.
 		</para>
 
 		<para>
-- 
2.29.2


From c9aea952eb3f8d83701abd6db4d48c8d93a8517a Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Fri, 17 Jul 2020 12:14:16 +0200
Subject: [PATCH 34/45] docs: Fix documentation for require_membership_of of
 pam_winbind.conf

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14358

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Isaac Boukris <iboukris@samba.org>
(cherry picked from commit 71b7140fd0a33e7e8c5bf37c2897cea8224b3f01)
---
 docs-xml/manpages/pam_winbind.conf.5.xml | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/docs-xml/manpages/pam_winbind.conf.5.xml b/docs-xml/manpages/pam_winbind.conf.5.xml
index fcac1ee7036..d81a0bd6eba 100644
--- a/docs-xml/manpages/pam_winbind.conf.5.xml
+++ b/docs-xml/manpages/pam_winbind.conf.5.xml
@@ -69,9 +69,12 @@
 		If this option is set, pam_winbind will only succeed if the user is a member of the given SID or NAME. A SID
 		can be either a group-SID, an alias-SID or even an user-SID. It is also possible to give a NAME instead of the
 		SID. That name must have the form: <parameter>MYDOMAIN\mygroup</parameter> or
-		<parameter>MYDOMAIN\myuser</parameter>.  pam_winbind will, in that case, lookup the SID internally. Note that
-		NAME may not contain any spaces. It is thus recommended to only use SIDs. You can verify the list of SIDs a
-		user is a member of with <command>wbinfo --user-sids=SID</command>. This setting is empty by default.
+		<parameter>MYDOMAIN\myuser</parameter> (where '\' character corresponds to the value of
+		<parameter>winbind separator</parameter> parameter). It is also possible to use a UPN in the form
+		<parameter>user@REALM</parameter> or <parameter>group@REALM</parameter>. pam_winbind will, in that case, lookup
+		the SID internally. Note that NAME may not contain any spaces. It is thus recommended to only use SIDs. You can
+		verify the list of SIDs a user is a member of with <command>wbinfo --user-sids=SID</command>.
+		This setting is empty by default.
 		</para>
 		<para>This option only operates during password authentication, and will not restrict access if a password is not required for any reason (such as SSH key-based login).</para>
 		</listitem>
-- 
2.29.2


From b04be6ffd3a1c9eda1f1dc78d60ad7b3a9b7471d Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Thu, 11 Jun 2020 21:05:07 +0300
Subject: [PATCH 35/45] Fix a typo in recent net man page changes

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14406

Signed-off-by: Isaac Boukris <iboukris@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(cherry picked from commit 4e51e832176a99f2a841c7a0d78fb0424f02956e)
---
 docs-xml/manpages/net.8.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs-xml/manpages/net.8.xml b/docs-xml/manpages/net.8.xml
index 69e18df8b6c..9b1d4458acc 100644
--- a/docs-xml/manpages/net.8.xml
+++ b/docs-xml/manpages/net.8.xml
@@ -470,7 +470,7 @@ joining the domain.
 </para>
 
 <para>
-[FQDN] (ADS only) set the dnsHosName attribute during the join.
+[FQDN] (ADS only) set the dnsHostName attribute during the join.
 The default format is netbiosname.dnsdomain.
 </para>
 
-- 
2.29.2


From a5a7dac759c2570861732c68efefb62371a29565 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Tue, 16 Jun 2020 22:01:49 +0300
Subject: [PATCH 36/45] selftest: add tests for binary
 msDS-AdditionalDnsHostName

Like the short names added implicitly by Windows DC.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14406

Signed-off-by: Isaac Boukris <iboukris@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(cherry picked from commit 4605d7aec5caf494a23f2c9800d6689f710ffbce)
---
 selftest/knownfail.d/binary_addl_hostname |  3 +++
 testprogs/blackbox/test_net_ads.sh        | 22 ++++++++++++++++++++++
 2 files changed, 25 insertions(+)
 create mode 100644 selftest/knownfail.d/binary_addl_hostname

diff --git a/selftest/knownfail.d/binary_addl_hostname b/selftest/knownfail.d/binary_addl_hostname
new file mode 100644
index 00000000000..559db1df507
--- /dev/null
+++ b/selftest/knownfail.d/binary_addl_hostname
@@ -0,0 +1,3 @@
+^samba4.blackbox.net_ads.dns alias1 check keytab
+^samba4.blackbox.net_ads.dns alias2 check keytab
+^samba4.blackbox.net_ads.addl short check keytab
diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh
index 85257f445d8..eef4a31a6a7 100755
--- a/testprogs/blackbox/test_net_ads.sh
+++ b/testprogs/blackbox/test_net_ads.sh
@@ -41,6 +41,11 @@ if [ -x "$BINDIR/ldbdel" ]; then
 	ldbdel="$BINDIR/ldbdel"
 fi
 
+ldbmodify="ldbmodify"
+if [ -x "$BINDIR/ldbmodify" ]; then
+	ldbmodify="$BINDIR/ldbmodify"
+fi
+
 # Load test functions
 . `dirname $0`/subunit.sh
 
@@ -217,12 +222,29 @@ testit_grep "dns alias SPN" $dns_alias2 $VALGRIND $net_tool ads search -P samacc
 testit_grep "dns alias addl" $dns_alias1 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ msDS-AdditionalDnsHostName || failed=`expr $failed + 1`
 testit_grep "dns alias addl" $dns_alias2 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ msDS-AdditionalDnsHostName || failed=`expr $failed + 1`
 
+# Test binary msDS-AdditionalDnsHostName like ones added by Windows DC
+short_alias_file="$PREFIX_ABS/short_alias_file"
+printf 'short_alias\0$' > $short_alias_file
+cat > $PREFIX_ABS/tmpldbmodify <<EOF
+dn: CN=$HOSTNAME,$computers_dn
+changetype: modify
+add: msDS-AdditionalDnsHostName
+msDS-AdditionalDnsHostName:< file://$short_alias_file
+EOF
+
+testit "add binary msDS-AdditionalDnsHostName" $VALGRIND $ldbmodify -k yes -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER.$REALM $PREFIX_ABS/tmpldbmodify || failed=`expr $failed + 1`
+
+testit_grep "addl short alias" short_alias $ldbsearch --show-binary -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER.$REALM -s base -b "CN=$HOSTNAME,CN=Computers,$base_dn" msDS-AdditionalDnsHostName || failed=`expr $failed + 1`
+
+rm -f $PREFIX_ABS/tmpldbmodify $short_alias_file
+
 dedicated_keytab_file="$PREFIX_ABS/test_dns_aliases_dedicated_krb5.keytab"
 
 testit "dns alias create_keytab" $VALGRIND $net_tool ads keytab create --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
 
 testit_grep "dns alias1 check keytab" "host/${dns_alias1}@$REALM" $net_tool ads keytab list --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
 testit_grep "dns alias2 check keytab" "host/${dns_alias2}@$REALM" $net_tool ads keytab list --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
+testit_grep "addl short check keytab" "host/short_alias@$REALM" $net_tool ads keytab list --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
 
 rm -f $dedicated_keytab_file
 
-- 
2.29.2


From 2769976aaa13474d2b5ee7b58ee17d5824dfa5a2 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Thu, 11 Jun 2020 16:51:27 +0300
Subject: [PATCH 37/45] Properly handle msDS-AdditionalDnsHostName returned
 from Windows DC

Windows DC adds short names for each specified msDS-AdditionalDnsHostName
attribute, but these have a suffix of "\0$" and thus fail with
ldap_get_values(), use ldap_get_values_len() instead.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14406

Signed-off-by: Isaac Boukris <iboukris@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>

Autobuild-User(master): Isaac Boukris <iboukris@samba.org>
Autobuild-Date(master): Thu Jun 18 16:43:47 UTC 2020 on sn-devel-184

(cherry picked from commit 9a447fb7e0701bf8b2fd922aed44d89f40420251)
---
 selftest/knownfail.d/binary_addl_hostname |  3 --
 source3/libads/ldap.c                     | 38 +++++++++++++++++++++--
 2 files changed, 35 insertions(+), 6 deletions(-)
 delete mode 100644 selftest/knownfail.d/binary_addl_hostname

diff --git a/selftest/knownfail.d/binary_addl_hostname b/selftest/knownfail.d/binary_addl_hostname
deleted file mode 100644
index 559db1df507..00000000000
--- a/selftest/knownfail.d/binary_addl_hostname
+++ /dev/null
@@ -1,3 +0,0 @@
-^samba4.blackbox.net_ads.dns alias1 check keytab
-^samba4.blackbox.net_ads.dns alias2 check keytab
-^samba4.blackbox.net_ads.addl short check keytab
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 02a628ee0e6..2684bba63ec 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -3664,6 +3664,40 @@ out:
 /********************************************************************
 ********************************************************************/
 
+static char **get_addl_hosts(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+			      LDAPMessage *msg, size_t *num_values)
+{
+	const char *field = "msDS-AdditionalDnsHostName";
+	struct berval **values = NULL;
+	char **ret = NULL;
+	size_t i, converted_size;
+
+	values = ldap_get_values_len(ads->ldap.ld, msg, field);
+	if (values == NULL) {
+		return NULL;
+	}
+
+	*num_values = ldap_count_values_len(values);
+
+	ret = talloc_array(mem_ctx, char *, *num_values + 1);
+	if (ret == NULL) {
+		ldap_value_free_len(values);
+		return NULL;
+	}
+
+	for (i = 0; i < *num_values; i++) {
+		if (!pull_utf8_talloc(mem_ctx, &ret[i], values[i]->bv_val,
+				      &converted_size)) {
+			ldap_value_free_len(values);
+			return NULL;
+		}
+	}
+	ret[i] = NULL;
+
+	ldap_value_free_len(values);
+	return ret;
+}
+
 ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx,
 					    ADS_STRUCT *ads,
 					    const char *machine_name,
@@ -3689,9 +3723,7 @@ ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx,
 		goto done;
 	}
 
-	*hostnames_array = ads_pull_strings(ads, mem_ctx, res,
-					    "msDS-AdditionalDnsHostName",
-					    num_hostnames);
+	*hostnames_array = get_addl_hosts(ads, mem_ctx, res, num_hostnames);
 	if (*hostnames_array == NULL) {
 		DEBUG(1, ("Host account for %s does not have msDS-AdditionalDnsHostName.\n",
 			  machine_name));
-- 
2.29.2


From 9727953d482a3849d4ac1f40486bc567f6b77067 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Sat, 20 Jun 2020 17:17:33 +0200
Subject: [PATCH 38/45] Fix usage of ldap_get_values_len for
 msDS-AdditionalDnsHostName

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14406

Signed-off-by: Isaac Boukris <iboukris@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>

Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org>
Autobuild-Date(master): Mon Jun 22 09:59:04 UTC 2020 on sn-devel-184

(cherry picked from commit f9dd67355ba35539d7ae1774d5135fd05d747b3f)
---
 source3/libads/ldap.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 2684bba63ec..d1ce9cee2f0 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -3686,8 +3686,12 @@ static char **get_addl_hosts(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
 	}
 
 	for (i = 0; i < *num_values; i++) {
-		if (!pull_utf8_talloc(mem_ctx, &ret[i], values[i]->bv_val,
-				      &converted_size)) {
+		ret[i] = NULL;
+		if (!convert_string_talloc(mem_ctx, CH_UTF8, CH_UNIX,
+					   values[i]->bv_val,
+					   strnlen(values[i]->bv_val,
+						   values[i]->bv_len),
+					   &ret[i], &converted_size)) {
 			ldap_value_free_len(values);
 			return NULL;
 		}
-- 
2.29.2


From ec4cfe786d8c3cb67bb0e9224ae1822902c672d3 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Tue, 15 Dec 2020 15:17:04 +0100
Subject: [PATCH 39/45] HACK:s3:winbind: Rely on the domain child for online
 check

---
 source3/winbindd/winbindd_cm.c   | 9 +++++++++
 source3/winbindd/winbindd_dual.c | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index 4bd03ed8b7a..502331f7260 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -89,6 +89,8 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
+extern bool wb_idmap_child;
+
 struct dc_name_ip {
 	fstring name;
 	struct sockaddr_storage ss;
@@ -176,6 +178,13 @@ static void msg_try_to_go_online(struct messaging_context *msg,
 				continue;
 			}
 
+			if (wb_child_domain() == NULL && !wb_idmap_child) {
+				DEBUG(5,("msg_try_to_go_online: domain %s "
+					"NOT CONNECTING IN MAIN PROCESS.\n", domainname));
+				domain->online = true;
+				continue;
+			}
+
 			/* This call takes care of setting the online
 			   flag to true if we connected, or re-adding
 			   the offline handler if false. Bypasses online
diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c
index 6e3277e5529..35b76a367aa 100644
--- a/source3/winbindd/winbindd_dual.c
+++ b/source3/winbindd/winbindd_dual.c
@@ -1612,6 +1612,8 @@ static void child_handler(struct tevent_context *ev, struct tevent_fd *fde,
 	}
 }
 
+bool wb_idmap_child;
+
 static bool fork_domain_child(struct winbindd_child *child)
 {
 	int fdpair[2];
@@ -1715,6 +1717,7 @@ static bool fork_domain_child(struct winbindd_child *child)
 		setproctitle("domain child [%s]", child_domain->name);
 	} else if (child == idmap_child()) {
 		setproctitle("idmap child");
+		wb_idmap_child = true;
 	}
 
 	/* Handle online/offline messages. */
-- 
2.29.2


From 958bed1a1e5c9f334a1859bef14f4fe1657c3e49 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Wed, 9 Sep 2020 16:00:52 +0200
Subject: [PATCH 40/45] s3:smbd: Use fsp al the talloc memory context

Somehow the lck pointer gets freed before we call TALLOC_FREE().

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>
Reviewed-by: Alexander Bokovoy <ab@samba.org>
---
 source3/smbd/open.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index de557f53a20..9a24e331ab1 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -4239,7 +4239,7 @@ static NTSTATUS open_directory(connection_struct *conn,
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
-	lck = get_share_mode_lock(talloc_tos(), fsp->file_id,
+	lck = get_share_mode_lock(fsp, fsp->file_id,
 				  conn->connectpath, smb_dname,
 				  &mtimespec);
 
-- 
2.29.2


From 2591ae5d6a1dbd71391801b7bdf20bd37c8e8375 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Wed, 3 Feb 2021 12:58:31 +0100
Subject: [PATCH 41/45] Revert "s3:smbd: Use fsp al the talloc memory context"

This reverts commit 958bed1a1e5c9f334a1859bef14f4fe1657c3e49.
---
 source3/smbd/open.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 9a24e331ab1..de557f53a20 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -4239,7 +4239,7 @@ static NTSTATUS open_directory(connection_struct *conn,
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
-	lck = get_share_mode_lock(fsp, fsp->file_id,
+	lck = get_share_mode_lock(talloc_tos(), fsp->file_id,
 				  conn->connectpath, smb_dname,
 				  &mtimespec);
 
-- 
2.29.2


From 2438619ec7ef18816f6b92c87a094851223d2bb1 Mon Sep 17 00:00:00 2001
From: Khem Raj <raj.khem@gmail.com>
Date: Wed, 22 Jul 2020 22:42:09 -0700
Subject: [PATCH 42/45] nsswitch/nsstest.c: Avoid nss function conflicts with
 glibc nss.h

glibc 2.32 will define these varibles [1] which results in conflicts
with these static function names, therefore prefix these function names
with samba_ to avoid it

[1] https://sourceware.org/git/?p=glibc.git;a=commit;h=499a92df8b9fc64a054cf3b7f728f8967fc1da7d

Signed-off-by: Khem Raj <raj.khem@gmail.com>
Reviewed-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Noel Power <npower@samba.org>

Autobuild-User(master): Noel Power <npower@samba.org>
Autobuild-Date(master): Tue Jul 28 10:52:00 UTC 2020 on sn-devel-184

(cherry picked from commit 6e496aa3635557b59792e469f7c7f8eccd822322)
---
 nsswitch/nsstest.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/nsswitch/nsstest.c b/nsswitch/nsstest.c
index 6d92806cffc..46f96795f39 100644
--- a/nsswitch/nsstest.c
+++ b/nsswitch/nsstest.c
@@ -137,7 +137,7 @@ static struct passwd *nss_getpwuid(uid_t uid)
 	return &pwd;
 }
 
-static void nss_setpwent(void)
+static void samba_nss_setpwent(void)
 {
 	NSS_STATUS (*_nss_setpwent)(void) =
 		(NSS_STATUS(*)(void))find_fn("setpwent");
@@ -152,7 +152,7 @@ static void nss_setpwent(void)
 	}
 }
 
-static void nss_endpwent(void)
+static void samba_nss_endpwent(void)
 {
 	NSS_STATUS (*_nss_endpwent)(void) =
 		(NSS_STATUS (*)(void))find_fn("endpwent");
@@ -284,7 +284,7 @@ again:
 	return &grp;
 }
 
-static void nss_setgrent(void)
+static void samba_nss_setgrent(void)
 {
 	NSS_STATUS (*_nss_setgrent)(void) =
 		(NSS_STATUS (*)(void))find_fn("setgrent");
@@ -299,7 +299,7 @@ static void nss_setgrent(void)
 	}
 }
 
-static void nss_endgrent(void)
+static void samba_nss_endgrent(void)
 {
 	NSS_STATUS (*_nss_endgrent)(void) =
 		(NSS_STATUS (*)(void))find_fn("endgrent");
@@ -396,7 +396,7 @@ static void nss_test_users(void)
 {
 	struct passwd *pwd;
 
-	nss_setpwent();
+	samba_nss_setpwent();
 	/* loop over all users */
 	while ((pwd = nss_getpwent())) {
 		printf("Testing user %s\n", pwd->pw_name);
@@ -418,14 +418,14 @@ static void nss_test_users(void)
 		printf("initgroups: "); nss_test_initgroups(pwd->pw_name, pwd->pw_gid);
 		printf("\n");
 	}
-	nss_endpwent();
+	samba_nss_endpwent();
 }
 
 static void nss_test_groups(void)
 {
 	struct group *grp;
 
-	nss_setgrent();
+	samba_nss_setgrent();
 	/* loop over all groups */
 	while ((grp = nss_getgrent())) {
 		printf("Testing group %s\n", grp->gr_name);
@@ -446,7 +446,7 @@ static void nss_test_groups(void)
 		printf("getgrgid: "); print_group(grp);
 		printf("\n");
 	}
-	nss_endgrent();
+	samba_nss_endgrent();
 }
 
 static void nss_test_errors(void)
-- 
2.29.2


From d5410b038bb3b1d31783c0d825dc933497f6eeaa Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Wed, 3 Feb 2021 10:30:08 +0100
Subject: [PATCH 43/45] lib:util: Add basic memcache unit test

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14625

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
(cherry picked from commit bebbf621d6052f797c5cf19a2a9bbc13e699d3f0)
---
 lib/util/tests/test_memcache.c | 122 +++++++++++++++++++++++++++++++++
 lib/util/wscript_build         |   6 ++
 selftest/tests.py              |   2 +
 3 files changed, 130 insertions(+)
 create mode 100644 lib/util/tests/test_memcache.c

diff --git a/lib/util/tests/test_memcache.c b/lib/util/tests/test_memcache.c
new file mode 100644
index 00000000000..8ea5e5b042e
--- /dev/null
+++ b/lib/util/tests/test_memcache.c
@@ -0,0 +1,122 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2021      Andreas Schneider <asn@samba.org>
+ *
+ * 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/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/util/memcache.h"
+
+static int setup_talloc_context(void **state)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	*state = frame;
+	return 0;
+}
+
+static int teardown_talloc_context(void **state)
+{
+	TALLOC_CTX *frame = *state;
+	TALLOC_FREE(frame);
+	return 0;
+}
+
+static void torture_memcache_init(void **state)
+{
+	TALLOC_CTX *mem_ctx = *state;
+	struct memcache *cache = NULL;
+
+	cache = memcache_init(mem_ctx, 0);
+	assert_non_null(cache);
+
+	TALLOC_FREE(cache);
+
+	cache = memcache_init(mem_ctx, 10);
+	assert_non_null(cache);
+
+	TALLOC_FREE(cache);
+}
+
+static void torture_memcache_add_lookup_delete(void **state)
+{
+	TALLOC_CTX *mem_ctx = *state;
+	struct memcache *cache = NULL;
+	DATA_BLOB key1, key2;
+	char *path1 = NULL, *path2 = NULL;
+
+	cache = memcache_init(mem_ctx, 0);
+	assert_non_null(cache);
+
+	key1 = data_blob_const("key1", 4);
+	path1 = talloc_strdup(mem_ctx, "/tmp/one");
+	assert_non_null(path1);
+
+	key2 = data_blob_const("key2", 4);
+	path2 = talloc_strdup(mem_ctx, "/tmp/two");
+	assert_non_null(path1);
+
+	memcache_add_talloc(cache, GETWD_CACHE, key1, &path1);
+	assert_null(path1);
+
+	memcache_add_talloc(cache, GETWD_CACHE, key2, &path2);
+	assert_null(path2);
+
+	path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1);
+	assert_non_null(path1);
+	assert_string_equal(path1, "/tmp/one");
+
+	path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2);
+	assert_non_null(path2);
+	assert_string_equal(path2, "/tmp/two");
+
+	memcache_delete(cache, GETWD_CACHE, key1);
+	path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1);
+	assert_null(path1);
+
+	memcache_flush(cache, GETWD_CACHE);
+	path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2);
+	assert_null(path2);
+
+	TALLOC_FREE(cache);
+}
+
+int main(int argc, char *argv[])
+{
+	int rc;
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test(torture_memcache_init),
+		cmocka_unit_test(torture_memcache_add_lookup_delete),
+	};
+
+	if (argc == 2) {
+		cmocka_set_test_filter(argv[1]);
+	}
+	cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+	rc = cmocka_run_group_tests(tests,
+				    setup_talloc_context,
+				    teardown_talloc_context);
+
+	return rc;
+}
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
index fd3027eff77..229dbd5ef6a 100644
--- a/lib/util/wscript_build
+++ b/lib/util/wscript_build
@@ -256,3 +256,9 @@ else:
                      deps='cmocka replace talloc samba-util',
                      local_include=False,
                      install=False)
+
+    bld.SAMBA_BINARY('test_memcache',
+                     source='tests/test_memcache.c',
+                     deps='cmocka replace talloc samba-util',
+                     local_include=False,
+                     install=False)
diff --git a/selftest/tests.py b/selftest/tests.py
index e7639c4da27..e3f7d9acb4a 100644
--- a/selftest/tests.py
+++ b/selftest/tests.py
@@ -254,6 +254,8 @@ plantestsuite("samba.unittests.ms_fnmatch", "none",
               [os.path.join(bindir(), "default/lib/util/test_ms_fnmatch")])
 plantestsuite("samba.unittests.util_paths", "none",
               [os.path.join(bindir(), "default/lib/util/test_util_paths")])
+plantestsuite("samba.unittests.memcache", "none",
+              [os.path.join(bindir(), "default/lib/util/test_memcache")])
 plantestsuite("samba.unittests.ntlm_check", "none",
               [os.path.join(bindir(), "default/libcli/auth/test_ntlm_check")])
 plantestsuite("samba.unittests.test_registry_regfio", "none",
-- 
2.29.2


From 7f6661b3c60319073d7fd58906b9a3728f421fed Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Wed, 3 Feb 2021 10:37:12 +0100
Subject: [PATCH 44/45] lib:util: Add cache oversize test for memcache

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14625

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
(cherry picked from commit 00543ab3b29e3fbfe8314e51919629803e14ede6)
---
 lib/util/tests/test_memcache.c | 39 ++++++++++++++++++++++++++++++++++
 selftest/knownfail.d/memcache  |  1 +
 2 files changed, 40 insertions(+)
 create mode 100644 selftest/knownfail.d/memcache

diff --git a/lib/util/tests/test_memcache.c b/lib/util/tests/test_memcache.c
index 8ea5e5b042e..8a3997817c1 100644
--- a/lib/util/tests/test_memcache.c
+++ b/lib/util/tests/test_memcache.c
@@ -98,6 +98,44 @@ static void torture_memcache_add_lookup_delete(void **state)
 	path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2);
 	assert_null(path2);
 
+	TALLOC_FREE(path1);
+	TALLOC_FREE(path2);
+	TALLOC_FREE(cache);
+}
+
+static void torture_memcache_add_oversize(void **state)
+{
+	TALLOC_CTX *mem_ctx = *state;
+	struct memcache *cache = NULL;
+	DATA_BLOB key1, key2;
+	char *path1 = NULL, *path2 = NULL;
+
+	cache = memcache_init(mem_ctx, 10);
+	assert_non_null(cache);
+
+	key1 = data_blob_const("key1", 4);
+	path1 = talloc_strdup(mem_ctx, "/tmp/one");
+	assert_non_null(path1);
+
+	key2 = data_blob_const("key2", 4);
+	path2 = talloc_strdup(mem_ctx, "/tmp/two");
+	assert_non_null(path1);
+
+	memcache_add_talloc(cache, GETWD_CACHE, key1, &path1);
+	assert_null(path1);
+
+	memcache_add_talloc(cache, GETWD_CACHE, key2, &path2);
+	assert_null(path2);
+
+	path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1);
+	assert_null(path1);
+
+	path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2);
+	assert_non_null(path2);
+	assert_string_equal(path2, "/tmp/two");
+
+	TALLOC_FREE(path1);
+	TALLOC_FREE(path2);
 	TALLOC_FREE(cache);
 }
 
@@ -107,6 +145,7 @@ int main(int argc, char *argv[])
 	const struct CMUnitTest tests[] = {
 		cmocka_unit_test(torture_memcache_init),
 		cmocka_unit_test(torture_memcache_add_lookup_delete),
+		cmocka_unit_test(torture_memcache_add_oversize),
 	};
 
 	if (argc == 2) {
diff --git a/selftest/knownfail.d/memcache b/selftest/knownfail.d/memcache
new file mode 100644
index 00000000000..0a74ace3003
--- /dev/null
+++ b/selftest/knownfail.d/memcache
@@ -0,0 +1 @@
+^samba.unittests.memcache.torture_memcache_add_oversize
-- 
2.29.2


From 53c7f00510556aea15b640254934e514c1d88c25 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Tue, 2 Feb 2021 18:10:38 +0100
Subject: [PATCH 45/45] lib:util: Avoid free'ing our own pointer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14625

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>

Autobuild-User(master): Ralph Böhme <slow@samba.org>
Autobuild-Date(master): Wed Feb  3 10:57:01 UTC 2021 on sn-devel-184

(cherry picked from commit 0bdbe50fac680be3fe21043246b8c75005611351)
---
 lib/util/memcache.c           | 19 +++++++++++++++----
 selftest/knownfail.d/memcache |  1 -
 2 files changed, 15 insertions(+), 5 deletions(-)
 delete mode 100644 selftest/knownfail.d/memcache

diff --git a/lib/util/memcache.c b/lib/util/memcache.c
index 1e616bd0e9a..7b0b27eaddb 100644
--- a/lib/util/memcache.c
+++ b/lib/util/memcache.c
@@ -223,14 +223,25 @@ static void memcache_delete_element(struct memcache *cache,
 	TALLOC_FREE(e);
 }
 
-static void memcache_trim(struct memcache *cache)
+static void memcache_trim(struct memcache *cache, struct memcache_element *e)
 {
+	struct memcache_element *tail = NULL;
+
 	if (cache->max_size == 0) {
 		return;
 	}
 
-	while ((cache->size > cache->max_size) && DLIST_TAIL(cache->mru)) {
-		memcache_delete_element(cache, DLIST_TAIL(cache->mru));
+	for (tail = DLIST_TAIL(cache->mru);
+	     (cache->size > cache->max_size) && (tail != NULL);
+	     tail = DLIST_TAIL(cache->mru))
+	{
+		if (tail == e) {
+			tail = DLIST_PREV(tail);
+			if (tail == NULL) {
+				break;
+			}
+		}
+		memcache_delete_element(cache, tail);
 	}
 }
 
@@ -351,7 +362,7 @@ void memcache_add(struct memcache *cache, enum memcache_number n,
 		memcpy(&mtv, cache_value.data, sizeof(mtv));
 		cache->size += mtv.len;
 	}
-	memcache_trim(cache);
+	memcache_trim(cache, e);
 }
 
 void memcache_add_talloc(struct memcache *cache, enum memcache_number n,
diff --git a/selftest/knownfail.d/memcache b/selftest/knownfail.d/memcache
deleted file mode 100644
index 0a74ace3003..00000000000
--- a/selftest/knownfail.d/memcache
+++ /dev/null
@@ -1 +0,0 @@
-^samba.unittests.memcache.torture_memcache_add_oversize
-- 
2.29.2