[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Fri Jul 6 02:00:02 MDT 2012


The branch, master has been updated
       via  8f44389 s4-classicupgrade: Demote any other 'BDC' accounts back to a member server during upgrade
       via  2908bbe s4-selftest: Test samba-tool domain dcpromo
       via  1c86ab9 s4-samba-tool: Provide a samba-tool domain dcpromo that upgrades a member to a DC
       via  c436f98 s4-dsdb: Give a much better error message when parentGUID generation fails
       via  8b32d9a s4-dsdb: Use parent_object_guid to find the correct parent for new objects
      from  7abe51f talloc: remove unused variables

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 8f443895f20aa6d03fd5ae02cbbc6c3064bf42f4
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Jul 6 15:40:02 2012 +1000

    s4-classicupgrade: Demote any other 'BDC' accounts back to a member server during upgrade
    
    This makes it clear that they cannot be a DC until they are upgraded with
    samba-tool domain dcpromo.
    
    Andrew Bartlett
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Fri Jul  6 09:59:13 CEST 2012 on sn-devel-104

commit 2908bbe06a3905007864c6caeaa77fb46cc442ef
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Jul 6 15:39:09 2012 +1000

    s4-selftest: Test samba-tool domain dcpromo
    
    This needs a new environment to test it properly.  This requires a raise in the
    number of socket wrapper interfaces.
    
    Andrew Bartlett

commit 1c86ab9c5056c457a40dc4c8e3b39c9b940c077b
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Jul 6 15:38:06 2012 +1000

    s4-samba-tool: Provide a samba-tool domain dcpromo that upgrades a member to a DC
    
    This command is like dcpromo in that it upgrades the existing workstation account
    to be a domain controller.
    
    The SID (and therefore any file ownerships) is preserved.
    
    Andrew Bartlett

commit c436f986ca67c71fe5d0855a14dfea65942a47fb
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Jul 6 15:36:12 2012 +1000

    s4-dsdb: Give a much better error message when parentGUID generation fails

commit 8b32d9ad2de96679108fd7bffe804da10a652b2f
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Jul 6 15:35:42 2012 +1000

    s4-dsdb: Use parent_object_guid to find the correct parent for new objects
    
    This allows the parent to be renmaed while a new object is added on another replica.
    
    This rename may also be a delete, in which case we must move it to lostandfound.
    
    Andrew Bartlett

-----------------------------------------------------------------------

Summary of changes:
 lib/socket_wrapper/socket_wrapper.c             |    2 +-
 selftest/target/Samba.pm                        |    1 +
 selftest/target/Samba4.pm                       |  131 ++++++++++++++++++++++-
 source4/dsdb/repl/replicated_objects.c          |   11 ++
 source4/dsdb/samdb/ldb_modules/operational.c    |    6 +-
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c |  118 ++++++++++++++++++++-
 source4/dsdb/samdb/samdb.h                      |    1 +
 source4/scripting/python/samba/join.py          |   64 +++++++++--
 source4/scripting/python/samba/netcmd/domain.py |   67 ++++++++++++
 source4/scripting/python/samba/upgrade.py       |   14 ++-
 source4/selftest/tests.py                       |    3 +-
 11 files changed, 399 insertions(+), 19 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/socket_wrapper/socket_wrapper.c b/lib/socket_wrapper/socket_wrapper.c
index 2c24ab7..44d21fb 100644
--- a/lib/socket_wrapper/socket_wrapper.c
+++ b/lib/socket_wrapper/socket_wrapper.c
@@ -154,7 +154,7 @@
 /* This limit is to avoid broadcast sendto() needing to stat too many
  * files.  It may be raised (with a performance cost) to up to 254
  * without changing the format above */
-#define MAX_WRAPPED_INTERFACES 32
+#define MAX_WRAPPED_INTERFACES 40
 
 #ifdef HAVE_IPV6
 /*
diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm
index 72f26a5..ec6fc48 100644
--- a/selftest/target/Samba.pm
+++ b/selftest/target/Samba.pm
@@ -161,6 +161,7 @@ sub get_interface($)
     $interfaces{"plugindc"} = 30;
     $interfaces{"localsubdc"} = 31;
     $interfaces{"chgdcpass"} = 32;
+    $interfaces{"promotedvdc"} = 33;
 
     # update lib/socket_wrapper/socket_wrapper.c
     #  #define MAX_WRAPPED_INTERFACES 32
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index f472bb5..b1998a6 100644
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -966,6 +966,78 @@ sub provision_rpc_proxy($$$)
 	return $ret;
 }
 
+sub provision_promoted_vampire_dc($$$)
+{
+	my ($self, $prefix, $dcvars) = @_;
+	print "PROVISIONING VAMPIRE DC...";
+
+	# We do this so that we don't run the provision.  That's the job of 'net vampire'.
+	my $ctx = $self->provision_raw_prepare($prefix, "domain controller",
+					       "promotedvdc",
+					       "SAMBADOMAIN",
+					       "samba.example.com",
+					       "2008",
+					       $dcvars->{PASSWORD},
+					       $dcvars->{SERVER_IP});
+
+	$ctx->{smb_conf_extra_options} = "
+	max xmit = 32K
+	server max protocol = SMB2
+
+[sysvol]
+	path = $ctx->{statedir}/sysvol
+	read only = yes
+
+[netlogon]
+	path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
+	read only = no
+
+";
+
+	my $ret = $self->provision_raw_step1($ctx);
+	unless ($ret) {
+		return undef;
+	}
+
+	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
+	my $cmd = "";
+	$cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$ret->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
+	$cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
+	$cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} MEMBER --realm=$dcvars->{REALM}";
+	$cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
+	$cmd .= " --machinepass=machine$ret->{password}";
+
+	unless (system($cmd) == 0) {
+		warn("Join failed\n$cmd");
+		return undef;
+	}
+
+	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
+	my $cmd = "";
+	$cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$ret->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
+	$cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
+	$cmd .= "$samba_tool domain dcpromo $ret->{CONFIGURATION} $dcvars->{REALM} DC --realm=$dcvars->{REALM}";
+	$cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
+	$cmd .= " --machinepass=machine$ret->{password}";
+
+	unless (system($cmd) == 0) {
+		warn("Join failed\n$cmd");
+		return undef;
+	}
+
+	$ret->{PROMOTED_VAMPIRE_DC_SERVER} = $ret->{SERVER};
+	$ret->{PROMOTED_VAMPIRE_DC_SERVER_IP} = $ret->{SERVER_IP};
+	$ret->{PROMOTED_VAMPIRE_DC_NETBIOSNAME} = $ret->{NETBIOSNAME};
+
+	$ret->{DC_SERVER} = $dcvars->{DC_SERVER};
+	$ret->{DC_SERVER_IP} = $dcvars->{DC_SERVER_IP};
+	$ret->{DC_NETBIOSNAME} = $dcvars->{DC_NETBIOSNAME};
+	$ret->{DC_USERNAME} = $dcvars->{DC_USERNAME};
+	$ret->{DC_PASSWORD} = $dcvars->{DC_PASSWORD};
+
+	return $ret;
+}
+
 sub provision_vampire_dc($$$)
 {
 	my ($self, $prefix, $dcvars) = @_;
@@ -1486,6 +1558,11 @@ sub setup_env($$$)
 			$self->setup_dc("$path/dc");
 		}
 		return $self->setup_vampire_dc("$path/vampire_dc", $self->{vars}->{dc});
+	} elsif ($envname eq "promoted_vampire_dc") {
+		if (not defined($self->{vars}->{dc})) {
+			$self->setup_dc("$path/dc");
+		}
+		return $self->setup_promoted_vampire_dc("$path/promoted_vampire_dc", $self->{vars}->{dc});
 	} elsif ($envname eq "subdom_dc") {
 		if (not defined($self->{vars}->{dc})) {
 			$self->setup_dc("$path/dc");
@@ -1659,7 +1736,59 @@ sub setup_vampire_dc($$$)
 		my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
 		$cmd = "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\"";
 		$cmd .= " KRB5_CONFIG=\"$env->{KRB5_CONFIG}\"";
-		$cmd .= " $samba_tool drs replicate $env->{DC_SERVER} $env->{VAMPIRE_DC_SERVER}";
+		$cmd .= " $samba_tool drs replicate $env->{DC_SERVER} $env->{SERVER}";
+		$cmd .= " $dc_vars->{CONFIGURATION}";
+		$cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
+		# replicate Configuration NC
+		my $cmd_repl = "$cmd \"CN=Configuration,$base_dn\"";
+		unless(system($cmd_repl) == 0) {
+			warn("Failed to replicate\n$cmd_repl");
+			return undef;
+		}
+		# replicate Default NC
+		$cmd_repl = "$cmd \"$base_dn\"";
+		unless(system($cmd_repl) == 0) {
+			warn("Failed to replicate\n$cmd_repl");
+			return undef;
+		}
+	}
+
+	return $env;
+}
+
+sub setup_promoted_vampire_dc($$$)
+{
+	my ($self, $path, $dc_vars) = @_;
+
+	my $env = $self->provision_promoted_vampire_dc($path, $dc_vars);
+
+	if (defined $env) {
+		$self->check_or_start($env, "single");
+
+		$self->wait_for_start($env);
+
+		$self->{vars}->{promoted_vampire_dc} = $env;
+
+		# force replicated DC to update repsTo/repsFrom
+		# for vampired partitions
+		my $samba_tool =  Samba::bindir_path($self, "samba-tool");
+		my $cmd = "";
+		$cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\"";
+		$cmd .= " KRB5_CONFIG=\"$env->{KRB5_CONFIG}\"";
+		$cmd .= " $samba_tool drs kcc $env->{DC_SERVER}";
+		$cmd .= " $env->{CONFIGURATION}";
+		$cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
+		unless (system($cmd) == 0) {
+			warn("Failed to exec kcc\n$cmd");
+			return undef;
+		}
+
+		# as 'vampired' dc may add data in its local replica
+		# we need to synchronize data between DCs
+		my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
+		$cmd = "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\"";
+		$cmd .= " KRB5_CONFIG=\"$env->{KRB5_CONFIG}\"";
+		$cmd .= " $samba_tool drs replicate $env->{DC_SERVER} $env->{SERVER}";
 		$cmd .= " $dc_vars->{CONFIGURATION}";
 		$cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
 		# replicate Configuration NC
diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c
index 481ff60..ec4dffe 100644
--- a/source4/dsdb/repl/replicated_objects.c
+++ b/source4/dsdb/repl/replicated_objects.c
@@ -203,6 +203,7 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 	struct ldb_message *msg;
 	struct replPropertyMetaDataBlob *md;
 	struct ldb_val guid_value;
+	struct ldb_val parent_guid_value;
 	NTTIME whenChanged = 0;
 	time_t whenChanged_t;
 	const char *whenChanged_s;
@@ -375,8 +376,18 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 		return ntstatus_to_werror(nt_status);
 	}
 
+	if (in->parent_object_guid) {
+		nt_status = GUID_to_ndr_blob(in->parent_object_guid, msg, &parent_guid_value);
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			return ntstatus_to_werror(nt_status);
+		}
+	} else {
+		parent_guid_value = data_blob_null;
+	}
+
 	out->msg		= msg;
 	out->guid_value		= guid_value;
+	out->parent_guid_value	= parent_guid_value;
 	out->when_changed	= whenChanged_s;
 	out->meta_data		= md;
 	return WERR_OK;
diff --git a/source4/dsdb/samdb/ldb_modules/operational.c b/source4/dsdb/samdb/ldb_modules/operational.c
index 79a1d6f..4ce8b8f 100644
--- a/source4/dsdb/samdb/ldb_modules/operational.c
+++ b/source4/dsdb/samdb/ldb_modules/operational.c
@@ -309,9 +309,9 @@ static int construct_parent_guid(struct ldb_module *module,
 
 	/* not NC, so the object should have a parent*/
 	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
-		DEBUG(4,(__location__ ": Parent dn for %s does not exist \n",
-			 ldb_dn_get_linearized(msg->dn)));
-		return ldb_operr(ldb_module_get_ctx(module));
+		return ldb_error(ldb_module_get_ctx(module), LDB_ERR_OPERATIONS_ERROR, 
+				 talloc_asprintf(msg, "Parent dn for %s does not exist", 
+						 ldb_dn_get_linearized(msg->dn)));
 	} else if (ret != LDB_SUCCESS) {
 		return ret;
 	}
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 49fca5f..1dc7ea0 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -3671,6 +3671,122 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
 	return ldb_next_request(ar->module, change_req);
 }
 
