801d0a
From 0d1179d5c3585678e6b4097425a4137b8666d333 Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Thu, 8 Aug 2019 14:35:38 +0200
801d0a
Subject: [PATCH 01/11] testprogs: Fix failure count in test_net_ads.sh
801d0a
801d0a
There are missing ` at the end of the line.
801d0a
801d0a
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13884
801d0a
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
(cherry picked from commit 320b5be4dce95d8dac4b3c0847faf5b730754a37)
801d0a
---
801d0a
 testprogs/blackbox/test_net_ads.sh | 4 ++--
801d0a
 1 file changed, 2 insertions(+), 2 deletions(-)
801d0a
801d0a
diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh
801d0a
index d3c4de5b741..512aa9d2952 100755
801d0a
--- a/testprogs/blackbox/test_net_ads.sh
801d0a
+++ b/testprogs/blackbox/test_net_ads.sh
801d0a
@@ -141,10 +141,10 @@ testit "test spn service doensn't exist in AD but is present in keytab file afte
801d0a
 # SPN parser is very basic but does detect some illegal combination
801d0a
 
801d0a
 windows_spn="$spn_service/$spn_host:"
801d0a
-testit_expect_failure "test (dedicated keytab) fail to parse windows spn with missing port" $VALGRIND $net_tool ads keytab add $windows_spn -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1
801d0a
+testit_expect_failure "test (dedicated keytab) fail to parse windows spn with missing port" $VALGRIND $net_tool ads keytab add $windows_spn -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
801d0a
 
801d0a
 windows_spn="$spn_service/$spn_host/"
801d0a
-testit_expect_failure "test (dedicated keytab) fail to parse windows spn with missing servicename" $VALGRIND $net_tool ads keytab add $windows_spn -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1
801d0a
+testit_expect_failure "test (dedicated keytab) fail to parse windows spn with missing servicename" $VALGRIND $net_tool ads keytab add $windows_spn -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1`
801d0a
 
801d0a
 testit "changetrustpw (dedicated keytab)" $VALGRIND $net_tool ads changetrustpw || failed=`expr $failed + 1`
801d0a
 
801d0a
-- 
801d0a
2.23.0
801d0a
801d0a
801d0a
From 5acc6ededece33202fe3aa26cb9de9c052e32ba2 Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Tue, 13 Aug 2019 17:06:58 +0200
801d0a
Subject: [PATCH 02/11] s3:libads: Use ldap_add_ext_s() in ads_gen_add()
801d0a
801d0a
ldap_add_s() is marked as deprecated.
801d0a
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
(cherry picked from commit 456322a61319a10aaedda5244488ea4e5aa5cb64)
801d0a
---
801d0a
 source3/libads/ldap.c | 2 +-
801d0a
 1 file changed, 1 insertion(+), 1 deletion(-)
801d0a
801d0a
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
801d0a
index 8d13a7cf18c..d409d4ab78e 100644
801d0a
--- a/source3/libads/ldap.c
801d0a
+++ b/source3/libads/ldap.c
801d0a
@@ -1596,7 +1596,7 @@ ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods)
801d0a
 	/* make sure the end of the list is NULL */
801d0a
 	mods[i] = NULL;
801d0a
 
801d0a
-	ret = ldap_add_s(ads->ldap.ld, utf8_dn, (LDAPMod**)mods);
801d0a
+	ret = ldap_add_ext_s(ads->ldap.ld, utf8_dn, (LDAPMod**)mods, NULL, NULL);
801d0a
 	ads_print_error(ret, ads->ldap.ld);
801d0a
 	TALLOC_FREE(utf8_dn);
801d0a
 	return ADS_ERROR(ret);
801d0a
-- 
801d0a
2.23.0
801d0a
801d0a
801d0a
From 17d370a97ee2c7e6359aafc0248efae90c654857 Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Tue, 13 Aug 2019 17:41:40 +0200
801d0a
Subject: [PATCH 03/11] s3:libnet: Require sealed LDAP SASL connections for
801d0a
 joining
801d0a
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
(cherry picked from commit b84abb3a46211dc84e52ef95750627e4dd081f2f)
801d0a
---
801d0a
 libgpo/pygpo.c                     |  2 +-
801d0a
 source3/lib/netapi/joindomain.c    |  5 ++++-
801d0a
 source3/libads/ads_proto.h         |  9 ++++++++-
801d0a
 source3/libads/ads_struct.c        | 14 +++++++++++++-
801d0a
 source3/libads/ldap.c              |  4 ++--
801d0a
 source3/libnet/libnet_join.c       |  3 ++-
801d0a
 source3/libsmb/namequery_dc.c      |  2 +-
801d0a
 source3/printing/nt_printing_ads.c |  6 +++---
801d0a
 source3/utils/net_ads.c            | 13 +++++++++----
801d0a
 source3/winbindd/winbindd_ads.c    |  5 ++++-
801d0a
 source3/winbindd/winbindd_cm.c     |  5 ++++-
801d0a
 11 files changed, 51 insertions(+), 17 deletions(-)
801d0a
801d0a
diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c
801d0a
index cd107318860..4db8cad7ca4 100644
801d0a
--- a/libgpo/pygpo.c
801d0a
+++ b/libgpo/pygpo.c
801d0a
@@ -212,7 +212,7 @@ static int py_ads_init(ADS *self, PyObject *args, PyObject *kwds)
801d0a
 		return -1;
801d0a
 	}
801d0a
 
801d0a
-	self->ads_ptr = ads_init(realm, workgroup, ldap_server);
801d0a
+	self->ads_ptr = ads_init(realm, workgroup, ldap_server, ADS_SASL_PLAIN);
801d0a
 	if (self->ads_ptr == NULL) {
801d0a
 		return -1;
801d0a
 	}
801d0a
diff --git a/source3/lib/netapi/joindomain.c b/source3/lib/netapi/joindomain.c
801d0a
index ff2154ba803..8d0752f4531 100644
801d0a
--- a/source3/lib/netapi/joindomain.c
801d0a
+++ b/source3/lib/netapi/joindomain.c
801d0a
@@ -411,7 +411,10 @@ WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
801d0a
 
801d0a
 	dc = strip_hostname(info->dc_unc);
801d0a
 
801d0a
-	ads = ads_init(info->domain_name, info->domain_name, dc);
801d0a
+	ads = ads_init(info->domain_name,
801d0a
+		       info->domain_name,
801d0a
+		       dc,
801d0a
+		       ADS_SASL_PLAIN);
801d0a
 	if (!ads) {
801d0a
 		return WERR_GEN_FAILURE;
801d0a
 	}
801d0a
diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h
801d0a
index 154bf67f964..92bb3a22cdb 100644
801d0a
--- a/source3/libads/ads_proto.h
801d0a
+++ b/source3/libads/ads_proto.h
801d0a
@@ -32,6 +32,12 @@
801d0a
 #ifndef _LIBADS_ADS_PROTO_H_
801d0a
 #define _LIBADS_ADS_PROTO_H_
801d0a
 
801d0a
+enum ads_sasl_state_e {
801d0a
+	ADS_SASL_PLAIN = 0,
801d0a
+	ADS_SASL_SIGN,
801d0a
+	ADS_SASL_SEAL,
801d0a
+};
801d0a
+
801d0a
 /* The following definitions come from libads/ads_struct.c  */
