This patch does two things:

1. Prompts when deleting a master to make clear that this is irreversible
2. Does not allow a deleted master to be reconnected.

Reconnecting to a deleted master causes all heck to break loose because we delete principals as part of deletion process. If you reconnect to a deleted master then we replicate those deletes and the connected master is now unusable (no principals).

A simple test is:

Install master
Install replica
ipa-replica-manage del replica
ipa-replica-manage connect replica
ipa-server-uninstall -U on replica
re-install replica

The re-install should be successful.

>From 708e2ed1b0950c165ef16c8725a42f3fb2e09ffb Mon Sep 17 00:00:00 2001
From: Rob Crittenden <>
Date: Fri, 24 Feb 2012 18:17:47 -0500
Subject: [PATCH] Warn that deleting replica is irreversible, try to detect

Using ipa-replica-manage del <replica> is irreversible. You can't
turn around and do a connect to it, all heck will break loose. This is
because we clean up all references to the replica when we delete so if
we connect to it again we'll end up deleting all of its principals.

When a connection is deleted then the agreement is removed on both sides.
What isn't removed is the nsDS5ReplicaBindDN so we can use that to
determine if we previously had a connection.
 install/tools/ipa-replica-manage |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index c804ccb..abaaa52 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -29,6 +29,7 @@ from ipaserver.install import bindinstance
 from ipaserver import ipaldap
 from ipapython import version
 from ipalib import api, errors, util
+from ipalib.dn import DN
 from ipapython.ipa_log_manager import *
 CACERT = "/etc/ipa/ca.crt"
@@ -287,6 +288,7 @@ def del_master(realm, hostname, options):
     # 3. If an IPA agreement connect to the master to be removed.
     repltype = thisrepl.get_agreement_type(hostname)
     if repltype == replication.IPA_REPLICA:
+        winsync = False
             delrepl = replication.ReplicationManager(realm, hostname, options.dirman_passwd)
         except Exception, e:
@@ -308,8 +310,17 @@ def del_master(realm, hostname, options):
             replica_names = delrepl.find_ipa_replication_agreements()
         # WINSYNC replica, delete agreement from current host
+        winsync = True
         replica_names = []
+    if not winsync:
+        print "Deleting a master is irreversible."
+        print "To reconnect to the remote master you will need to prepare " \
+              "a new replica file"
+        print "and re-install."
+        if not ipautil.user_input("Continue to delete?", False):
+            sys.exit("Deletion aborted")
     # 4. Remove each agreement
     for r in replica_names:
@@ -390,6 +401,18 @@ def add_link(realm, replica1, replica2, dirman_passwd, options):
                                         options.passsync, options.win_subtree,
+        # First see if we already exist on the remote master. If so this was
+        # a previously deleted connection.
+        try:
+            repl2 = replication.ReplicationManager(realm, replica2, dirman_passwd)
+            master_dn = repl2.replica_dn()
+            binddn = str(DN(('krbprincipalname','ldap/%s@%s' % (replica1, api.env.realm)),(api.env.container_service),(api.env.basedn)))
+            master = repl2.conn.getEntry(master_dn, ldap.SCOPE_BASE)
+            binddns = master.getValues('nsDS5ReplicaBindDN')
+            if binddns and binddn in binddns:
+                sys.exit("You cannot connect to a previously deleted master")
+        except errors.NotFound:
+            pass
         repl1.setup_gssapi_replication(replica2, "cn=Directory Manager", dirman_passwd)
     print "Connected '%s' to '%s'" % (replica1, replica2)

Freeipa-devel mailing list

Reply via email to