+static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
+							      struct ldb_reply *ares)
+{
+	struct replmd_replicated_request *ar = talloc_get_type(req->context,
+					       struct replmd_replicated_request);
+	int ret;
+
+	if (!ares) {
+		return ldb_module_done(ar->req, NULL, NULL,
+					LDB_ERR_OPERATIONS_ERROR);
+	}
+	if (ares->error != LDB_SUCCESS &&
+	    ares->error != LDB_ERR_NO_SUCH_OBJECT) {
+		return ldb_module_done(ar->req, ares->controls,
+					ares->response, ares->error);
+	}
+
+	switch (ares->type) {
+	case LDB_REPLY_ENTRY:
+	{
+		struct ldb_message *parent_msg = ares->message;
+		struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
+		struct ldb_dn *parent_dn;
+		int comp_num = ldb_dn_get_comp_num(msg->dn);
+		if (comp_num > 1) {
+			if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
+				talloc_free(ares);
+				return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
+			}
+		}
+		if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
+		    && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
+			/* Per MS-DRSR 4.1.10.6.10
+			 * FindBestParentObject we need to move this
+			 * new object under a deleted object to
+			 * lost-and-found */
+			
+			ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
+						ldb_get_default_basedn(ldb_module_get_ctx(ar->module)),
+						DS_GUID_LOSTANDFOUND_CONTAINER,
+						&parent_dn);
+			if (ret != LDB_SUCCESS) {
+				return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
+			}
+		} else {
+			parent_dn = parent_msg->dn;
+		}
+		if (!ldb_dn_add_base(msg->dn, parent_dn)) {
+			talloc_free(ares);
+			return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
+		}
+		break;
+	}
+	case LDB_REPLY_REFERRAL:
+		/* we ignore referrals */
+		break;
+
+	case LDB_REPLY_DONE:
+		ret = replmd_replicated_apply_add(ar);
+		if (ret != LDB_SUCCESS) {
+			return ldb_module_done(ar->req, NULL, NULL, ret);
+		}
+	}
+
+	talloc_free(ares);
+	return LDB_SUCCESS;
+}
+
+/*
+ * Look for the parent object, so we put the new object in the right place
+ */
+
+static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
+{
+	struct ldb_context *ldb;
+	int ret;
+	char *tmp_str;
+	char *filter;
+	struct ldb_request *search_req;
+	static const char *attrs[] = {"isDeleted", NULL};
+
+	ldb = ldb_module_get_ctx(ar->module);
+
+	if (!ar->objs->objects[ar->index_current].parent_guid_value.data) {
+		return replmd_replicated_apply_add(ar);
+	}
+
+	tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].parent_guid_value);
+	if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
+
+	filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
+	if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
+	talloc_free(tmp_str);
+
+	ret = ldb_build_search_req(&search_req,
+				   ldb,
+				   ar,
+				   ar->objs->partition_dn,
+				   LDB_SCOPE_SUBTREE,
+				   filter,
+				   attrs,
+				   NULL,
+				   ar,
+				   replmd_replicated_apply_search_for_parent_callback,
+				   ar->req);
+	LDB_REQ_SET_LOCATION(search_req);
+
+	ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
+				      true, NULL);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
+
+	return ldb_next_request(ar->module, search_req);
+}
+
 /*
   handle renames that come in over DRS replication
  */