801d0a
 
801d0a
 char *ads_build_path(const char *realm, const char *sep, const char *field, int reverse);
801d0a
@@ -39,7 +45,8 @@ char *ads_build_dn(const char *realm);
801d0a
 char *ads_build_domain(const char *dn);
801d0a
 ADS_STRUCT *ads_init(const char *realm,
801d0a
 		     const char *workgroup,
801d0a
-		     const char *ldap_server);
801d0a
+		     const char *ldap_server,
801d0a
+		     enum ads_sasl_state_e sasl_state);
801d0a
 bool ads_set_sasl_wrap_flags(ADS_STRUCT *ads, int flags);
801d0a
 void ads_destroy(ADS_STRUCT **ads);
801d0a
 
801d0a
diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c
801d0a
index 3ab682c0e38..043a1b21247 100644
801d0a
--- a/source3/libads/ads_struct.c
801d0a
+++ b/source3/libads/ads_struct.c
801d0a
@@ -132,7 +132,8 @@ char *ads_build_domain(const char *dn)
801d0a
 */
801d0a
 ADS_STRUCT *ads_init(const char *realm, 
801d0a
 		     const char *workgroup,
801d0a
-		     const char *ldap_server)
801d0a
+		     const char *ldap_server,
801d0a
+		     enum ads_sasl_state_e sasl_state)
801d0a
 {
801d0a
 	ADS_STRUCT *ads;
801d0a
 	int wrap_flags;
801d0a
@@ -152,6 +153,17 @@ ADS_STRUCT *ads_init(const char *realm,
801d0a
 		wrap_flags = 0;
801d0a
 	}
801d0a
 
801d0a
+	switch (sasl_state) {
801d0a
+	case ADS_SASL_PLAIN:
801d0a
+		break;
801d0a
+	case ADS_SASL_SIGN:
801d0a
+		wrap_flags |= ADS_AUTH_SASL_SIGN;
801d0a
+		break;
801d0a
+	case ADS_SASL_SEAL:
801d0a
+		wrap_flags |= ADS_AUTH_SASL_SEAL;
801d0a
+		break;
801d0a
+	}
801d0a
+
801d0a
 	ads->auth.flags = wrap_flags;
801d0a
 
801d0a
 	/* Start with the configured page size when the connection is new,
801d0a
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
801d0a
index d409d4ab78e..7bdda4b1768 100644
801d0a
--- a/source3/libads/ldap.c
801d0a
+++ b/source3/libads/ldap.c
801d0a
@@ -2964,7 +2964,7 @@ ADS_STATUS ads_current_time(ADS_STRUCT *ads)
801d0a
 
801d0a
 	if ( !ads->ldap.ld ) {
801d0a
 		if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup, 
801d0a
-			ads->server.ldap_server )) == NULL )
801d0a
+			ads->server.ldap_server, ADS_SASL_PLAIN )) == NULL )
801d0a
 		{
801d0a
 			status = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
 			goto done;
801d0a
@@ -3026,7 +3026,7 @@ ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32_t *val)
801d0a
 
801d0a
 	if ( !ads->ldap.ld ) {
801d0a
 		if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup, 
801d0a
-			ads->server.ldap_server )) == NULL )
801d0a
+			ads->server.ldap_server, ADS_SASL_PLAIN )) == NULL )
801d0a
 		{
801d0a
 			status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
801d0a
 			goto done;
801d0a
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
801d0a
index b876d7ea89f..a512afc238a 100644
801d0a
--- a/source3/libnet/libnet_join.c
801d0a
+++ b/source3/libnet/libnet_join.c
801d0a
@@ -140,7 +140,8 @@ static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
801d0a
 
801d0a
 	my_ads = ads_init(dns_domain_name,
801d0a
 			  netbios_domain_name,
801d0a
-			  dc_name);
801d0a
+			  dc_name,
801d0a
+			  ADS_SASL_SEAL);
801d0a
 	if (!my_ads) {
801d0a
 		return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
801d0a
 	}
801d0a
diff --git a/source3/libsmb/namequery_dc.c b/source3/libsmb/namequery_dc.c
801d0a
index 4ee5b5278e4..f63dde61603 100644
801d0a
--- a/source3/libsmb/namequery_dc.c
801d0a
+++ b/source3/libsmb/namequery_dc.c
801d0a
@@ -69,7 +69,7 @@ static bool ads_dc_name(const char *domain,
801d0a
 
801d0a
 	/* Try this 3 times then give up. */
801d0a
 	for( i =0 ; i < 3; i++) {
801d0a
-		ads = ads_init(realm, domain, NULL);
801d0a
+		ads = ads_init(realm, domain, NULL, ADS_SASL_PLAIN);
801d0a
 		if (!ads) {
801d0a
 			TALLOC_FREE(sitename);
801d0a
 			return False;
801d0a
diff --git a/source3/printing/nt_printing_ads.c b/source3/printing/nt_printing_ads.c
801d0a
index 2588e1de7e7..a82f1361fc8 100644
801d0a
--- a/source3/printing/nt_printing_ads.c
801d0a
+++ b/source3/printing/nt_printing_ads.c
801d0a
@@ -227,7 +227,7 @@ WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer,
801d0a
 		return WERR_NOT_ENOUGH_MEMORY;
801d0a
 	}
801d0a
 
801d0a
-	ads = ads_init(lp_realm(), lp_workgroup(), NULL);
801d0a
+	ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN);
801d0a
 	if (ads == NULL) {
801d0a
 		result = WERR_RPC_S_SERVER_UNAVAILABLE;
801d0a
 		goto out;
801d0a
@@ -577,7 +577,7 @@ WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
801d0a
 
801d0a
 	TALLOC_FREE(sinfo2);
801d0a
 
801d0a
-	ads = ads_init(lp_realm(), lp_workgroup(), NULL);
801d0a
+	ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN);
801d0a
 	if (!ads) {
801d0a
 		DEBUG(3, ("ads_init() failed\n"));
801d0a
 		win_rc = WERR_RPC_S_SERVER_UNAVAILABLE;
801d0a
@@ -633,7 +633,7 @@ WERROR check_published_printers(struct messaging_context *msg_ctx)
801d0a
 	tmp_ctx = talloc_new(NULL);
801d0a
 	if (!tmp_ctx) return WERR_NOT_ENOUGH_MEMORY;
801d0a
 
801d0a
-	ads = ads_init(lp_realm(), lp_workgroup(), NULL);
801d0a
+	ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN);
801d0a
 	if (!ads) {
801d0a
 		DEBUG(3, ("ads_init() failed\n"));
801d0a
 		return WERR_RPC_S_SERVER_UNAVAILABLE;
801d0a
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
801d0a
index d33031a0dbd..07a22098fb1 100644
801d0a
--- a/source3/utils/net_ads.c
801d0a
+++ b/source3/utils/net_ads.c
801d0a
@@ -620,7 +620,10 @@ retry_connect:
801d0a
 		realm = assume_own_realm(c);
801d0a
 	}
801d0a
 
801d0a
-	ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
801d0a
+	ads = ads_init(realm,
801d0a
+			c->opt_target_workgroup,
801d0a
+			c->opt_host,
801d0a
+			ADS_SASL_PLAIN);
801d0a
 
801d0a
 	if (!c->opt_user_name) {
801d0a
 		c->opt_user_name = "administrator";
801d0a
@@ -729,7 +732,8 @@ static int net_ads_check_int(const char *realm, const char *workgroup, const cha
801d0a
 	ADS_STRUCT *ads;
801d0a
 	ADS_STATUS status;
801d0a
 
801d0a
-	if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
801d0a
+	ads = ads_init(realm, workgroup, host, ADS_SASL_PLAIN);
801d0a
+	if (ads == NULL ) {
801d0a
 		return -1;
801d0a
 	}
801d0a
 
801d0a
@@ -1764,7 +1768,7 @@ static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, st
801d0a
 	 * kinit with the machine password to do dns update.
801d0a
 	 */
801d0a
 
801d0a
-	ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
801d0a
+	ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name, ADS_SASL_PLAIN);
801d0a
 
801d0a
 	if (ads_dns == NULL) {
801d0a
 		d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
801d0a
@@ -2654,7 +2658,8 @@ static int net_ads_password(struct net_context *c, int argc, const char **argv)
801d0a
 
801d0a
 	/* use the realm so we can eventually change passwords for users
801d0a
 	in realms other than default */
801d0a
-	if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
801d0a
+	ads = ads_init(realm, c->opt_workgroup, c->opt_host, ADS_SASL_PLAIN);
801d0a
+	if (ads == NULL) {
801d0a
 		return -1;
801d0a
 	}
801d0a
 
801d0a
diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c
801d0a
index 922ca43764b..556b4523866 100644
801d0a
--- a/source3/winbindd/winbindd_ads.c
801d0a
+++ b/source3/winbindd/winbindd_ads.c
801d0a
@@ -110,7 +110,10 @@ static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
801d0a
 	/* we don't want this to affect the users ccache */
801d0a
 	setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
801d0a
 
801d0a
-	ads = ads_init(target_realm, target_dom_name, ldap_server);
801d0a
+	ads = ads_init(target_realm,
801d0a
+		       target_dom_name,
801d0a
+		       ldap_server,
801d0a
+		       ADS_SASL_SEAL);
801d0a
 	if (!ads) {
801d0a
 		DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
801d0a
 		return ADS_ERROR(LDAP_NO_MEMORY);
801d0a
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
801d0a
index 22d3dcaa92b..4bd03ed8b7a 100644
801d0a
--- a/source3/winbindd/winbindd_cm.c
801d0a
+++ b/source3/winbindd/winbindd_cm.c
801d0a
@@ -1414,7 +1414,10 @@ static bool dcip_check_name(TALLOC_CTX *mem_ctx,
801d0a
 
801d0a
 		print_sockaddr(addr, sizeof(addr), pss);
801d0a
 
801d0a
-		ads = ads_init(domain->alt_name, domain->name, addr);
801d0a
+		ads = ads_init(domain->alt_name,
801d0a
+			       domain->name,
801d0a
+			       addr,
801d0a
+			       ADS_SASL_PLAIN);
801d0a
 		ads->auth.flags |= ADS_AUTH_NO_BIND;
801d0a
 		ads->config.flags |= request_flags;
801d0a
 		ads->server.no_fallback = true;
801d0a
-- 
801d0a
2.23.0
801d0a
801d0a
801d0a
From 244ecd7d839340858e96d75118548942b44bbd5c Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Tue, 13 Aug 2019 16:30:07 +0200
801d0a
Subject: [PATCH 04/11] s3:libads: Cleanup error code paths in
801d0a
 ads_create_machine_acct()
801d0a
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
(cherry picked from commit 8ed993789f93624b7b60dd5314fe5472e69e903a)
801d0a
---
801d0a
 source3/libads/ldap.c | 34 +++++++++++++++++++++++-----------
801d0a
 1 file changed, 23 insertions(+), 11 deletions(-)
801d0a
801d0a
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
801d0a
index 7bdda4b1768..e492d0688a5 100644
801d0a
--- a/source3/libads/ldap.c
801d0a
+++ b/source3/libads/ldap.c
801d0a
@@ -2092,11 +2092,12 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 				   uint32_t etype_list)
801d0a
 {
801d0a
 	ADS_STATUS ret;
801d0a
-	char *samAccountName, *controlstr;
801d0a
-	TALLOC_CTX *ctx;
801d0a
+	char *samAccountName = NULL;
801d0a
+	char *controlstr = NULL;
801d0a
+	TALLOC_CTX *ctx = NULL;
801d0a
 	ADS_MODLIST mods;
801d0a
 	char *machine_escaped = NULL;
801d0a
-	char *new_dn;
801d0a
+	char *new_dn = NULL;
801d0a
 	const char *objectClass[] = {"top", "person", "organizationalPerson",
801d0a
 				     "user", "computer", NULL};
801d0a
 	LDAPMessage *res = NULL;
801d0a
@@ -2110,13 +2111,14 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 		return ret;
801d0a
 	}
801d0a
 
801d0a
-	if (!(ctx = talloc_init("ads_add_machine_acct")))
801d0a
+	ctx = talloc_init("ads_add_machine_acct");
801d0a
+	if (ctx == NULL) {
801d0a
 		return ADS_ERROR(LDAP_NO_MEMORY);
801d0a
-
801d0a
-	ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+	}
801d0a
 
801d0a
 	machine_escaped = escape_rdn_val_string_alloc(machine_name);
801d0a
-	if (!machine_escaped) {
801d0a
+	if (machine_escaped == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
@@ -2131,17 +2133,26 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 	ads_msgfree(ads, res);
801d0a
 
801d0a
 	new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_escaped, org_unit);
801d0a
-	samAccountName = talloc_asprintf(ctx, "%s$", machine_name);
801d0a
+	if (new_dn == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
 
801d0a
-	if ( !new_dn || !samAccountName ) {
801d0a
+	samAccountName = talloc_asprintf(ctx, "%s$", machine_name);
801d0a
+	if (samAccountName == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
-	if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control))) {
801d0a
+	controlstr = talloc_asprintf(ctx, "%u", acct_control);
801d0a
+	if (controlstr == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
-	if (!(mods = ads_init_mods(ctx))) {
801d0a
+	mods = ads_init_mods(ctx);
801d0a
+	if (mods == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
@@ -2155,6 +2166,7 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 
801d0a
 		etype_list_str = talloc_asprintf(ctx, "%d", (int)etype_list);
801d0a
 		if (etype_list_str == NULL) {
801d0a
+			ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
 			goto done;
801d0a
 		}
801d0a
 		ads_mod_str(ctx, &mods, "msDS-SupportedEncryptionTypes",
801d0a
-- 
801d0a
2.23.0
801d0a
801d0a
801d0a
From 8d0e49716b7039fee4785186c67de774b34bd85b Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Wed, 21 Aug 2019 12:22:32 +0200
801d0a
Subject: [PATCH 05/11] s3:libads: Use a talloc_asprintf in
801d0a
 ads_find_machine_acct()
801d0a
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
(cherry picked from commit 35f3e4aed1f1c2ba1c8dc50921f238937f343357)
801d0a
---
801d0a
 source3/libads/ldap.c | 12 ++++++++----
801d0a
 1 file changed, 8 insertions(+), 4 deletions(-)
801d0a
801d0a
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
801d0a
index e492d0688a5..3bc9a2a06aa 100644
801d0a
--- a/source3/libads/ldap.c
801d0a
+++ b/source3/libads/ldap.c
801d0a
@@ -1367,18 +1367,22 @@ char *ads_parent_dn(const char *dn)
801d0a
 	ADS_STATUS status;
801d0a
 	char *expr;
801d0a
 	const char *attrs[] = {"*", "msDS-SupportedEncryptionTypes", "nTSecurityDescriptor", NULL};
801d0a
+	TALLOC_CTX *frame = talloc_stackframe();
801d0a
 
801d0a
 	*res = NULL;
801d0a
 
801d0a
 	/* the easiest way to find a machine account anywhere in the tree
801d0a
 	   is to look for hostname$ */
801d0a
-	if (asprintf(&expr, "(samAccountName=%s$)", machine) == -1) {
801d0a
-		DEBUG(1, ("asprintf failed!\n"));
801d0a
-		return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
801d0a
+	expr = talloc_asprintf(frame, "(samAccountName=%s$)", machine);
801d0a
+	if (expr == NULL) {
801d0a
+		status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
801d0a
+		goto done;
801d0a
 	}
801d0a
 
801d0a
 	status = ads_search(ads, res, expr, attrs);
801d0a
-	SAFE_FREE(expr);
801d0a
+
801d0a
+done:
801d0a
+	TALLOC_FREE(frame);
801d0a
 	return status;
801d0a
 }
801d0a
 
801d0a
-- 
801d0a
2.23.0
801d0a
801d0a
801d0a
From be247641382d1cc730ab5cd1e8bebe92e1d3a6fc Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Wed, 14 Aug 2019 13:01:19 +0200
801d0a
Subject: [PATCH 06/11] s3:libads: Fix detection if acount already exists in
801d0a
 ads_find_machine_count()
801d0a
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
(cherry picked from commit 4f389c1f78cdc2424795e3b2a1ce43818c400c2d)
801d0a
---
801d0a
 source3/libads/ldap.c | 36 ++++++++++++++++++++++++++++--------
801d0a
 1 file changed, 28 insertions(+), 8 deletions(-)
801d0a
801d0a
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
801d0a
index 3bc9a2a06aa..ec6ad61a55c 100644
801d0a
--- a/source3/libads/ldap.c
801d0a
+++ b/source3/libads/ldap.c
801d0a
@@ -1366,7 +1366,21 @@ char *ads_parent_dn(const char *dn)
801d0a
 {
801d0a
 	ADS_STATUS status;
801d0a
 	char *expr;
801d0a
-	const char *attrs[] = {"*", "msDS-SupportedEncryptionTypes", "nTSecurityDescriptor", NULL};
801d0a
+	const char *attrs[] = {
801d0a
+		/* This is how Windows checks for machine accounts */
801d0a
+		"objectClass",
801d0a
+		"SamAccountName",
801d0a
+		"userAccountControl",
801d0a
+		"DnsHostName",
801d0a
+		"ServicePrincipalName",
801d0a
+		"unicodePwd",
801d0a
+
801d0a
+		/* Additional attributes Samba checks */
801d0a
+		"msDS-SupportedEncryptionTypes",
801d0a
+		"nTSecurityDescriptor",
801d0a
+
801d0a
+		NULL
801d0a
+	};
801d0a
 	TALLOC_CTX *frame = talloc_stackframe();
801d0a
 
801d0a
 	*res = NULL;
801d0a
@@ -1380,6 +1394,11 @@ char *ads_parent_dn(const char *dn)
801d0a
 	}
801d0a
 
801d0a
 	status = ads_search(ads, res, expr, attrs);
801d0a
+	if (ADS_ERR_OK(status)) {
801d0a
+		if (ads_count_replies(ads, *res) != 1) {
801d0a
+			status = ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
801d0a
+		}
801d0a
+	}
801d0a
 
801d0a
 done:
801d0a
 	TALLOC_FREE(frame);
801d0a
@@ -1867,11 +1886,11 @@ ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machin
801d0a
 	char *dn_string = NULL;
801d0a
 
801d0a
 	ret = ads_find_machine_acct(ads, &res, machine_name);
801d0a
-	if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) {
801d0a
+	if (!ADS_ERR_OK(ret)) {
801d0a
 		DEBUG(5,("ads_clear_service_principal_names: WARNING: Host Account for %s not found... skipping operation.\n", machine_name));
801d0a
 		DEBUG(5,("ads_clear_service_principal_names: WARNING: Service Principals for %s have NOT been cleared.\n", machine_name));
801d0a
 		ads_msgfree(ads, res);
801d0a
-		return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
801d0a
+		return ret;
801d0a
 	}
801d0a
 
801d0a
 	DEBUG(5,("ads_clear_service_principal_names: Host account for %s found\n", machine_name));
801d0a
@@ -2027,12 +2046,12 @@ ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads,
801d0a
 	const char **servicePrincipalName = spns;
801d0a
 
801d0a
 	ret = ads_find_machine_acct(ads, &res, machine_name);
801d0a
-	if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) {
801d0a
+	if (!ADS_ERR_OK(ret)) {
801d0a
 		DEBUG(1,("ads_add_service_principal_name: WARNING: Host Account for %s not found... skipping operation.\n",
801d0a
 			machine_name));
801d0a
 		DEBUG(1,("ads_add_service_principal_name: WARNING: Service Principals have NOT been added.\n"));
801d0a
 		ads_msgfree(ads, res);
801d0a
-		return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
801d0a
+		return ret;
801d0a
 	}
801d0a
 
801d0a
 	DEBUG(1,("ads_add_service_principal_name: Host account for %s found\n", machine_name));
801d0a
@@ -2127,7 +2146,7 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 	}
801d0a
 
801d0a
 	ret = ads_find_machine_acct(ads, &res, machine_escaped);
801d0a
-	if (ADS_ERR_OK(ret) && ads_count_replies(ads, res) == 1) {
801d0a
+	if (ADS_ERR_OK(ret)) {
801d0a
 		DBG_DEBUG("Host account for %s already exists.\n",
801d0a
 				machine_escaped);
801d0a
 		ret = ADS_ERROR_LDAP(LDAP_ALREADY_EXISTS);
801d0a
@@ -3684,14 +3703,15 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
801d0a
 	TALLOC_FREE(hostnameDN);
801d0a
 
801d0a
 	status = ads_find_machine_acct(ads, &res, host);
801d0a
-	if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
801d0a
+	if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
801d0a
+	    (status.err.rc != LDAP_NO_SUCH_OBJECT)) {
801d0a
 		DEBUG(3, ("Failed to remove host account.\n"));
801d0a
 		SAFE_FREE(host);
801d0a
 		return status;
801d0a
 	}
801d0a
 
801d0a
 	SAFE_FREE(host);
801d0a
-	return status;
801d0a
+	return ADS_SUCCESS;
801d0a
 }
801d0a
 
801d0a
 /**
801d0a
-- 
801d0a
2.23.0
801d0a
801d0a
801d0a
From d7485cee3652a91ac199f912d656713cf1ddafa9 Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Wed, 14 Aug 2019 12:17:20 +0200
801d0a
Subject: [PATCH 07/11] s3:libads: Don't set supported encryption types during
801d0a
 account creation
801d0a
801d0a
This is already handled by libnet_join_post_processing_ads_modify()
801d0a
which calls libnet_join_set_etypes() if encrytion types should be set.
801d0a
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
(cherry picked from commit b755a6438022579dab1a403c81d60b1ed7efca38)
801d0a
---
801d0a
 source3/libads/ldap.c | 18 ------------------
801d0a
 1 file changed, 18 deletions(-)
801d0a
801d0a
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
801d0a
index ec6ad61a55c..8fbd97e25e2 100644
801d0a
--- a/source3/libads/ldap.c
801d0a
+++ b/source3/libads/ldap.c
801d0a
@@ -2127,12 +2127,6 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 	uint32_t acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\
801d0a
 	                        UF_DONT_EXPIRE_PASSWD |\
801d0a
 			        UF_ACCOUNTDISABLE );
801d0a
-	uint32_t func_level = 0;
801d0a
-
801d0a
-	ret = ads_domain_func_level(ads, &func_level);
801d0a
-	if (!ADS_ERR_OK(ret)) {
801d0a
-		return ret;
801d0a
-	}
801d0a
 
801d0a
 	ctx = talloc_init("ads_add_machine_acct");
801d0a
 	if (ctx == NULL) {
801d0a
@@ -2184,18 +2178,6 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 	ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
801d0a
 	ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
801d0a
 
801d0a
-	if (func_level >= DS_DOMAIN_FUNCTION_2008) {
801d0a
-		const char *etype_list_str;
801d0a
-
801d0a
-		etype_list_str = talloc_asprintf(ctx, "%d", (int)etype_list);
801d0a
-		if (etype_list_str == NULL) {
801d0a
-			ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
-			goto done;
801d0a
-		}
801d0a
-		ads_mod_str(ctx, &mods, "msDS-SupportedEncryptionTypes",
801d0a
-			    etype_list_str);
801d0a
-	}
801d0a
-
801d0a
 	ret = ads_gen_add(ads, new_dn, mods);
801d0a
 
801d0a
 done:
801d0a
-- 
801d0a
2.23.0
801d0a
801d0a
801d0a
From f8f7158ac639c516e6dcdeca9d41b94ba6d06134 Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Tue, 13 Aug 2019 16:34:34 +0200
801d0a
Subject: [PATCH 08/11] s3:libads: Fix creating machine account using LDAP
801d0a
801d0a
This implements the same behaviour as Windows.
801d0a
801d0a
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13884
801d0a
801d0a
Pair-Programmed-With: Guenther Deschner <gd@samba.org>
801d0a
Signed-off-by: Guenther Deschner <gd@samba.org>
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
(cherry picked from commit ce7762935051c862ecdd3e82d93096aac61dd292)
801d0a
---
801d0a
 source3/libads/ads_proto.h   |   4 +-
801d0a
 source3/libads/ldap.c        | 118 +++++++++++++++++++++++++++++++----
801d0a
 source3/libnet/libnet_join.c |  23 ++++---
801d0a
 3 files changed, 124 insertions(+), 21 deletions(-)
801d0a
801d0a
diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h
801d0a
index 92bb3a22cdb..495ef5d3325 100644
801d0a
--- a/source3/libads/ads_proto.h
801d0a
+++ b/source3/libads/ads_proto.h
801d0a
@@ -114,8 +114,10 @@ ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads, const char *machine_
801d0a
                                           const char **spns);
801d0a
 ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 				   const char *machine_name,
801d0a
+				   const char *machine_password,
801d0a
 				   const char *org_unit,
801d0a
-				   uint32_t etype_list);
801d0a
+				   uint32_t etype_list,
801d0a
+				   const char *dns_domain_name);
801d0a
 ADS_STATUS ads_move_machine_acct(ADS_STRUCT *ads, const char *machine_name,
801d0a
                                  const char *org_unit, bool *moved);
801d0a
 int ads_count_replies(ADS_STRUCT *ads, void *res);
801d0a
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
801d0a
index 8fbd97e25e2..81efda0cf30 100644
801d0a
--- a/source3/libads/ldap.c
801d0a
+++ b/source3/libads/ldap.c
801d0a
@@ -1516,7 +1516,6 @@ ADS_STATUS ads_mod_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
801d0a
 			       name, (const void **) vals);
801d0a
 }
801d0a
 
801d0a
-#if 0
801d0a
 /**
801d0a
  * Add a single ber-encoded value to a mod list
801d0a
  * @param ctx An initialized TALLOC_CTX
801d0a
@@ -1537,7 +1536,6 @@ static ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods,
801d0a
 	return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE|LDAP_MOD_BVALUES,
801d0a
 			       name, (const void **) values);
801d0a
 }
801d0a
-#endif
801d0a
 
801d0a
 static void ads_print_error(int ret, LDAP *ld)
801d0a
 {
801d0a
@@ -2111,8 +2109,10 @@ ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads,
801d0a
 
801d0a
 ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 				   const char *machine_name,
801d0a
+				   const char *machine_password,
801d0a
 				   const char *org_unit,
801d0a
-				   uint32_t etype_list)
801d0a
+				   uint32_t etype_list,
801d0a
+				   const char *dns_domain_name)
801d0a
 {
801d0a
 	ADS_STATUS ret;
801d0a
 	char *samAccountName = NULL;
801d0a
@@ -2120,13 +2120,23 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 	TALLOC_CTX *ctx = NULL;
801d0a
 	ADS_MODLIST mods;
801d0a
 	char *machine_escaped = NULL;
801d0a
+	char *dns_hostname = NULL;
801d0a
 	char *new_dn = NULL;
801d0a
-	const char *objectClass[] = {"top", "person", "organizationalPerson",
801d0a
-				     "user", "computer", NULL};
801d0a
+	char *utf8_pw = NULL;
801d0a
+	size_t utf8_pw_len = 0;
801d0a
+	char *utf16_pw = NULL;
801d0a
+	size_t utf16_pw_len = 0;
801d0a
+	struct berval machine_pw_val;
801d0a
+	bool ok;
801d0a
+	const char **spn_array = NULL;
801d0a
+	size_t num_spns = 0;
801d0a
+	const char *spn_prefix[] = {
801d0a
+		"HOST",
801d0a
+		"RestrictedKrbHost",
801d0a
+	};
801d0a
+	size_t i;
801d0a
 	LDAPMessage *res = NULL;
801d0a
-	uint32_t acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\
801d0a
-	                        UF_DONT_EXPIRE_PASSWD |\
801d0a
-			        UF_ACCOUNTDISABLE );
801d0a
+	uint32_t acct_control = UF_WORKSTATION_TRUST_ACCOUNT;
801d0a
 
801d0a
 	ctx = talloc_init("ads_add_machine_acct");
801d0a
 	if (ctx == NULL) {
801d0a
@@ -2139,10 +2149,9 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
+	/* Check if the machine account already exists. */
801d0a
 	ret = ads_find_machine_acct(ads, &res, machine_escaped);
801d0a
 	if (ADS_ERR_OK(ret)) {
801d0a
-		DBG_DEBUG("Host account for %s already exists.\n",
801d0a
-				machine_escaped);
801d0a
 		ret = ADS_ERROR_LDAP(LDAP_ALREADY_EXISTS);
801d0a
 		ads_msgfree(ads, res);
801d0a
 		goto done;
801d0a
@@ -2155,28 +2164,111 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
+	/* Create machine account */
801d0a
+
801d0a
 	samAccountName = talloc_asprintf(ctx, "%s$", machine_name);
801d0a
 	if (samAccountName == NULL) {
801d0a
 		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
+	dns_hostname = talloc_asprintf(ctx,
801d0a
+				       "%s.%s",
801d0a
+				       machine_name,
801d0a
+				       dns_domain_name);
801d0a
+	if (dns_hostname == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+
801d0a
+	/* Add dns_hostname SPNs */
801d0a
+	for (i = 0; i < ARRAY_SIZE(spn_prefix); i++) {
801d0a
+		char *spn = talloc_asprintf(ctx,
801d0a
+					    "%s/%s",
801d0a
+					    spn_prefix[i],
801d0a
+					    dns_hostname);
801d0a
+		if (spn == NULL) {
801d0a
+			ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+			goto done;
801d0a
+		}
801d0a
+
801d0a
+		ok = add_string_to_array(spn_array,
801d0a
+					 spn,
801d0a
+					 &spn_array,
801d0a
+					 &num_spns);
801d0a
+		if (!ok) {
801d0a
+			ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+			goto done;
801d0a
+		}
801d0a
+	}
801d0a
+
801d0a
+	/* Add machine_name SPNs */
801d0a
+	for (i = 0; i < ARRAY_SIZE(spn_prefix); i++) {
801d0a
+		char *spn = talloc_asprintf(ctx,
801d0a
+					    "%s/%s",
801d0a
+					    spn_prefix[i],
801d0a
+					    machine_name);
801d0a
+		if (spn == NULL) {
801d0a
+			ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+			goto done;
801d0a
+		}
801d0a
+
801d0a
+		ok = add_string_to_array(spn_array,
801d0a
+					 spn,
801d0a
+					 &spn_array,
801d0a
+					 &num_spns);
801d0a
+		if (!ok) {
801d0a
+			ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+			goto done;
801d0a
+		}
801d0a
+	}
801d0a
+
801d0a
+	/* Make sure to NULL terminate the array */
801d0a
+	spn_array = talloc_realloc(ctx, spn_array, const char *, num_spns + 1);
801d0a
+	if (spn_array == NULL) {
801d0a
+		return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
801d0a
+	}
801d0a
+	spn_array[num_spns] = NULL;
801d0a
+
801d0a
 	controlstr = talloc_asprintf(ctx, "%u", acct_control);
801d0a
 	if (controlstr == NULL) {
801d0a
 		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
+	utf8_pw = talloc_asprintf(ctx, "\"%s\"", machine_password);
801d0a
+	if (utf8_pw == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+	utf8_pw_len = strlen(utf8_pw);
801d0a
+
801d0a
+	ok = convert_string_talloc(ctx,
801d0a
+				   CH_UTF8, CH_UTF16MUNGED,
801d0a
+				   utf8_pw, utf8_pw_len,
801d0a
+				   (void *)&utf16_pw, &utf16_pw_len);
801d0a
+	if (!ok) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+
801d0a
+	machine_pw_val = (struct berval) {
801d0a
+		.bv_val = utf16_pw,
801d0a
+		.bv_len = utf16_pw_len,
801d0a
+	};
801d0a
+
801d0a
 	mods = ads_init_mods(ctx);
801d0a
 	if (mods == NULL) {
801d0a
 		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
-	ads_mod_str(ctx, &mods, "cn", machine_name);
801d0a
-	ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
801d0a
-	ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
801d0a
+	ads_mod_str(ctx, &mods, "objectClass", "Computer");
801d0a
+	ads_mod_str(ctx, &mods, "SamAccountName", samAccountName);
801d0a
 	ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
801d0a
+	ads_mod_str(ctx, &mods, "DnsHostName", dns_hostname);
801d0a
+	ads_mod_strlist(ctx, &mods, "ServicePrincipalName", spn_array);
801d0a
+	ads_mod_ber(ctx, &mods, "unicodePwd", &machine_pw_val);
801d0a
 
801d0a
 	ret = ads_gen_add(ads, new_dn, mods);
801d0a
 
801d0a
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
801d0a
index a512afc238a..d5c8599beee 100644
801d0a
--- a/source3/libnet/libnet_join.c
801d0a
+++ b/source3/libnet/libnet_join.c
801d0a
@@ -338,10 +338,22 @@ static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
801d0a
 	/* Attempt to create the machine account and bail if this fails.
801d0a
 	   Assume that the admin wants exactly what they requested */
801d0a
 
801d0a
+	if (r->in.machine_password == NULL) {
801d0a
+		r->in.machine_password =
801d0a
+			trust_pw_new_value(mem_ctx,
801d0a
+					   r->in.secure_channel_type,
801d0a
+					   SEC_ADS);
801d0a
+		if (r->in.machine_password == NULL) {
801d0a
+			return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
801d0a
+		}
801d0a
+	}
801d0a
+
801d0a
 	status = ads_create_machine_acct(r->in.ads,
801d0a
 					 r->in.machine_name,
801d0a
+					 r->in.machine_password,
801d0a
 					 r->in.account_ou,
801d0a
-					 r->in.desired_encryption_types);
801d0a
+					 r->in.desired_encryption_types,
801d0a
+					 r->out.dns_domain_name);
801d0a
 
801d0a
 	if (ADS_ERR_OK(status)) {
801d0a
 		DEBUG(1,("machine account creation created\n"));
801d0a
@@ -2668,12 +2680,11 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
801d0a
 		if (ADS_ERR_OK(ads_status)) {
801d0a
 
801d0a
 			/*
801d0a
-			 * LDAP object create succeeded, now go to the rpc
801d0a
-			 * password set routines
801d0a
+			 * LDAP object creation succeeded.
801d0a
 			 */
801d0a
-
801d0a
 			r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
801d0a
-			goto rpc_join;
801d0a
+
801d0a
+			return WERR_OK;
801d0a
 		}
801d0a
 
801d0a
 		if (initial_account_ou != NULL) {
801d0a
@@ -2687,8 +2698,6 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
801d0a
 		DBG_INFO("Failed to pre-create account in OU %s: %s\n",
801d0a
 			 r->in.account_ou, ads_errstr(ads_status));
801d0a
 	}
801d0a
- rpc_join:
801d0a
-
801d0a
 #endif /* HAVE_ADS */
801d0a
 
801d0a
 	if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
801d0a
-- 
801d0a
2.23.0
801d0a
801d0a
801d0a
From f37eaa71dbd1cb206e8f3bcf251fc42308aa561d Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Wed, 14 Aug 2019 10:15:19 +0200
801d0a
Subject: [PATCH 09/11] s3:libnet: Improve debug messages
801d0a
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
(cherry picked from commit 39b8c8b30a5d5bd70f8da3a02cf77f7592788b94)
801d0a
---
801d0a
 source3/libnet/libnet_join.c | 4 ++--
801d0a
 1 file changed, 2 insertions(+), 2 deletions(-)
801d0a
801d0a
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
801d0a
index d5c8599beee..31d1d221ed3 100644
801d0a
--- a/source3/libnet/libnet_join.c
801d0a
+++ b/source3/libnet/libnet_join.c
801d0a
@@ -356,7 +356,7 @@ static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
801d0a
 					 r->out.dns_domain_name);
801d0a
 
801d0a
 	if (ADS_ERR_OK(status)) {
801d0a
-		DEBUG(1,("machine account creation created\n"));
801d0a
+		DBG_WARNING("Machine account successfully created\n");
801d0a
 		return status;
801d0a
 	} else  if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
801d0a
 		    (status.err.rc == LDAP_ALREADY_EXISTS)) {
801d0a
@@ -364,7 +364,7 @@ static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
801d0a
 	}
801d0a
 
801d0a
 	if (!ADS_ERR_OK(status)) {
801d0a
-		DEBUG(1,("machine account creation failed\n"));
801d0a
+		DBG_WARNING("Failed to create machine account\n");
801d0a
 		return status;
801d0a
 	}
801d0a
 
801d0a
-- 
801d0a
2.23.0
801d0a
801d0a
801d0a
From d590cf9739393e15aa4d9cc86ca56f93db6f1a2b Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Thu, 8 Aug 2019 14:40:04 +0200
801d0a
Subject: [PATCH 10/11] s3:libads: Just change the machine password if account
801d0a
 already exists
801d0a
801d0a
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13884
801d0a
801d0a
Pair-Programmed-With: Guenther Deschner <gd@samba.org>
801d0a
Signed-off-by: Guenther Deschner <gd@samba.org>
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
(cherry picked from commit 14f320fa1e40ecc3a43dabb0cecd57430270a521)
801d0a
---
801d0a
 source3/libads/ldap.c        | 167 ++++++++++++++++++++++++++++++-----
801d0a
 source3/libnet/libnet_join.c |   1 +
801d0a
 2 files changed, 146 insertions(+), 22 deletions(-)
801d0a
801d0a
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
801d0a
index 81efda0cf30..afae46d2e79 100644
801d0a
--- a/source3/libads/ldap.c
801d0a
+++ b/source3/libads/ldap.c
801d0a
@@ -2098,6 +2098,127 @@ ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads,
801d0a
 	return ret;
801d0a
 }
801d0a
 
801d0a
+static uint32_t ads_get_acct_ctrl(ADS_STRUCT *ads,
801d0a
+				  LDAPMessage *msg)
801d0a
+{
801d0a
+	uint32_t acct_ctrl = 0;
801d0a
+	bool ok;
801d0a
+
801d0a
+	ok = ads_pull_uint32(ads, msg, "userAccountControl", &acct_ctrl);
801d0a
+	if (!ok) {
801d0a
+		return 0;
801d0a
+	}
801d0a
+
801d0a
+	return acct_ctrl;
801d0a
+}
801d0a
+
801d0a
+static ADS_STATUS ads_change_machine_acct(ADS_STRUCT *ads,
801d0a
+					  LDAPMessage *msg,
801d0a
+					  const struct berval *machine_pw_val)
801d0a
+{
801d0a
+	ADS_MODLIST mods;
801d0a
+	ADS_STATUS ret;
801d0a
+	TALLOC_CTX *frame = talloc_stackframe();
801d0a
+	uint32_t acct_control;
801d0a
+	char *control_str = NULL;
801d0a
+	const char *attrs[] = {
801d0a
+		"objectSid",
801d0a
+		NULL
801d0a
+	};
801d0a
+	LDAPMessage *res = NULL;
801d0a
+	char *dn = NULL;
801d0a
+
801d0a
+	dn = ads_get_dn(ads, frame, msg);
801d0a
+	if (dn == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+
801d0a
+	acct_control = ads_get_acct_ctrl(ads, msg);
801d0a
+	if (acct_control == 0) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
801d0a
+		goto done;
801d0a
+	}
801d0a
+
801d0a
+	/*
801d0a
+	 * Changing the password, disables the account. So we need to change the
801d0a
+	 * userAccountControl flags to enable it again.
801d0a
+	 */
801d0a
+	mods = ads_init_mods(frame);
801d0a
+	if (mods == NULL) {
801d0a
+		ret = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+
801d0a
+	ads_mod_ber(frame, &mods, "unicodePwd", machine_pw_val);
801d0a
+
801d0a
+	ret = ads_gen_mod(ads, dn, mods);
801d0a
+	if (!ADS_ERR_OK(ret)) {
801d0a
+		goto done;
801d0a
+	}
801d0a
+	TALLOC_FREE(mods);
801d0a
+
801d0a
+	/*
801d0a
+	 * To activate the account, we need to disable and enable it.
801d0a
+	 */
801d0a
+	acct_control |= UF_ACCOUNTDISABLE;
801d0a
+
801d0a
+	control_str = talloc_asprintf(frame, "%u", acct_control);
801d0a
+	if (control_str == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+
801d0a
+	mods = ads_init_mods(frame);
801d0a
+	if (mods == NULL) {
801d0a
+		ret = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+
801d0a
+	ads_mod_str(frame, &mods, "userAccountControl", control_str);
801d0a
+
801d0a
+	ret = ads_gen_mod(ads, dn, mods);
801d0a
+	if (!ADS_ERR_OK(ret)) {
801d0a
+		goto done;
801d0a
+	}
801d0a
+	TALLOC_FREE(mods);
801d0a
+	TALLOC_FREE(control_str);
801d0a
+
801d0a
+	/*
801d0a
+	 * Enable the account again.
801d0a
+	 */
801d0a
+	acct_control &= ~UF_ACCOUNTDISABLE;
801d0a
+
801d0a
+	control_str = talloc_asprintf(frame, "%u", acct_control);
801d0a
+	if (control_str == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+
801d0a
+	mods = ads_init_mods(frame);
801d0a
+	if (mods == NULL) {
801d0a
+		ret = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+
801d0a
+	ads_mod_str(frame, &mods, "userAccountControl", control_str);
801d0a
+
801d0a
+	ret = ads_gen_mod(ads, dn, mods);
801d0a
+	if (!ADS_ERR_OK(ret)) {
801d0a
+		goto done;
801d0a
+	}
801d0a
+	TALLOC_FREE(mods);
801d0a
+	TALLOC_FREE(control_str);
801d0a
+
801d0a
+	ret = ads_search_dn(ads, &res, dn, attrs);
801d0a
+	ads_msgfree(ads, res);
801d0a
+
801d0a
+done:
801d0a
+	talloc_free(frame);
801d0a
+
801d0a
+	return ret;
801d0a
+}
801d0a
+
801d0a
 /**
801d0a
  * adds a machine account to the ADS server
801d0a
  * @param ads An intialized ADS_STRUCT
801d0a
@@ -2149,11 +2270,34 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
+	utf8_pw = talloc_asprintf(ctx, "\"%s\"", machine_password);
801d0a
+	if (utf8_pw == NULL) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+	utf8_pw_len = strlen(utf8_pw);
801d0a
+
801d0a
+	ok = convert_string_talloc(ctx,
801d0a
+				   CH_UTF8, CH_UTF16MUNGED,
801d0a
+				   utf8_pw, utf8_pw_len,
801d0a
+				   (void *)&utf16_pw, &utf16_pw_len);
801d0a
+	if (!ok) {
801d0a
+		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
+		goto done;
801d0a
+	}
801d0a
+
801d0a
+	machine_pw_val = (struct berval) {
801d0a
+		.bv_val = utf16_pw,
801d0a
+		.bv_len = utf16_pw_len,
801d0a
+	};
801d0a
+
801d0a
 	/* Check if the machine account already exists. */
801d0a
 	ret = ads_find_machine_acct(ads, &res, machine_escaped);
801d0a
 	if (ADS_ERR_OK(ret)) {
801d0a
-		ret = ADS_ERROR_LDAP(LDAP_ALREADY_EXISTS);
801d0a
+		/* Change the machine account password */
801d0a
+		ret = ads_change_machine_acct(ads, res, &machine_pw_val);
801d0a
 		ads_msgfree(ads, res);
801d0a
+
801d0a
 		goto done;
801d0a
 	}
801d0a
 	ads_msgfree(ads, res);
801d0a
@@ -2236,27 +2380,6 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
801d0a
 		goto done;
801d0a
 	}
801d0a
 
801d0a
-	utf8_pw = talloc_asprintf(ctx, "\"%s\"", machine_password);
801d0a
-	if (utf8_pw == NULL) {
801d0a
-		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
-		goto done;
801d0a
-	}
801d0a
-	utf8_pw_len = strlen(utf8_pw);
801d0a
-
801d0a
-	ok = convert_string_talloc(ctx,
801d0a
-				   CH_UTF8, CH_UTF16MUNGED,
801d0a
-				   utf8_pw, utf8_pw_len,
801d0a
-				   (void *)&utf16_pw, &utf16_pw_len);
801d0a
-	if (!ok) {
801d0a
-		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
-		goto done;
801d0a
-	}
801d0a
-
801d0a
-	machine_pw_val = (struct berval) {
801d0a
-		.bv_val = utf16_pw,
801d0a
-		.bv_len = utf16_pw_len,
801d0a
-	};
801d0a
-
801d0a
 	mods = ads_init_mods(ctx);
801d0a
 	if (mods == NULL) {
801d0a
 		ret = ADS_ERROR(LDAP_NO_MEMORY);
801d0a
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
801d0a
index 31d1d221ed3..1052afde641 100644
801d0a
--- a/source3/libnet/libnet_join.c
801d0a
+++ b/source3/libnet/libnet_join.c
801d0a
@@ -968,6 +968,7 @@ static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
801d0a
 
801d0a
 		if (r->in.ads->auth.ccache_name != NULL) {
801d0a
 			ads_kdestroy(r->in.ads->auth.ccache_name);
801d0a
+			r->in.ads->auth.ccache_name = NULL;
801d0a
 		}
801d0a
 
801d0a
 		ads_destroy(&r->in.ads);
801d0a
-- 
801d0a
2.23.0
801d0a
801d0a
801d0a
From 2209c01f8069d47b47c8fc5df376cc9c41c552e1 Mon Sep 17 00:00:00 2001
801d0a
From: Andreas Schneider <asn@samba.org>
801d0a
Date: Thu, 22 Aug 2019 16:31:30 +0200
801d0a
Subject: [PATCH 11/11] testprogs: Add test for 'net ads join createcomputer='
801d0a
801d0a
Signed-off-by: Andreas Schneider <asn@samba.org>
801d0a
Reviewed-by: Alexander Bokovoy <ab@samba.org>
801d0a
801d0a
Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org>
801d0a
Autobuild-Date(master): Wed Oct  9 08:26:17 UTC 2019 on sn-devel-184
801d0a
801d0a
(cherry picked from commit 459b43e5776180dc1540cd845b72ff78747ecd6f)
801d0a
---
801d0a
 testprogs/blackbox/test_net_ads.sh | 32 ++++++++++++++++++++++++++++--
801d0a
 1 file changed, 30 insertions(+), 2 deletions(-)
801d0a
801d0a
diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh
801d0a
index 512aa9d2952..cc8345c4624 100755
801d0a
--- a/testprogs/blackbox/test_net_ads.sh
801d0a
+++ b/testprogs/blackbox/test_net_ads.sh
801d0a
@@ -31,6 +31,16 @@ if [ -x "$BINDIR/ldbsearch" ]; then
801d0a
 	ldbsearch="$BINDIR/ldbsearch"
801d0a
 fi
801d0a
 
801d0a
+ldbadd="ldbadd"
801d0a
+if [ -x "$BINDIR/ldbadd" ]; then
801d0a
+	ldbadd="$BINDIR/ldbadd"
801d0a
+fi
801d0a
+
801d0a
+ldbdel="ldbdel"
801d0a
+if [ -x "$BINDIR/ldbdel" ]; then
801d0a
+	ldbdel="$BINDIR/ldbdel"
801d0a
+fi
801d0a
+
801d0a
 # Load test functions
801d0a
 . `dirname $0`/subunit.sh
801d0a
 
801d0a
@@ -188,8 +198,9 @@ testit "testjoin user+password" $VALGRIND $net_tool ads testjoin -U$DC_USERNAME%
801d0a
 
801d0a
 testit "leave+keep_account" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD --keep-account || failed=`expr $failed + 1`
801d0a
 
801d0a
-computers_ldb_ou="CN=Computers,DC=addom,DC=samba,DC=example,DC=com"
801d0a
-testit "ldb check for existence of machine account" $ldbsearch -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER.$REALM -s base -b "cn=$HOSTNAME,$computers_ldb_ou" || failed=`expr $failed + 1`
801d0a
+base_dn="DC=addom,DC=samba,DC=example,DC=com"
801d0a
+computers_dn="CN=Computers,$base_dn"
801d0a
+testit "ldb check for existence of machine account" $ldbsearch -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER.$REALM -s base -b "cn=$HOSTNAME,$computers_dn" || failed=`expr $failed + 1`
801d0a
 
801d0a
 testit "join" $VALGRIND $net_tool ads join -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
801d0a
 
801d0a
@@ -198,6 +209,23 @@ testit "testjoin" $VALGRIND $net_tool ads testjoin || failed=`expr $failed + 1`
801d0a
 ##Goodbye...
801d0a
 testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
801d0a
 
801d0a
+#
801d0a
+# Test createcomputer option of 'net ads join'
801d0a
+#
801d0a
+testit "Create OU=Servers,$base_dn" $VALGRIND $ldbadd -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER <
801d0a
+dn: OU=Servers,$base_dn
801d0a
+objectClass: organizationalUnit
801d0a
+EOF
801d0a
+
801d0a
+testit "join+createcomputer" $VALGRIND $net_tool ads join -U$DC_USERNAME%$DC_PASSWORD createcomputer=Servers || failed=`expr $failed + 1`
801d0a
+
801d0a
+testit "ldb check for existence of machine account in OU=Servers" $ldbsearch -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER.$REALM -s base -b "cn=$HOSTNAME,OU=Servers,$base_dn" || failed=`expr $failed + 1`
801d0a
+
801d0a
+## Goodbye...
801d0a
+testit "leave+createcomputer" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1`
801d0a
+
801d0a
+testit "Remove OU=Servers" $VALGRIND $ldbdel -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER "OU=Servers,$base_dn"
801d0a
+
801d0a
 rm -rf $BASEDIR/$WORKDIR
801d0a
 
801d0a
 exit $failed
801d0a
-- 
801d0a
2.23.0
801d0a