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 <[email protected]>
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 <[email protected]>
    Autobuild-Date(master): Fri Jul  6 09:59:13 CEST 2012 on sn-devel-104

commit 2908bbe06a3905007864c6caeaa77fb46cc442ef
Author: Andrew Bartlett <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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

Reply via email to