@@ -3964,7 +4080,7 @@ static int replmd_replicated_apply_search_callback(struct ldb_request *req,
 		if (ar->search_msg != NULL) {
 			ret = replmd_replicated_apply_merge(ar);
 		} else {
-			ret = replmd_replicated_apply_add(ar);
+			ret = replmd_replicated_apply_search_for_parent(ar);
 		}
 		if (ret != LDB_SUCCESS) {
 			return ldb_module_done(ar->req, NULL, NULL, ret);
diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h
index 3e2f4a2..5422218 100644
--- a/source4/dsdb/samdb/samdb.h
+++ b/source4/dsdb/samdb/samdb.h
@@ -129,6 +129,7 @@ struct dsdb_control_password_change {
 struct dsdb_extended_replicated_object {
 	struct ldb_message *msg;
 	struct ldb_val guid_value;
+	struct ldb_val parent_guid_value;
 	const char *when_changed;
 	struct replPropertyMetaDataBlob *meta_data;
 };
diff --git a/source4/scripting/python/samba/join.py b/source4/scripting/python/samba/join.py
index 9ef7d3d..0d21279 100644
--- a/source4/scripting/python/samba/join.py
+++ b/source4/scripting/python/samba/join.py
@@ -47,8 +47,9 @@ class dc_join(object):
     '''perform a DC join'''
 
     def __init__(ctx, server=None, creds=None, lp=None, site=None,
-            netbios_name=None, targetdir=None, domain=None,
-            machinepass=None, use_ntvfs=False, dns_backend=None):
+                 netbios_name=None, targetdir=None, domain=None,
+                 machinepass=None, use_ntvfs=False, dns_backend=None,
+                 promote_existing=False):
         ctx.creds = creds
         ctx.lp = lp
         ctx.site = site
@@ -60,6 +61,9 @@ class dc_join(object):
         else:
             ctx.dns_backend = dns_backend
 
+        ctx.promote_existing = promote_existing
+        ctx.promote_from_dn = None
+
         ctx.nc_list = []
         ctx.full_nc_list = []
 
@@ -203,6 +207,25 @@ class dc_join(object):
         except Exception:
             pass
 
+    def promote_possible(ctx):
+        '''confirm that the account is just a bare NT4 BDC or a member server, so can be safely promoted'''
+        if ctx.subdomain:
+            # This shouldn't happen
+            raise Exception("Can not promote into a subdomain")
+
+        res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(),
+                               expression='sAMAccountName=%s' % ldb.binary_encode(ctx.samname),
+                               attrs=["msDS-krbTgtLink", "userAccountControl", "serverReferenceBL", "rIDSetReferences"])
+        if len(res) == 0:
+            raise Exception("Could not find domain member account '%s' to promote to a DC, use 'samba-tool domain join' instead'" % ctx.samname)
+        if "msDS-krbTgtLink" in res[0] or "serverReferenceBL" in res[0] or "rIDSetReferences" in res[0]:
+            raise Exception("Account '%s' appears to be an active DC, use 'samba-tool domain join' if you must re-create this account" % ctx.samname)
+        if (int(res[0]["userAccountControl"][0]) & (samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT|samba.dsdb.UF_SERVER_TRUST_ACCOUNT) == 0):
+            raise Exception("Account %s is not a domain member or a bare NT4 BDC, use 'samba-tool domain join' instead'" % ctx.samname)
+        
+        ctx.promote_from_dn = res[0].dn
+
+
     def find_dc(ctx, domain):
         '''find a writeable DC for the given domain'''
         try:
@@ -439,13 +462,29 @@ class dc_join(object):
                 "dnshostname" : ctx.dnshostname}
             if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2008:
                 rec['msDS-SupportedEncryptionTypes'] = str(samba.dsdb.ENC_ALL_TYPES)
+            elif ctx.promote_existing:
+                rec['msDS-SupportedEncryptionTypes'] = []
             if ctx.managedby:
                 rec["managedby"] = ctx.managedby
+            elif ctx.promote_existing:
+                rec["managedby"] = []
+
             if ctx.never_reveal_sid:
                 rec["msDS-NeverRevealGroup"] = ctx.never_reveal_sid
+            elif ctx.promote_existing:
+                rec["msDS-NeverRevealGroup"] = []
+                
             if ctx.reveal_sid:
                 rec["msDS-RevealOnDemandGroup"] = ctx.reveal_sid
-            ctx.samdb.add(rec)
+            elif ctx.promote_existing:
+                rec["msDS-RevealOnDemandGroup"] = []
+
+            if ctx.promote_existing:
+                if ctx.promote_from_dn != ctx.acct_dn:
+                    ctx.samdb.rename(ctx.promote_from_dn, ctx.acct_dn)
+                ctx.samdb.modify(ldb.Message.from_dict(ctx.samdb, rec, ldb.FLAG_MOD_REPLACE))
+            else:
+                ctx.samdb.add(rec)
 
         if ctx.krbtgt_dn:
             ctx.add_krbtgt_account()
@@ -490,7 +529,7 @@ class dc_join(object):
             for i in range(len(ctx.SPNs)):
                 ctx.SPNs[i] = ctx.SPNs[i].replace("$NTDSGUID", str(ctx.ntds_guid))
             m["servicePrincipalName"] = ldb.MessageElement(ctx.SPNs,
-                                                           ldb.FLAG_MOD_ADD,
+                                                           ldb.FLAG_MOD_REPLACE,
                                                            "servicePrincipalName")
             ctx.samdb.modify(m)
 
@@ -908,8 +947,11 @@ class dc_join(object):
             ctx.full_nc_list += ['DC=ForestDnsZones,%s' % ctx.root_dn]
             ctx.nc_list += ['DC=ForestDnsZones,%s' % ctx.root_dn]
 
-
-        ctx.cleanup_old_join()
+        if ctx.promote_existing:
+            ctx.promote_possible()
+        else:
+            ctx.cleanup_old_join()
+            
         try:
             ctx.join_add_objects()
             ctx.join_provision()
@@ -927,11 +969,12 @@ class dc_join(object):
 
 def join_RODC(server=None, creds=None, lp=None, site=None, netbios_name=None,
               targetdir=None, domain=None, domain_critical_only=False,
-              machinepass=None, use_ntvfs=False, dns_backend=None):
+              machinepass=None, use_ntvfs=False, dns_backend=None,
+              promote_existing=False):
     """join as a RODC"""
 
     ctx = dc_join(server, creds, lp, site, netbios_name, targetdir, domain,
-                  machinepass, use_ntvfs, dns_backend)
+                  machinepass, use_ntvfs, dns_backend, promote_existing)
 
     lp.set("workgroup", ctx.domain_name)
     print("workgroup is %s" % ctx.domain_name)
@@ -981,10 +1024,11 @@ def join_RODC(server=None, creds=None, lp=None, site=None, netbios_name=None,
 


-- 
Samba Shared Repository


More information about the samba-cvs mailing list