summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLudwig Krispenz <lkrispen@redhat.com>2015-05-20 17:28:39 +0200
committerPetr Vobornik <pvoborni@redhat.com>2015-05-26 10:40:29 +0200
commit25bf0c6e78dca62e7fa11cd654ed0d8675408176 (patch)
tree732cda7366308c4e7e8920ac0e922c8dfedbc9c6
parentc5f319d3e8d1b5e500225af207ac247f75baea17 (diff)
downloadfreeipa-25bf0c6e78dca62e7fa11cd654ed0d8675408176.tar.gz
freeipa-25bf0c6e78dca62e7fa11cd654ed0d8675408176.tar.xz
freeipa-25bf0c6e78dca62e7fa11cd654ed0d8675408176.zip
ds plugin - manage replication topology in the shared tree
Implementation of ticket: https://fedorahosted.org/freeipa/ticket/4302 Design page: http://www.freeipa.org/page/V4/Manage_replication_topology Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
-rw-r--r--daemons/configure.ac1
-rw-r--r--daemons/ipa-slapi-plugins/Makefile.am1
-rw-r--r--daemons/ipa-slapi-plugins/topology/Makefile.am51
-rwxr-xr-xdaemons/ipa-slapi-plugins/topology/ipa-topology-conf.ldif20
-rw-r--r--daemons/ipa-slapi-plugins/topology/topology.h302
-rw-r--r--daemons/ipa-slapi-plugins/topology/topology_agmt.c314
-rw-r--r--daemons/ipa-slapi-plugins/topology/topology_cfg.c888
-rw-r--r--daemons/ipa-slapi-plugins/topology/topology_init.c313
-rw-r--r--daemons/ipa-slapi-plugins/topology/topology_post.c272
-rw-r--r--daemons/ipa-slapi-plugins/topology/topology_pre.c458
-rw-r--r--daemons/ipa-slapi-plugins/topology/topology_util.c1441
-rw-r--r--freeipa.spec.in2
-rw-r--r--install/share/70topology.ldif15
-rw-r--r--install/share/Makefile.am1
14 files changed, 4079 insertions, 0 deletions
diff --git a/daemons/configure.ac b/daemons/configure.ac
index 7c979fe2d..f2eebee51 100644
--- a/daemons/configure.ac
+++ b/daemons/configure.ac
@@ -362,6 +362,7 @@ AC_CONFIG_FILES([
ipa-slapi-plugins/ipa-modrdn/Makefile
ipa-slapi-plugins/ipa-sidgen/Makefile
ipa-slapi-plugins/ipa-range-check/Makefile
+ ipa-slapi-plugins/topology/Makefile
])
AC_OUTPUT
diff --git a/daemons/ipa-slapi-plugins/Makefile.am b/daemons/ipa-slapi-plugins/Makefile.am
index 07733921e..39f9142fd 100644
--- a/daemons/ipa-slapi-plugins/Makefile.am
+++ b/daemons/ipa-slapi-plugins/Makefile.am
@@ -16,6 +16,7 @@ SUBDIRS = \
ipa-winsync \
ipa-sidgen \
ipa-range-check \
+ topology \
$(NULL)
EXTRA_DIST = \
diff --git a/daemons/ipa-slapi-plugins/topology/Makefile.am b/daemons/ipa-slapi-plugins/topology/Makefile.am
new file mode 100644
index 000000000..8f3fa3b00
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/topology/Makefile.am
@@ -0,0 +1,51 @@
+NULL =
+
+PLUGIN_COMMON_DIR=../common
+
+AM_CPPFLAGS = \
+ -I. \
+ -I$(srcdir) \
+ -I$(PLUGIN_COMMON_DIR) \
+ -I/usr/include/dirsrv \
+ -DPREFIX=\""$(prefix)"\" \
+ -DBINDIR=\""$(bindir)"\" \
+ -DLIBDIR=\""$(libdir)"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DDATADIR=\""$(datadir)"\" \
+ $(LDAP_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(NULL)
+
+plugindir = $(libdir)/dirsrv/plugins
+plugin_LTLIBRARIES = \
+ libtopology.la \
+ $(NULL)
+
+libtopology_la_SOURCES = \
+ topology_agmt.c \
+ topology_init.c \
+ topology_cfg.c \
+ topology_post.c \
+ topology_pre.c \
+ topology_util.c \
+ $(NULL)
+
+libtopology_la_LDFLAGS = -avoid-version
+
+#libtopology_la_LIBADD = \
+# $(LDAP_LIBS) \
+# $(NULL)
+
+appdir = $(IPA_DATA_DIR)
+app_DATA = \
+ ipa-topology-conf.ldif \
+ $(NULL)
+
+EXTRA_DIST = \
+ README \
+ $(app_DATA) \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ Makefile.in
diff --git a/daemons/ipa-slapi-plugins/topology/ipa-topology-conf.ldif b/daemons/ipa-slapi-plugins/topology/ipa-topology-conf.ldif
new file mode 100755
index 000000000..9b7e5ebf8
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/topology/ipa-topology-conf.ldif
@@ -0,0 +1,20 @@
+dn: cn=IPA Topology Configuration,cn=plugins,cn=config
+changetype: add
+objectClass: top
+objectClass: nsSlapdPlugin
+objectClass: extensibleObject
+cn: IPA Topology Configuration
+nsslapd-pluginPath: libtopology
+nsslapd-pluginInitfunc: ipa_topo_init
+nsslapd-pluginType: object
+nsslapd-pluginEnabled: on
+nsslapd-topo-plugin-shared-config-base: cn=ipa,cn=etc,$SUFFIX
+nsslapd-topo-plugin-shared-replica-root: $SUFFIX
+nsslapd-topo-plugin-shared-binddngroup: cn=replication managers,cn=etc,$SUFFIX
+nsslapd-topo-plugin-startup-delay: 20
+nsslapd-pluginId: none
+nsslapd-plugin-depends-on-named: ldbm database
+nsslapd-plugin-depends-on-named: Multimaster Replication Plugin
+nsslapd-pluginVersion: 1.0
+nsslapd-pluginVendor: none
+nsslapd-pluginDescription: none
diff --git a/daemons/ipa-slapi-plugins/topology/topology.h b/daemons/ipa-slapi-plugins/topology/topology.h
new file mode 100644
index 000000000..38c2823f5
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/topology/topology.h
@@ -0,0 +1,302 @@
+
+/**
+ * IPA Replication Topology Plugin
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include "slapi-plugin.h"
+
+#define PLUGIN_NAME "ipa-topology-plugin"
+#define PLUGIN_VENDOR "freeipa"
+#define PLUGIN_VERSION "1.0"
+
+#define IPA_TOPO_PLUGIN_SUBSYSTEM "ipa-topology-plugin"
+#define IPA_TOPO_PREOP_DESC "ipa-topology-preop-subplugin"
+#define IPA_TOPO_POSTOP_DESC "ipa-topology-postop-subplugin"
+#define IPA_TOPO_INTERNAL_POSTOP_DESC "ipa-topology-internal-postop-subplugin"
+
+#define AGMT_TIMEOUT "300"
+#define REPL_MAN_DN "cn=replman,cn=config"
+#define REPL_MAN_PASSWD "replman"
+#define REPL_ATTR_LIST "(objectclass=*) $ EXCLUDE memberof idnssoaserial " \
+ "entryusn krblastsuccessfulauth krblastfailedauth "\
+ "krbloginfailedcount"
+#define REPL_ATTR_STRIP "modifiersName modifyTimestamp internalModifiersName "\
+ "internalModifyTimestamp"
+#define REPL_ATTR_LIST_TOTAL "(objectclass=*) $ EXCLUDE entryusn "\
+ "krblastsuccessfulauth krblastfailedauth "\
+ "krbloginfailedcount"
+
+#define SEGMENT_DIR_BOTH "both"
+#define SEGMENT_DIR_LEFT_ORIGIN "left-right"
+#define SEGMENT_DIR_RIGHT_ORIGIN "right-left"
+#define SEGMENT_LEFT_RIGHT 0x01
+#define SEGMENT_RIGHT_LEFT 0x02
+#define SEGMENT_BIDIRECTIONAL 0x03
+#define SEGMENT_OBSOLETE 0x04
+#define SEGMENT_AUTOGEN 0x05
+#define SEGMENT_REMOVED 0x06
+#define SEGMENT_OBSOLETE_STR "obsolete"
+#define SEGMENT_AUTOGEN_STR "autogen"
+#define SEGMENT_REMOVED_STR "removed"
+#define TOPO_IGNORE_ENTRY 0
+#define TOPO_CONFIG_ENTRY 1
+#define TOPO_SEGMENT_ENTRY 2
+#define TOPO_HOST_ENTRY 3
+#define TOPO_DOMLEVEL_ENTRY 4
+
+typedef struct topo_replica_agmt {
+ char *rdn;
+ char *origin; /* supplier side of agmt */
+ char *target; /* consumer side of agmt */
+ char *enabled;
+ char *repl_root;
+ char *strip_attrs;
+ char *total_attrs;
+ char *repl_attrs;
+ char *repl_pause;
+ char *repl_timeout;
+ char *repl_refresh;
+ char *repl_transport;
+ char *repl_bind_dn;
+ char *repl_bind_cred;
+ char *repl_bind_method;
+} TopoReplicaAgmt;
+
+typedef struct topo_replica_segment {
+ char *name;
+ int direct;
+ char *from;
+ char *to;
+ int state;
+ TopoReplicaAgmt *left;
+ TopoReplicaAgmt *right;
+} TopoReplicaSegment;
+
+typedef struct topo_replica_segment_list {
+ struct topo_replica_segment_list *next;
+ TopoReplicaSegment *segm;
+ int visited;
+} TopoReplicaSegmentList;
+
+typedef struct topo_replica_host {
+ struct topo_replica_host *next;
+ char *hostname;
+} TopoReplicaHost;
+
+typedef struct topo_replica {
+ struct topo_replica *next;
+ Slapi_Mutex *repl_lock;
+ char *shared_config_base;
+ Slapi_DN *shared_config_sdn;
+ char *repl_root;
+ TopoReplicaSegmentList *repl_segments;
+ TopoReplicaHost *hosts;
+} TopoReplica;
+
+typedef struct topo_replica_conf {
+ Slapi_Mutex *conf_lock;
+ int startup_inprogress;
+ TopoReplica *replicas;
+ TopoReplicaHost *allhosts; /* maybe not needed */
+} TopoReplicaConf;
+
+typedef struct topo_plugin_config {
+ Slapi_Mutex *plg_lock;
+ void *identity;
+ int version_major;
+ int version_minor;
+ int startup_delay;
+ char *hostname;
+ char *shared_config_base;
+ char *shared_topo;
+ Slapi_DN *shared_topo_sdn;
+ char *shared_hosts;
+ Slapi_DN *shared_hosts_sdn;
+ char *shared_bindgroup;
+ Slapi_DN *shared_bindgroup_sdn;
+ char *domain_level;
+ Slapi_DN *domain_level_sdn;
+ char **shared_replica_root;
+ char **managed_attrs;
+ char **restricted_attrs;
+ int activated;
+} TopoPluginConf;
+
+typedef struct ipa_domain_level {
+ int major;
+ int minor;
+} IpaDomainLevel;
+
+#define CONFIG_ATTR_SHARED_BASE "nsslapd-topo-plugin-shared-config-base"
+#define CONFIG_ATTR_REPLICA_ROOT "nsslapd-topo-plugin-shared-replica-root"
+#define CONFIG_ATTR_SHARED_BINDDNGROUP "nsslapd-topo-plugin-shared-binddngroup"
+#define CONFIG_ATTR_STARTUP_DELAY "nsslapd-topo-plugin-startup-delay"
+#define CONFIG_ATTR_PLUGIN_ACTIVE "nsslapd-topo-plugin-activated"
+#define CONFIG_ATTR_PLUGIN_VERSION "nsslapd-pluginVersion"
+
+/* functions to manage config and global variables */
+int ipa_topo_init_plugin_config(Slapi_PBlock *pb);
+void ipa_topo_init_shared_config(void);
+int ipa_topo_init_config(Slapi_PBlock *pb);
+void *ipa_topo_get_plugin_id(void);
+int ipa_topo_get_plugin_active(void);
+char *ipa_topo_get_plugin_shared_config(void);
+Slapi_DN *ipa_topo_get_plugin_shared_topo_dn(void);
+Slapi_DN *ipa_topo_get_plugin_shared_hosts_dn(void);
+Slapi_DN *ipa_topo_get_plugin_shared_bindgroup_dn(void);
+char *ipa_topo_get_plugin_shared_topo(void);
+char *ipa_topo_get_plugin_shared_hosts(void);
+char *ipa_topo_get_plugin_shared_bindgroup(void);
+char *ipa_topo_get_plugin_hostname(void);
+char **ipa_topo_get_plugin_replica_root(void);
+char **ipa_topo_get_plugin_managed_attrs(void);
+char **ipa_topo_get_plugin_restricted_attrs(void);
+int ipa_topo_get_plugin_version_major(void);
+int ipa_topo_get_plugin_version_minor(void);
+char *ipa_topo_get_domain_level_entry(void);
+Slapi_DN *ipa_topo_get_domain_level_entry_dn(void);
+int ipa_topo_get_domain_level_major(void);
+int ipa_topo_get_domain_level_minor(void);
+int ipa_topo_get_plugin_startup_delay(void);
+void ipa_topo_set_plugin_id(void *plg_id);
+void ipa_topo_set_plugin_active(int state);
+void ipa_topo_set_plugin_shared_config(char *);
+void ipa_topo_set_plugin_hostname(char *hostname);
+void ipa_topo_set_plugin_replica_root(char **roots);
+void ipa_topo_set_plugin_managed_attrs(char **mattrs);
+void ipa_topo_set_plugin_restricted_attrs(char **mattrs);
+void ipa_topo_set_plugin_startup_delay(char *delay);
+void ipa_topo_set_plugin_version(char *version);
+int ipa_topo_cfg_plugin_suffix_is_managed(const char *be_suffix);
+void ipa_topo_free_plugin_config(void);
+void ipa_topo_set_domain_level(char *level);
+void ipa_topo_util_check_plugin_active(void);
+void ipa_topo_lock_conf(void);
+void ipa_topo_unlock_conf(void);
+int ipa_topo_acquire_startup_inprogress(void);
+void ipa_topo_release_startup_inprogress(void);
+void ipa_topo_cfg_host_add(Slapi_Entry *hostentry);
+void ipa_topo_cfg_host_del(Slapi_Entry *hostentry);
+TopoReplicaHost *ipa_topo_cfg_host_find(TopoReplica *tconf, char *host, int lock);
+TopoReplicaHost *ipa_topo_cfg_host_new(char *newhost);
+TopoReplicaSegment *
+ipa_topo_cfg_segment_find(char *repl_root, char *leftHost, char *rightHost);
+TopoReplicaSegment *
+ipa_topo_cfg_replica_segment_find(TopoReplica *tconf, char *leftHost,
+ char *rightHost, int lock);
+void ipa_topo_cfg_segment_set_visited(TopoReplica *tconf, TopoReplicaSegment *tsegm);
+void ipa_topo_cfg_segment_add(TopoReplica *tconf, TopoReplicaSegment *tsegm);
+void ipa_topo_cfg_segment_del(TopoReplica *tconf, TopoReplicaSegment *tsegm);
+void ipa_topo_cfg_segment_free(TopoReplicaSegment *tsegm);
+TopoReplicaSegment *ipa_topo_cfg_segment_dup(TopoReplicaSegment *orig);
+TopoReplicaAgmt *ipa_topo_cfg_agmt_dup(TopoReplicaAgmt *agmt);
+TopoReplicaAgmt *ipa_topo_cfg_agmt_dup_reverse(TopoReplicaAgmt *agmt);
+TopoReplica *ipa_topo_cfg_replica_new(void);
+int ipa_topo_cfg_replica_add(TopoReplica *tconf);
+void ipa_topo_cfg_replica_del(TopoReplica *tconf);
+void ipa_topo_cfg_replica_free(TopoReplica *tconf);
+TopoReplica *ipa_topo_cfg_replica_find(char *repl_root, int lock);
+
+/* pre and postop plugin functions */
+int ipa_topo_check_entry_type(Slapi_Entry *entry);
+/* postop plugin functions */
+int ipa_topo_post_add(Slapi_PBlock *pb);
+int ipa_topo_post_mod(Slapi_PBlock *pb);
+int ipa_topo_post_del(Slapi_PBlock *pb);
+
+/* preop plugin functions */
+int ipa_topo_pre_add(Slapi_PBlock *pb);
+int ipa_topo_pre_mod(Slapi_PBlock *pb);
+int ipa_topo_pre_del(Slapi_PBlock *pb);
+
+/* functions to modify agreements */
+int ipa_topo_agmt_new(char *hostname, TopoReplica *repl_conf,
+ TopoReplicaAgmt *agmt);
+int ipa_topo_agmt_del_dn(char *dn);
+int ipa_topo_agmt_del(char *hostname, TopoReplica *conf,
+ TopoReplicaAgmt *agmt);
+int ipa_topo_agmt_mod(TopoReplica *conf, TopoReplicaAgmt *agmt,
+ LDAPMod **mod, char *direction);
+int ipa_topo_agmt_setup(char *hostname, TopoReplica *repl_conf,
+ TopoReplicaAgmt *agmt, int isgssapi);
+int ipa_topo_setup_std_agmt(char *hostname, TopoReplica *repl_conf,
+ TopoReplicaAgmt *agmt);
+int ipa_topo_setup_gssapi_agmt(char *hostname, TopoReplica *repl_conf,
+ TopoReplicaAgmt *agmt);
+void ipa_topo_queue_apply_shared_config(time_t event_time, void *arg);
+int ipa_topo_apply_shared_config(void);
+int ipa_topo_setup_managed_servers(void);
+int ipa_topo_util_start(int delay);
+int ipa_topo_util_update_agmt_list(TopoReplica *repl_conf,
+ TopoReplicaSegmentList *repl_segments);
+char *ipa_topo_agmt_gen_rdn(char *from, char *to);
+char *ipa_topo_agmt_std_rdn(char *to);
+char *ipa_topo_agreement_dn(TopoReplica *conf, TopoReplicaAgmt *agmt, char *rdn);
+char *ipa_topo_segment_dn(TopoReplica *tconf, char *segname);
+void ipa_topo_util_segment_update(TopoReplica *repl_conf,
+ TopoReplicaSegment *repl_segment,
+ LDAPMod **mods ,char *fromHost);
+void ipa_topo_util_missing_agmts_add(TopoReplica *repl_conf,
+ TopoReplicaSegment *repl_segment,
+ char *fromHost);
+void ipa_topo_util_existing_agmts_del(TopoReplica *repl_conf,
+ TopoReplicaSegment *repl_segment,
+ char *fromHost);
+void ipa_topo_util_existing_agmts_update(TopoReplica *repl_conf,
+ TopoReplicaSegment *repl_segment,
+ LDAPMod **mods ,char *fromHost);
+void ipa_topo_util_missing_agmts_add_list(TopoReplica *repl_conf,
+ TopoReplicaSegmentList *repl_segments,
+ char *fromHost);
+void ipa_topo_util_existing_agmts_del_list(TopoReplica *repl_conf,
+ TopoReplicaSegmentList *repl_segments,
+ char *fromHost);
+void ipa_topo_util_existing_agmts_update_list(TopoReplica *repl_conf,
+ TopoReplicaSegmentList *repl_segments,
+ LDAPMod **mods ,char *fromHost);
+TopoReplicaAgmt *ipa_topo_util_agmt_from_entry(Slapi_Entry *entry,
+ char* replRoot, char *fromHost,
+ char *toHost, char *direction);
+TopoReplicaAgmt *
+ipa_topo_util_find_segment_agmt(TopoReplicaSegmentList *repl_segments,
+ char *fromHost, char *toHost);
+void ipa_topo_util_segm_update(TopoReplica *tconf, TopoReplicaSegment *tsegm,
+ int property);
+int ipa_topo_util_segment_write(TopoReplica *tconf, TopoReplicaSegment *tsegm);
+void ipa_topo_util_segm_remove(TopoReplica *tconf, TopoReplicaSegment *tsegm);
+void ipa_topo_util_segment_merge(TopoReplica *tconf,
+ TopoReplicaSegment *tsegm);
+int ipa_topo_util_agmt_mark(TopoReplica *tconf, Slapi_Entry * repl_agmt,
+ TopoReplicaSegment *tsegm);
+int ipa_topo_util_agmt_is_marked(Slapi_Entry * repl_agmt);
+char *ipa_topo_agmt_attr_is_managed(char *type, char *direction);
+int ipa_topo_cfg_attr_is_restricted(char *type);
+int ipa_topo_util_setup_servers(void);
+void ipa_topo_util_update_segments_for_host(Slapi_Entry *hostentry);
+char *ipa_topo_util_get_ldap_principal(char *repl_root, char *hostname);
+void ipa_topo_util_disable_repl_for_principal(char *repl_root, char *principal);
+void ipa_topo_util_delete_host(Slapi_Entry *hostentry);
+void ipa_topo_util_disable_repl_from_host(char *repl_root, char *delhost);
+void ipa_topo_util_delete_segments_for_host(char *repl_root, char *delhost);
+
+int ipa_topo_util_entry_is_candidate(Slapi_Entry *e);
+int ipa_topo_util_target_is_managed(Slapi_Entry *e);
+char * ipa_topo_util_get_segm_attr(TopoReplicaAgmt *agmt, char *attr_type);
+void ipa_topo_util_set_segm_attr(TopoReplicaAgmt *agmt, char *attr_type,
+ char *attr_val);
+TopoReplicaSegment *ipa_topo_util_segm_from_agmt(Slapi_Entry *repl_agmt);
+TopoReplicaSegment *ipa_topo_util_segment_from_entry(TopoReplica *conf,
+ Slapi_Entry *entry);
+TopoReplicaSegment *ipa_topo_util_find_segment(TopoReplica *conf,
+ Slapi_Entry *entry);
+TopoReplica *ipa_topo_util_conf_from_entry(Slapi_Entry *entry);
+TopoReplica *ipa_topo_util_get_conf_for_segment(Slapi_Entry *segment_entry);
+Slapi_Entry *ipa_topo_util_get_entry(char *dn);
+int ipa_topo_util_modify(Slapi_DN *entrySDN, Slapi_Mods *smods);
+char *ipa_topo_util_get_pluginhost(void);
+TopoReplica *ipa_topo_util_get_replica_conf(char *repl_root);
+TopoReplicaSegmentList *ipa_topo_util_get_replica_segments(TopoReplica *replica);
+void ipa_topo_util_set_domain_level(void);
diff --git a/daemons/ipa-slapi-plugins/topology/topology_agmt.c b/daemons/ipa-slapi-plugins/topology/topology_agmt.c
new file mode 100644
index 000000000..57614351e
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/topology/topology_agmt.c
@@ -0,0 +1,314 @@
+#include "topology.h"
+
+/* generate the dn for a topology segment by providing replroot and segment name */
+char *
+ipa_topo_segment_dn(TopoReplica *tconf, char *segname)
+{
+ char *dn = NULL;
+
+ dn = slapi_ch_smprintf("cn=%s,%s", segname, tconf->shared_config_base);
+ return dn;
+}
+
+/* generate the rdn for a replication agreement by providing connected nodes */
+char *
+ipa_topo_agmt_gen_rdn(char *from, char *to)
+{
+ char *agmt_rdn = slapi_ch_smprintf("cn=%s-to-%s", from, to);
+
+ return agmt_rdn;
+}
+
+/* generate the rdn for a replication agreement by providing target node */
+char *
+ipa_topo_agmt_std_rdn(char *to)
+{
+ char *agmt_rdn = slapi_ch_smprintf("cn=meTo%s", to);
+
+ return agmt_rdn;
+}
+
+/* generate the dn for a replication agreement by providing replroot and host */
+char *
+ipa_topo_agreement_dn(TopoReplica *conf, TopoReplicaAgmt *agmt, char *rdn)
+{
+ char *dn;
+ char *filter;
+ Slapi_PBlock *pb;
+ Slapi_Entry **entries;
+ int ret;
+
+ pb = slapi_pblock_new();
+ filter = slapi_ch_smprintf("(&(objectclass=nsds5replica)(nsds5replicaroot=%s))",
+ conf->repl_root);
+ slapi_search_internal_set_pb(pb, "cn=config", LDAP_SCOPE_SUB,
+ filter, NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret != 0) {
+ dn = NULL;
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_agreement_dn: no replica found\n");
+ dn = NULL;
+ } else if (rdn) {
+ dn = slapi_ch_smprintf("%s,%s", rdn,
+ slapi_entry_get_dn_const(entries[0]));
+ } else {
+ dn = slapi_ch_smprintf("cn=meTo%s,%s", agmt->target,
+ slapi_entry_get_dn_const(entries[0]));
+ }
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return dn;
+}
+int
+ipa_topo_agmt_new(char *hostname, TopoReplica *conf, TopoReplicaAgmt *agmt)
+{
+ int ret = 0;
+ if (strcasecmp(agmt->repl_bind_method,"SASL/GSSAPI") == 0) {
+ ret = ipa_topo_agmt_setup(hostname, conf, agmt, 1);
+ } else {
+ ret = ipa_topo_agmt_setup(hostname, conf, agmt, 0);
+ }
+ return ret;
+}
+
+int ipa_topo_agmt_mod(TopoReplica *conf, TopoReplicaAgmt *agmt, LDAPMod **mods,
+ char *direction)
+{
+ int ret;
+ Slapi_PBlock *pb;
+ char *dn = NULL;
+ Slapi_Entry **entries;
+ int i;
+ LDAPMod *tmp;
+ Slapi_Mods *smods = NULL;
+
+ dn = ipa_topo_agreement_dn(conf, agmt, agmt->rdn);
+ if (dn == NULL)
+ return 1;
+
+ pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(pb, dn, LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret != 0) {
+ /* search failed */
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_agmt_mod: agreement not found: %s\n", dn);
+ goto done;
+ }
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ /* no entry */
+ ret = 1;
+ goto done;
+ }
+ /* apply mods to entry */
+
+ smods = slapi_mods_new();
+ for (i = 0; (mods != NULL) && (mods[i] != NULL); i++) {
+ char *type = ipa_topo_agmt_attr_is_managed(mods[i]->mod_type,direction);
+ if (type) {
+ tmp = mods[i];
+ switch (tmp->mod_op & ~LDAP_MOD_BVALUES) {
+ case LDAP_MOD_DELETE:
+ break;
+ case LDAP_MOD_ADD:
+ case LDAP_MOD_REPLACE:
+ slapi_mods_add_modbvps(smods, LDAP_MOD_REPLACE,
+ type, tmp->mod_bvalues);
+ break;
+ }
+ slapi_ch_free_string(&type);
+ }
+ }
+ if (slapi_mods_get_num_mods(smods) > 0) {
+ Slapi_DN *sdn = slapi_sdn_new_normdn_byref(dn);
+ ipa_topo_util_modify(sdn, smods);
+ slapi_sdn_free(&sdn);
+ } else {
+ slapi_ch_free_string(&dn);
+ }
+ slapi_mods_free(&smods);
+done:
+ if (ret) slapi_ch_free_string(&dn);
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return ret;
+}
+
+int
+ipa_topo_agmt_del(char *hostname, TopoReplica *conf, TopoReplicaAgmt *agmt)
+{
+ char *dn = NULL;
+ int rc;
+
+ dn = ipa_topo_agreement_dn(conf, agmt, agmt->rdn);
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_agmt_del: %s\n", agmt->rdn?agmt->rdn:"RDN missing");
+ if (dn == NULL)
+ return (-1);
+
+ rc = ipa_topo_agmt_del_dn(dn);
+ slapi_ch_free_string(&dn);
+
+ return rc;
+}
+
+int
+ipa_topo_agmt_del_dn(char *dn)
+{
+ int ret = 0;
+ Slapi_PBlock *pb;
+ pb = slapi_pblock_new();
+ slapi_delete_internal_set_pb(pb, dn, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+
+ slapi_delete_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ slapi_pblock_destroy(pb);
+
+ return ret;
+}
+int
+ipa_topo_agmt_setup(char *hostname, TopoReplica *conf,
+ TopoReplicaAgmt *agmt, int isgssapi)
+{
+ Slapi_Entry *e = NULL;
+ Slapi_PBlock *pb;
+ char *dn = NULL;
+ Slapi_DN *sdn = NULL;
+ char *cn;
+ char port[] = "389";
+ char *description;
+ int ret;
+ /* Set up the new replication agreement entry */
+ agmt->rdn = ipa_topo_agmt_gen_rdn(agmt->origin, agmt->target);
+ dn = ipa_topo_agreement_dn(conf, agmt, agmt->rdn);
+ if (dn == NULL)
+ return -1;
+ sdn = slapi_sdn_new_normdn_byref(dn);
+ e = slapi_entry_alloc();
+ /* the entry now owns the dup'd dn */
+ slapi_entry_init_ext(e, sdn, NULL); /* sdn is copied into e */
+ slapi_sdn_free(&sdn);
+
+ slapi_entry_add_string(e, SLAPI_ATTR_OBJECTCLASS, "nsds5replicationagreement");
+ slapi_entry_add_string(e, SLAPI_ATTR_OBJECTCLASS, "ipaReplTopoManagedAgreement");
+ cn = slapi_ch_smprintf("%s-to-%s", agmt->origin, agmt->target);
+ slapi_entry_add_string(e, "cn",cn);
+ slapi_ch_free_string(&cn);
+ slapi_entry_add_string(e, "nsds5replicahost",hostname);
+ slapi_entry_add_string(e, "nsds5replicaport",port);
+ slapi_entry_add_string(e, "nsds5replicatimeout",AGMT_TIMEOUT);
+ slapi_entry_add_string(e, "nsds5replicaroot",agmt->repl_root);
+ description = slapi_ch_smprintf("%s to %s", ipa_topo_get_plugin_hostname(), hostname);
+ slapi_entry_add_string(e, "description",description);
+ slapi_ch_free_string(&description);
+ slapi_entry_add_string(e, "ipaReplTopoManagedAgreementState",
+ "managed agreement - generated by topology plugin");
+
+ if (isgssapi) {
+ slapi_entry_add_string(e, "nsds5replicatransportinfo","LDAP");
+ slapi_entry_add_string(e, "nsds5replicabindmethod","SASL/GSSAPI");
+ } else {
+ slapi_entry_add_string(e, "nsds5replicabinddn",REPL_MAN_DN);
+ slapi_entry_add_string(e, "nsds5replicacredentials",REPL_MAN_PASSWD);
+ slapi_entry_add_string(e, "nsds5replicatransportinfo","TLS");
+ slapi_entry_add_string(e, "nsds5replicabindmethod","simple");
+ }
+ if (agmt->repl_attrs) {
+ slapi_entry_add_string(e, "nsDS5ReplicatedAttributeList",agmt->repl_attrs);
+ } else {
+ slapi_entry_add_string(e, "nsDS5ReplicatedAttributeList", REPL_ATTR_LIST);
+ }
+ if (agmt->strip_attrs) {
+ slapi_entry_add_string(e, "nsds5ReplicaStripAttrs", agmt->strip_attrs);
+ } else {
+ slapi_entry_add_string(e, "nsds5ReplicaStripAttrs", REPL_ATTR_STRIP);
+ }
+ if (agmt->total_attrs) {
+ slapi_entry_add_string(e, "nsDS5ReplicatedAttributeListTotal",
+ agmt->total_attrs);
+ } else {
+ slapi_entry_add_string(e, "nsDS5ReplicatedAttributeListTotal",
+ REPL_ATTR_LIST_TOTAL);
+ }
+
+ pb = slapi_pblock_new();
+ slapi_pblock_init(pb);
+
+ /* e will be consumed by slapi_add_internal() */
+ slapi_add_entry_internal_set_pb(pb, e, NULL, ipa_topo_get_plugin_id(), 0);
+ slapi_add_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ slapi_pblock_destroy(pb);
+
+ return ret;
+}
+
+
+int
+ipa_topo_agmt_initialize_replication(char *hostname,
+ TopoReplica *conf, TopoReplicaAgmt *agmt)
+{
+ int ret = 0;
+ char *dn;
+ Slapi_Mods *smods = slapi_mods_new();
+
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "nsds5ReplicaEnabled", "on");
+ slapi_mods_add_string(smods, LDAP_MOD_ADD,
+ "nsds5BeginReplicaRefresh", "start");
+ if (slapi_mods_get_num_mods(smods) > 0) {
+ dn = ipa_topo_agreement_dn(conf, agmt, agmt->rdn);
+ Slapi_DN *sdn = slapi_sdn_new_normdn_byref(dn);
+ ipa_topo_util_modify(sdn, smods);
+ slapi_sdn_free(&sdn);
+ }
+ slapi_mods_free(&smods);
+ return ret;
+}
+
+char *
+ipa_topo_agmt_attr_is_managed(char *type, char *direction)
+{
+ char *mtype = NULL;
+ char **mattrs = NULL;
+ char *subtype;
+ char *ctype = slapi_ch_strdup(type);
+ int i;
+
+ /* segment attrs have the form
+ * attrtype od attrtype;direction
+ * find the attrtype and return the corresponding
+ * repl agreeement attribute type
+ */
+ subtype = strchr(ctype,';');
+ if (subtype) {
+ /* attr is handling specific direction,
+ * check if interested
+ */
+ if (strstr(ctype,direction)) {
+ *subtype = '\0';
+ } else {
+ return NULL;
+ }
+ }
+ mattrs = ipa_topo_get_plugin_managed_attrs();
+ for (i=0; mattrs[i]; i++) {
+ if(0 == strcasecmp(mattrs[i], ctype)) {
+ mtype = slapi_ch_strdup(mattrs[i]);
+ break;
+ }
+ }
+ return mtype;
+}
diff --git a/daemons/ipa-slapi-plugins/topology/topology_cfg.c b/daemons/ipa-slapi-plugins/topology/topology_cfg.c
new file mode 100644
index 000000000..17493495a
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/topology/topology_cfg.c
@@ -0,0 +1,888 @@
+
+#include "topology.h"
+
+/* two static data structures to hold the
+ * plugin configuration and the information
+ * stored in the shared tree.
+ * They will be initialized at plugin init/start,
+ * updated when the shared config is modified
+ * and accessed via set/get functions
+ */
+static TopoPluginConf topo_plugin_conf = {0};
+static TopoReplicaConf topo_shared_conf = {0};
+static IpaDomainLevel ipa_domain_level = {0,0};
+
+char *ipa_topo_plugin_managed_attrs[] = {
+ "nsds5ReplicaStripAttrs",
+ "nsds5ReplicatedAttributeList",
+ "nsDS5ReplicatedAttributeListTotal",
+ "nsds5BeginReplicaRefresh",
+ "nsds5replicaTimeout",
+ "nsds5ReplicaEnabled",
+ "nsds5replicaSessionPauseTime",
+ "nsds5replicabinddn",
+ "nsds5replicacredentials",
+ "nsds5replicatransportinfo",
+ "nsds5replicabindmethod",
+ NULL };
+
+/* subset of attrs which can only be modified via
+ * modification of segments in the shared tree.
+ * Other attributes still can be directly modified
+ * eg to reinit a replica or change bind method and
+ * credentials.
+ * This is currently needed to make ipa-replica-install work
+ */
+char *ipa_topo_plugin_restricted_attrs[] = {
+ "nsds5ReplicaStripAttrs",
+ "nsds5ReplicatedAttributeList",
+ "nsDS5ReplicatedAttributeListTotal",
+ "nsds5replicaTimeout",
+ "nsds5replicaSessionPauseTime",
+ NULL };
+
+void *
+ipa_topo_get_plugin_id(void)
+{
+ return topo_plugin_conf.identity;
+}
+
+char *
+ipa_topo_get_plugin_hostname(void)
+{
+ return topo_plugin_conf.hostname;
+}
+
+char **
+ipa_topo_get_plugin_managed_attrs(void)
+{
+ return topo_plugin_conf.managed_attrs;
+}
+
+char **
+ipa_topo_get_plugin_restricted_attrs(void)
+{
+ return topo_plugin_conf.restricted_attrs;
+}
+
+char *
+ipa_topo_get_plugin_shared_config(void)
+{
+ return topo_plugin_conf.shared_config_base;
+}
+char *
+ipa_topo_get_plugin_shared_topo(void)
+{
+ return topo_plugin_conf.shared_topo;
+}
+
+Slapi_DN *
+ipa_topo_get_plugin_shared_topo_dn(void)
+{
+ return topo_plugin_conf.shared_topo_sdn;
+}
+
+char *
+ipa_topo_get_domain_level_entry(void)
+{
+ return topo_plugin_conf.domain_level;
+}
+
+Slapi_DN *
+ipa_topo_get_domain_level_entry_dn(void)
+{
+ return topo_plugin_conf.domain_level_sdn;
+}
+
+int
+ipa_topo_get_domain_level_major(void)
+{
+ return ipa_domain_level.major;
+}
+
+int
+ipa_topo_get_domain_level_minor(void)
+{
+ return ipa_domain_level.minor;
+}
+
+char *
+ipa_topo_get_plugin_shared_hosts(void)
+{
+ return topo_plugin_conf.shared_hosts;
+}
+
+Slapi_DN *
+ipa_topo_get_plugin_shared_hosts_dn(void)
+{
+ return topo_plugin_conf.shared_hosts_sdn;
+}
+
+char *
+ipa_topo_get_plugin_shared_bindgroup(void)
+{
+ return topo_plugin_conf.shared_bindgroup;
+}
+
+Slapi_DN *
+ipa_topo_get_plugin_shared_bindgroup_dn(void)
+{
+ return topo_plugin_conf.shared_bindgroup_sdn;
+}
+char **
+ipa_topo_get_plugin_replica_root(void)
+{
+ return topo_plugin_conf.shared_replica_root;
+}
+
+int
+ipa_topo_get_plugin_version_major(void)
+{
+ return topo_plugin_conf.version_major;
+}
+
+int
+ipa_topo_get_plugin_version_minor(void)
+{
+ return topo_plugin_conf.version_minor;
+}
+
+int
+ipa_topo_get_plugin_startup_delay(void)
+{
+ return topo_plugin_conf.startup_delay;
+}
+
+void
+ipa_topo_set_plugin_id(void *plg_id)
+{
+ topo_plugin_conf.identity = plg_id;
+}
+
+void
+ipa_topo_set_plugin_active(int state)
+{
+ topo_plugin_conf.activated = state;
+}
+int
+ipa_topo_get_plugin_active(void)
+{
+ return topo_plugin_conf.activated;
+}
+
+void
+ipa_topo_set_plugin_shared_config(char *cfg)
+{
+ char *topo;
+ char *hosts;
+ char *domain_level;
+ topo_plugin_conf.shared_config_base = cfg;
+ topo = slapi_ch_smprintf("%s,%s","cn=topology",cfg);
+ hosts = slapi_ch_smprintf("%s,%s","cn=masters",cfg);
+ domain_level = slapi_ch_smprintf("%s,%s","cn=domain level",cfg);
+ topo_plugin_conf.shared_topo = topo;
+ topo_plugin_conf.shared_topo_sdn = slapi_sdn_new_normdn_byref(topo);
+ topo_plugin_conf.shared_hosts = hosts;
+ topo_plugin_conf.shared_hosts_sdn = slapi_sdn_new_normdn_byref(hosts);
+ topo_plugin_conf.domain_level = domain_level;
+ topo_plugin_conf.domain_level_sdn = slapi_sdn_new_normdn_byref(domain_level);
+
+}
+
+void
+ipa_topo_set_plugin_shared_bindgroup(char *bindgroup)
+{
+ topo_plugin_conf.shared_bindgroup = bindgroup;
+ topo_plugin_conf.shared_bindgroup_sdn = slapi_sdn_new_normdn_byref(bindgroup);
+}
+
+void
+ipa_topo_set_domain_level(char *level)
+{
+ char *minor;
+
+ if (level == NULL) {
+ ipa_domain_level.major = 0;
+ ipa_domain_level.minor = 0;
+ return;
+ }
+
+ minor = strchr(level,'.');
+ if (minor) {
+ *minor = '\0';
+ ipa_domain_level.minor = atoi(++minor);
+ } else {
+ ipa_domain_level.minor = 0;
+ }
+ ipa_domain_level.major = atoi(level);
+}
+
+void
+ipa_topo_set_plugin_hostname(char *hostname)
+{
+ topo_plugin_conf.hostname = hostname;
+}
+
+#define TOPO_PLUGIN_DEFAULT_STARTUP_DELAY 20
+void
+ipa_topo_set_plugin_startup_delay(char *delay)
+{
+ if (delay) {
+ topo_plugin_conf.startup_delay = atoi(delay);
+ } else {
+ topo_plugin_conf.startup_delay = TOPO_PLUGIN_DEFAULT_STARTUP_DELAY;
+ }
+}
+
+void
+ipa_topo_set_plugin_version(char *version)
+{
+ char *minor;
+
+ if ( version == NULL) {
+ topo_plugin_conf.version_major = 0;
+ topo_plugin_conf.version_minor = 0;
+ return;
+ }
+
+ minor = strchr(version,'.');
+ if (minor) {
+ *minor = '\0';
+ topo_plugin_conf.version_minor = atoi(++minor);
+ } else {
+ topo_plugin_conf.version_minor = 0;
+ }
+ topo_plugin_conf.version_major = atoi(version);
+}
+
+void
+ipa_topo_init_shared_config(void)
+{
+ topo_shared_conf.allhosts = NULL;
+ topo_shared_conf.replicas = NULL;
+ topo_shared_conf.conf_lock = slapi_new_mutex();
+}
+
+void
+ipa_topo_set_plugin_managed_attrs(char **attrs)
+{
+ if (attrs) {
+ topo_plugin_conf.managed_attrs = attrs;
+ } else {
+ topo_plugin_conf.managed_attrs = ipa_topo_plugin_managed_attrs;
+ }
+}
+
+void
+ipa_topo_set_plugin_restricted_attrs(char **attrs)
+{
+ if (attrs) {
+ topo_plugin_conf.restricted_attrs = attrs;
+ } else {
+ topo_plugin_conf.restricted_attrs = ipa_topo_plugin_restricted_attrs;
+ }
+}
+
+int
+ipa_topo_cfg_plugin_suffix_is_managed(const char *be_suffix) {
+
+ int i = 0;
+ char **shared_replica_root = ipa_topo_get_plugin_replica_root();
+
+ while (shared_replica_root[i]) {
+ if (0 == strcasecmp(shared_replica_root[i], be_suffix)) return 1;
+ i++;
+ }
+ return 0;
+}
+
+int
+ipa_topo_cfg_attr_is_restricted(char *type)
+{
+ int i;
+ int rc = 0;
+ char **rattrs = ipa_topo_get_plugin_restricted_attrs();
+ for (i=0; rattrs[i]; i++) {
+ if(0 == strcasecmp(rattrs[i], type)) {
+ rc = 1;
+ break;
+ }
+ }
+ return rc;
+}
+
+void
+ipa_topo_set_plugin_replica_root(char **root)
+{
+ topo_plugin_conf.shared_replica_root = root;
+}
+
+int
+ipa_topo_init_plugin_config(Slapi_PBlock * pb)
+{
+ Slapi_Entry *plugin_entry = NULL;
+ char *hostname;
+ char *config_base;
+ char *startup_delay;
+ char *plugin_version;
+ char *bindgroup;
+ char **replica_root;
+
+ /* get the local hostname */
+ hostname = ipa_topo_util_get_pluginhost();
+ if (hostname == NULL) {
+ /* log error */
+ return -1;
+ } else {
+ ipa_topo_set_plugin_hostname(hostname);
+ }
+ /* get the args */
+ /* slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry); */
+ slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &plugin_entry);
+
+ if(plugin_entry == NULL){
+ return -1;
+ }
+
+ ipa_topo_set_plugin_active(0);
+
+ config_base = slapi_entry_attr_get_charptr(plugin_entry,
+ CONFIG_ATTR_SHARED_BASE);
+ if(config_base){
+ ipa_topo_set_plugin_shared_config(config_base);
+ }
+
+ replica_root = slapi_entry_attr_get_charray(plugin_entry,
+ CONFIG_ATTR_REPLICA_ROOT);
+ if(replica_root){
+ ipa_topo_set_plugin_replica_root(replica_root);
+ }
+
+ bindgroup = slapi_entry_attr_get_charptr(plugin_entry,
+ CONFIG_ATTR_SHARED_BINDDNGROUP);
+ if(bindgroup){
+ ipa_topo_set_plugin_shared_bindgroup(bindgroup);
+ }
+
+ startup_delay = slapi_entry_attr_get_charptr(plugin_entry,
+ CONFIG_ATTR_STARTUP_DELAY);
+ ipa_topo_set_plugin_startup_delay(startup_delay);
+ slapi_ch_free_string(&startup_delay);
+
+ plugin_version = slapi_entry_attr_get_charptr(plugin_entry,
+ CONFIG_ATTR_PLUGIN_VERSION);
+ ipa_topo_set_plugin_version(plugin_version);
+ slapi_ch_free_string(&plugin_version);
+
+ ipa_topo_util_set_domain_level();
+
+ ipa_topo_util_check_plugin_active();
+
+
+ ipa_topo_set_plugin_managed_attrs(NULL); /* use defaults */
+ ipa_topo_set_plugin_restricted_attrs(NULL); /* use defaults */
+ return 0;
+
+}
+
+void
+ipa_topo_free_plugin_config(void)
+{
+ slapi_destroy_mutex(topo_plugin_conf.plg_lock);
+ slapi_ch_free((void **)topo_plugin_conf.identity);
+ slapi_ch_free_string(&topo_plugin_conf.hostname);
+ slapi_ch_free_string(&topo_plugin_conf.shared_config_base);
+ slapi_ch_free_string(&topo_plugin_conf.shared_topo);
+ slapi_sdn_free(&topo_plugin_conf.shared_topo_sdn);
+ slapi_ch_free_string(&topo_plugin_conf.shared_hosts);
+ slapi_sdn_free(&topo_plugin_conf.shared_hosts_sdn);
+ slapi_ch_free_string(&topo_plugin_conf.shared_bindgroup);
+ slapi_sdn_free(&topo_plugin_conf.shared_bindgroup_sdn);
+ slapi_ch_free_string(&topo_plugin_conf.domain_level);
+ slapi_sdn_free(&topo_plugin_conf.domain_level_sdn);
+ slapi_ch_array_free(topo_plugin_conf.shared_replica_root);
+ if (ipa_topo_plugin_managed_attrs != topo_plugin_conf.managed_attrs)
+ slapi_ch_array_free(topo_plugin_conf.managed_attrs);
+ if (ipa_topo_plugin_restricted_attrs != topo_plugin_conf.restricted_attrs)
+ slapi_ch_array_free(topo_plugin_conf.restricted_attrs);
+}
+
+void
+ipa_topo_lock_conf(void)
+{
+ slapi_lock_mutex(topo_shared_conf.conf_lock);
+}
+
+void
+ipa_topo_unlock_conf(void)
+{
+ slapi_unlock_mutex(topo_shared_conf.conf_lock);
+}
+
+int
+ipa_topo_acquire_startup_inprogress(void)
+{
+ int acquired = 0;
+ slapi_lock_mutex(topo_shared_conf.conf_lock);
+ if (topo_shared_conf.startup_inprogress == 0 ) {
+ topo_shared_conf.startup_inprogress = 1;
+ acquired = 1;
+ }
+ slapi_unlock_mutex(topo_shared_conf.conf_lock);
+ return acquired;
+}
+
+void
+ipa_topo_release_startup_inprogress(void)
+{
+ slapi_lock_mutex(topo_shared_conf.conf_lock);
+ topo_shared_conf.startup_inprogress = 0;
+ slapi_unlock_mutex(topo_shared_conf.conf_lock);
+}
+
+TopoReplicaHost *
+ipa_topo_cfg_host_find(TopoReplica *tconf, char *findhost, int lock)
+{
+ TopoReplicaHost *host = NULL;
+
+ if (tconf->hosts == NULL) return NULL;
+
+ if (lock) slapi_lock_mutex(tconf->repl_lock);
+ for (host=tconf->hosts;host;host=host->next) {
+ if (!strcasecmp(host->hostname,findhost)) {
+ break;
+ }
+ }
+ if (lock) slapi_unlock_mutex(tconf->repl_lock);
+ return host;
+}
+
+TopoReplicaHost *
+ipa_topo_cfg_host_new(char *newhost)
+{
+ TopoReplicaHost *newnode;
+ newnode = (TopoReplicaHost *)slapi_ch_malloc(sizeof(TopoReplicaHost));
+ newnode->next = NULL;
+ newnode->hostname = newhost;
+ return newnode;
+}
+
+void
+ipa_topo_cfg_host_add(Slapi_Entry *hostentry)
+{
+ char *newhost;
+ char **repl_root = NULL;
+ TopoReplicaHost *hostnode = NULL;
+ TopoReplica *replica = NULL;
+ int i;
+
+ newhost = slapi_entry_attr_get_charptr(hostentry,"cn");
+ if (newhost == NULL) return;
+
+ repl_root = slapi_entry_attr_get_charray(hostentry,"ipaReplTopoManagedSuffix");
+ if (repl_root == NULL || *repl_root == NULL) return;
+
+ for (i=0; repl_root[i];i++) {
+ replica = ipa_topo_cfg_replica_find(repl_root[i], 1);
+ if (replica == NULL) continue;
+
+ slapi_lock_mutex(replica->repl_lock);
+ if (ipa_topo_cfg_host_find(replica, newhost, 0)) {
+ /* log error */
+ slapi_unlock_mutex(replica->repl_lock);
+ continue;
+ }
+ hostnode = ipa_topo_cfg_host_new(slapi_ch_strdup(newhost));
+ hostnode->next = replica->hosts;
+ replica->hosts = hostnode;
+ slapi_unlock_mutex(replica->repl_lock);
+ }
+
+ slapi_ch_array_free(repl_root);
+ slapi_ch_free_string(&newhost);
+ return;
+}
+
+void
+ipa_topo_cfg_host_free(TopoReplicaHost **node)
+{
+ slapi_ch_free((void **)&((*node)->hostname));
+ slapi_ch_free((void **)node);
+}
+
+void
+ipa_topo_cfg_host_del(Slapi_Entry *hostentry)
+{
+ char *delhost;
+ TopoReplicaHost *hostnode = NULL;
+ TopoReplicaHost *prevnode = NULL;
+ char **repl_root = NULL;
+ TopoReplica *replica = NULL;
+ int i;
+
+ delhost = slapi_entry_attr_get_charptr(hostentry,"cn");
+ if (delhost == NULL) return;
+
+ repl_root = slapi_entry_attr_get_charray(hostentry,"ipaReplTopoManagedSuffix");
+ if (repl_root == NULL || *repl_root == NULL) return;
+
+ for (i=0; repl_root[i];i++) {
+ replica = ipa_topo_cfg_replica_find(repl_root[i], 1);
+ if (replica == NULL) continue;
+
+ slapi_lock_mutex(replica->repl_lock);
+ hostnode = replica->hosts;
+ while (hostnode) {
+ if (!strcasecmp(hostnode->hostname,delhost)) {
+ /*remove from list and free*/
+ if (prevnode) {
+ prevnode->next = hostnode->next;
+ } else {
+ replica->hosts = hostnode->next;
+ }
+ ipa_topo_cfg_host_free(&hostnode);
+ break;
+ } else {
+ prevnode = hostnode;
+ hostnode = hostnode->next;
+ }
+ }
+ slapi_unlock_mutex(replica->repl_lock);
+ }
+
+ return;
+}
+
+TopoReplicaSegment *
+ipa_topo_cfg_replica_segment_find(TopoReplica *replica, char *leftHost, char *rightHost, int lock)
+{
+ TopoReplicaSegment *tsegm = NULL;
+ TopoReplicaSegmentList *segments = NULL;
+
+ if (lock) slapi_lock_mutex(replica->repl_lock);
+ segments = replica->repl_segments;
+ while (segments) {
+ tsegm = segments->segm;
+ if ( (!strcasecmp(leftHost,tsegm->from) && !strcasecmp(rightHost,tsegm->to) &&
+ (tsegm->direct == SEGMENT_BIDIRECTIONAL || tsegm->direct == SEGMENT_LEFT_RIGHT)) ||
+ (!strcasecmp(leftHost,tsegm->to) && !strcasecmp(rightHost,tsegm->from) &&
+ (tsegm->direct == SEGMENT_BIDIRECTIONAL || tsegm->direct == SEGMENT_RIGHT_LEFT))) {
+ break;
+ }
+ tsegm = NULL;
+ segments = segments->next;
+ }
+ if (lock) slapi_unlock_mutex(replica->repl_lock);
+
+ return tsegm;
+}
+
+TopoReplicaAgmt *
+ipa_topo_cfg_agmt_dup(TopoReplicaAgmt *agmt)
+{
+ TopoReplicaAgmt *dup = NULL;
+
+ if (agmt == NULL) return NULL;
+
+ dup = (TopoReplicaAgmt *) slapi_ch_calloc(1,sizeof(TopoReplicaAgmt));
+ dup->rdn = slapi_ch_strdup(agmt->rdn);
+ dup->origin = slapi_ch_strdup(agmt->origin);
+ dup->target = slapi_ch_strdup(agmt->target);
+ dup->enabled = slapi_ch_strdup(agmt->enabled);
+ dup->repl_root = slapi_ch_strdup(agmt->repl_root);
+ dup->strip_attrs = slapi_ch_strdup(agmt->strip_attrs);
+ dup->total_attrs = slapi_ch_strdup(agmt->total_attrs);
+ dup->repl_attrs = slapi_ch_strdup(agmt->repl_attrs);
+ dup->repl_pause = slapi_ch_strdup(agmt->repl_pause);
+ dup->repl_timeout = slapi_ch_strdup(agmt->repl_timeout);
+ dup->repl_refresh = slapi_ch_strdup(agmt->repl_refresh);
+ dup->repl_transport = slapi_ch_strdup(agmt->repl_transport);
+ dup->repl_bind_dn = slapi_ch_strdup(agmt->repl_bind_dn);
+ dup->repl_bind_cred = slapi_ch_strdup(agmt->repl_bind_cred);
+ dup->repl_bind_method = slapi_ch_strdup(agmt->repl_bind_method);
+
+ return dup;
+}
+
+TopoReplicaAgmt *
+ipa_topo_cfg_agmt_dup_reverse(TopoReplicaAgmt *agmt)
+{
+ char *tmp;
+ TopoReplicaAgmt *dup = NULL;
+ dup = ipa_topo_cfg_agmt_dup(agmt);
+
+ if (dup == NULL) return NULL;
+
+ tmp = dup->origin;
+ dup->origin = dup->target;
+ dup->target = tmp;
+
+ /* this is not enough, if a reverse agmt is
+ * created because segment becomes bidirectional
+ * we don't really know the rdn of the other direction
+ * As long as this info is not in the segment,
+ * assume std agmt naming and do best effort.
+ */
+
+ slapi_ch_free_string(&dup->rdn);
+ dup->rdn = ipa_topo_agmt_std_rdn(dup->target);
+ return dup;
+}
+static void
+ipa_topo_cfg_agmt_done(TopoReplicaAgmt *agmt)
+{
+ if (agmt == NULL) return;
+
+ slapi_ch_free_string(&agmt->origin);
+ slapi_ch_free_string(&agmt->target);
+ slapi_ch_free_string(&agmt->enabled);
+ slapi_ch_free_string(&agmt->repl_root);
+ slapi_ch_free_string(&agmt->strip_attrs);
+ slapi_ch_free_string(&agmt->total_attrs);
+ slapi_ch_free_string(&agmt->repl_attrs);
+ slapi_ch_free_string(&agmt->repl_pause);
+ slapi_ch_free_string(&agmt->repl_timeout);
+ slapi_ch_free_string(&agmt->repl_refresh);
+ slapi_ch_free_string(&agmt->repl_transport);
+ slapi_ch_free_string(&agmt->repl_bind_dn);
+ slapi_ch_free_string(&agmt->repl_bind_cred);
+ slapi_ch_free_string(&agmt->repl_bind_method);
+}
+
+static void
+ipa_topo_cfg_segment_done(TopoReplicaSegment *tsegm)
+{
+ if (tsegm == NULL) return;
+
+ slapi_ch_free_string(&tsegm->name);
+ slapi_ch_free_string(&tsegm->from);
+ slapi_ch_free_string(&tsegm->to);
+ ipa_topo_cfg_agmt_done(tsegm->left);
+ ipa_topo_cfg_agmt_done(tsegm->right);
+ slapi_ch_free((void **)&tsegm->left);
+ slapi_ch_free((void **)&tsegm->right);
+}
+
+void
+ipa_topo_cfg_segment_free(TopoReplicaSegment *tsegm)
+{
+ ipa_topo_cfg_segment_done(tsegm);
+ slapi_ch_free((void **)&tsegm);
+}
+
+TopoReplicaSegment *
+ipa_topo_cfg_segment_dup(TopoReplicaSegment *orig)
+{
+ TopoReplicaSegment *dup = NULL;
+
+ if (orig == NULL) return NULL;
+
+ dup = (TopoReplicaSegment *) slapi_ch_calloc(1,sizeof(TopoReplicaSegment));
+ dup->name = slapi_ch_strdup(orig->name);
+ dup->from = slapi_ch_strdup(orig->from);
+ dup->to = slapi_ch_strdup(orig->to);
+ dup->left = ipa_topo_cfg_agmt_dup(orig->left);
+ dup->left = ipa_topo_cfg_agmt_dup(orig->left);
+ dup->direct = orig->direct;
+ dup->state = orig->state;
+ return dup;
+}
+
+TopoReplicaSegment *
+ipa_topo_cfg_segment_find(char *repl_root, char *leftHost, char *rightHost)
+{
+ TopoReplicaSegment *tsegm = NULL;
+ TopoReplica *replica = NULL;
+
+ slapi_lock_mutex(topo_shared_conf.conf_lock);
+
+ replica = ipa_topo_cfg_replica_find(repl_root, 0);
+ if (replica) {
+ tsegm = ipa_topo_cfg_replica_segment_find(replica,leftHost,rightHost, 1);
+ }
+ slapi_unlock_mutex(topo_shared_conf.conf_lock);
+ return tsegm;
+}
+
+void
+ipa_topo_cfg_segment_set_visited(TopoReplica *replica, TopoReplicaSegment *vsegm)
+{
+ TopoReplicaSegmentList *segments = NULL;
+ TopoReplicaSegment *tsegm = NULL;
+ char *leftHost = vsegm->from;
+ char *rightHost = vsegm->to;
+
+ slapi_lock_mutex(replica->repl_lock);
+ segments = replica->repl_segments;
+ while (segments) {
+ tsegm = segments->segm;
+ if ( (!strcasecmp(leftHost,tsegm->from) && !strcasecmp(rightHost,tsegm->to) &&
+ (tsegm->direct == SEGMENT_BIDIRECTIONAL || tsegm->direct == SEGMENT_LEFT_RIGHT)) ||
+ (!strcasecmp(leftHost,tsegm->to) && !strcasecmp(rightHost,tsegm->from) &&
+ (tsegm->direct == SEGMENT_BIDIRECTIONAL || tsegm->direct == SEGMENT_RIGHT_LEFT))) {
+ segments->visited = 1;
+ break;
+ }
+ tsegm = NULL;
+ segments = segments->next;
+ }
+ slapi_unlock_mutex(replica->repl_lock);
+
+}
+
+void
+ipa_topo_cfg_segment_add(TopoReplica *replica, TopoReplicaSegment *tsegm)
+{
+ TopoReplicaSegmentList *seglist = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_cfg_segment_add: %s\n", tsegm->name);
+ slapi_lock_mutex(replica->repl_lock);
+ if (ipa_topo_cfg_replica_segment_find(replica,
+ tsegm->from,
+ tsegm->to, 0)){
+ /* already exists: log error */
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_cfg_segment_add: error: segment exists: %s\n",
+ tsegm->name);
+ goto done;
+ }
+ seglist = (TopoReplicaSegmentList *)
+ slapi_ch_calloc(1,sizeof(TopoReplicaSegmentList));
+ seglist->visited = 0;
+ seglist->segm = tsegm;
+ if (replica->repl_segments == NULL) {
+ replica->repl_segments = seglist;
+ } else {
+ seglist->next = replica->repl_segments;
+ replica->repl_segments = seglist;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_cfg_segment_added: %s\n", tsegm->name);
+done:
+ slapi_unlock_mutex(replica->repl_lock);
+}
+
+void
+ipa_topo_cfg_segment_del(TopoReplica *tconf, TopoReplicaSegment *tsegm)
+{
+ TopoReplicaSegmentList *segment = NULL;
+ TopoReplicaSegmentList *prev = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_cfg_segment_del: %s\n", tsegm->name);
+ slapi_lock_mutex(tconf->repl_lock);
+ segment = tconf->repl_segments;
+ while (segment) {
+ if (segment->segm == tsegm) {
+ if (prev == NULL) {
+ tconf->repl_segments = segment->next;
+ } else {
+ prev->next = segment->next;
+ }
+ /* free segment */
+ ipa_topo_cfg_segment_free(tsegm);
+ slapi_ch_free((void **)&segment);
+ break;
+ }
+ prev = segment;
+ segment = segment->next;
+ }
+ slapi_unlock_mutex(tconf->repl_lock);
+}
+
+TopoReplica *
+ipa_topo_cfg_replica_new(void)
+{
+ TopoReplica *topoRepl;
+ topoRepl = (TopoReplica *)slapi_ch_malloc(sizeof(TopoReplica));
+ if (topoRepl) {
+ topoRepl->next = NULL;
+ topoRepl->repl_segments = NULL;
+ topoRepl->repl_root = NULL;
+ topoRepl->shared_config_base = NULL;
+ topoRepl->hosts = NULL;
+ topoRepl->repl_lock = slapi_new_mutex();
+ }
+ return topoRepl;
+
+}
+
+int
+ipa_topo_cfg_replica_add(TopoReplica *tconf)
+{
+ int rc = 0;
+ slapi_lock_mutex(topo_shared_conf.conf_lock);
+ if (topo_shared_conf.replicas == NULL) {
+ topo_shared_conf.replicas = tconf;
+ } else if (ipa_topo_cfg_replica_find(tconf->repl_root,0)) {
+ /* log error: already exists */
+ rc = -1;
+ } else {
+ tconf->next = topo_shared_conf.replicas;
+ topo_shared_conf.replicas = tconf;
+ }
+ slapi_unlock_mutex(topo_shared_conf.conf_lock);
+
+ return rc;
+}
+
+void
+ipa_topo_cfg_replica_del(TopoReplica *tconf)
+{
+/* TBD */
+}
+
+void
+ipa_topo_cfg_replica_free(TopoReplica *tconf)
+{
+ TopoReplicaSegmentList *seg, *seg_next;
+ TopoReplicaHost *host, *host_next;
+ if (tconf) {
+ slapi_destroy_mutex(tconf->repl_lock);
+ slapi_ch_free_string(&tconf->shared_config_base);
+ slapi_ch_free_string(&tconf->repl_root);
+ slapi_sdn_free(&tconf->shared_config_sdn);
+ seg = tconf->repl_segments;
+ while (seg) {
+ seg_next = seg->next;
+ ipa_topo_cfg_segment_free(seg->segm);
+ slapi_ch_free((void **)&seg);
+ seg = seg_next;
+ }
+ host = tconf->hosts;
+ while (host) {
+ host_next = host->next;
+ slapi_ch_free_string(&host->hostname);
+ host = host_next;
+ slapi_ch_free((void **)&host);
+ }
+ slapi_ch_free((void **)&tconf);
+ }
+
+}
+
+TopoReplica *
+ipa_topo_cfg_replica_find(char *repl_root, int lock)
+{
+ TopoReplica *tconf = NULL;
+
+ if (lock) {
+ slapi_lock_mutex(topo_shared_conf.conf_lock);
+ }
+ if (topo_shared_conf.replicas == NULL) goto done;
+
+ tconf = topo_shared_conf.replicas;
+ while (tconf) {
+ if (!strcasecmp(repl_root,tconf->repl_root)) {
+ break;
+ }
+ tconf = tconf->next;
+ }
+
+done:
+ if (lock) {
+ slapi_unlock_mutex(topo_shared_conf.conf_lock);
+ }
+ return tconf;
+}
diff --git a/daemons/ipa-slapi-plugins/topology/topology_init.c b/daemons/ipa-slapi-plugins/topology/topology_init.c
new file mode 100644
index 000000000..f45086760
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/topology/topology_init.c
@@ -0,0 +1,313 @@
+
+#include "topology.h"
+
+char *ipa_topo_plugin_hostname;
+char *ipa_topo_plugin_shared_config_base;
+int ipa_topo_plugin_activated;
+
+static Slapi_PluginDesc pdesc = { PLUGIN_NAME, PLUGIN_VENDOR, PLUGIN_VERSION,
+ IPA_TOPO_PLUGIN_SUBSYSTEM };
+
+static int ipa_topo_start(Slapi_PBlock * pb);
+static int ipa_topo_close(Slapi_PBlock * pb);
+static int ipa_topo_preop_init(Slapi_PBlock *pb);
+static int ipa_topo_postop_init(Slapi_PBlock *pb);
+static int ipa_topo_internal_postop_init(Slapi_PBlock *pb);
+static int ipa_topo_apply_shared_replica_config(char *replica_root);
+static int ipa_topo_rootdse_init(Slapi_PBlock *pb);
+static int ipa_topo_rootdse_search(Slapi_PBlock *pb, Slapi_Entry* e,
+ Slapi_Entry* entryAfter, int *returncode,
+ char *returntext, void *arg);
+void ipa_topo_be_state_change(void *handle, char *be_name,
+ int old_be_state, int new_be_state);
+
+int ipa_topo_init(Slapi_PBlock *pb)
+{
+ int rc = 0;
+ void *ipa_topo_plugin_identity = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "--> ipa_topo_init\n");
+
+ /**
+ * Store the plugin identity for later use.
+ * Used for internal operations
+ */
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &ipa_topo_plugin_identity);
+ ipa_topo_set_plugin_id(ipa_topo_plugin_identity);
+
+ if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) != 0
+ || slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *)ipa_topo_start) != 0
+ || slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void *)ipa_topo_close) != 0
+ || slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &pdesc) != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_init: failed to register plugin\n");
+ rc = 1;
+ }
+
+ if (rc == 0) {
+ char *plugin_type = "bepreoperation";
+ if (slapi_register_plugin(plugin_type, 1, "ipa_topo_init",
+ ipa_topo_preop_init, IPA_TOPO_PREOP_DESC,
+ NULL, ipa_topo_get_plugin_id())) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_init: failed to register preop plugin\n");
+ rc = 1;
+ }
+ }
+
+ if (rc == 0) {
+ char *plugin_type = "postoperation";
+ if (slapi_register_plugin(plugin_type, 1, "ipa_topo_init",
+ ipa_topo_postop_init, IPA_TOPO_POSTOP_DESC,
+ NULL, ipa_topo_get_plugin_id())) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_init: failed to register postop plugin\n");
+ rc = 1;
+ }
+ }
+ if (rc == 0) {
+ char *plugin_type = "internalpostoperation";
+ if (slapi_register_plugin(plugin_type, 1, "ipa_topo_internal_init",
+ ipa_topo_internal_postop_init,
+ IPA_TOPO_INTERNAL_POSTOP_DESC,
+ NULL, ipa_topo_get_plugin_id())) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_init: failed to register internal postop plugin\n");
+ rc = 1;
+ }
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_init\n");
+ return(rc);
+}
+
+static int
+ipa_topo_preop_init(Slapi_PBlock *pb)
+{
+ int rc;
+
+ rc = slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN,
+ (void *)ipa_topo_pre_mod);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_ADD_FN,
+ (void *)ipa_topo_pre_add);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_DELETE_FN,
+ (void *)ipa_topo_pre_del);
+
+ return(rc);
+
+}
+
+static int
+ipa_topo_postop_init(Slapi_PBlock *pb)
+{
+ int rc;
+ rc = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
+ (void *)ipa_topo_post_add);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN,
+ (void *)ipa_topo_post_del);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN,
+ (void *)ipa_topo_post_mod);
+ return(rc);
+}
+
+static int
+ipa_topo_internal_postop_init(Slapi_PBlock *pb)
+{
+ int rc;
+ rc = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN,
+ (void *)ipa_topo_post_add);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN,
+ (void *)ipa_topo_post_del);
+ return(rc);
+}
+
+int
+ipa_topo_setup_managed_servers(void)
+{
+ int rc = 0;
+
+ /* initially only read the entries below cn=masters
+ * and build the list of hostnames
+ */
+ rc = ipa_topo_util_setup_servers();
+
+ return rc;
+}
+void
+ipa_topo_queue_apply_shared_config(time_t event_time, void *arg)
+{
+ ipa_topo_apply_shared_config();
+}
+int
+ipa_topo_apply_shared_config(void)
+{
+ int i = 0;
+ int rc = 0;
+ char **shared_replica_root = NULL;
+
+ while (0 == ipa_topo_acquire_startup_inprogress()) {
+ DS_Sleep(1);
+ }
+
+ shared_replica_root = ipa_topo_get_plugin_replica_root();
+ while (rc == 0 && shared_replica_root[i]) {
+ rc = ipa_topo_apply_shared_replica_config(shared_replica_root[i]);
+ i++;
+ }
+ /* initialize the list of managed servers */
+ rc = ipa_topo_setup_managed_servers();
+
+ ipa_topo_release_startup_inprogress();
+ return (rc);
+}
+
+static int
+ipa_topo_apply_shared_replica_config(char *replica_root)
+{
+ TopoReplica *replica_config = NULL;
+ TopoReplicaSegmentList *replica_segments = NULL;
+ int rc = 0;
+
+ /* step 1. get replica onfig entry from shared tree
+ * search replica entry for replcia root below shared config base
+ */
+ replica_config = ipa_topo_util_get_replica_conf(replica_root);
+ if (replica_config) {
+ /* step 2. get all segments for the replica from the shared config */
+ replica_segments = ipa_topo_util_get_replica_segments(replica_config);
+ /* step 3. get all replication agreements for replica root */
+ rc = ipa_topo_util_update_agmt_list(replica_config, replica_segments);
+ }
+ return (rc);
+}
+
+static int
+ipa_topo_start(Slapi_PBlock * pb)
+{
+ int rc = 0;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "--> ipa_topo_start\n");
+
+ /* expose info about the plugin via rootdse */
+ rc = ipa_topo_rootdse_init(pb);
+
+ /* register callback to handle state changes of backends,
+ * required to check changes in domain level after online initialization
+ */
+ slapi_register_backend_state_change((void *)ipa_topo_be_state_change,
+ ipa_topo_be_state_change);
+
+ /* init plugin config data from the plugin entry in cn=config */
+ rc = ipa_topo_init_plugin_config(pb);
+ if (rc != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "unable to get configuration\n");
+ return (rc);
+ }
+
+ if (0 == ipa_topo_get_plugin_active()) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "plugin not activated, waiting for increase of domain level\n");
+ return rc;
+ }
+
+ rc = ipa_topo_util_start(1);
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_start\n");
+ return (rc);
+}
+
+static int
+ipa_topo_close(Slapi_PBlock * pb)
+{
+
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP,
+ "", LDAP_SCOPE_BASE, "(objectclass=*)", ipa_topo_rootdse_search);
+ slapi_unregister_backend_state_change((void *)ipa_topo_be_state_change);
+ ipa_topo_free_plugin_config();
+ return 0;
+
+}
+static int
+ipa_topo_rootdse_init(Slapi_PBlock *pb)
+{
+ int rc = SLAPI_PLUGIN_FAILURE;
+
+ if (slapi_config_register_callback_plugin(SLAPI_OPERATION_SEARCH,
+ DSE_FLAG_PREOP | DSE_FLAG_PLUGIN,
+ "", LDAP_SCOPE_BASE, "(objectclass=*)",
+ ipa_topo_rootdse_search, NULL, pb)) {
+ rc = SLAPI_PLUGIN_SUCCESS;
+ }
+
+ return rc;
+}
+
+static int
+ipa_topo_rootdse_search(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
+ int *returncode, char *returntext, void *arg)
+{
+
+ char *version = slapi_ch_smprintf("%d.%d", ipa_topo_get_plugin_version_major(),
+ ipa_topo_get_plugin_version_minor());
+ slapi_entry_attr_set_charptr(e, "ipaTopologyPluginVersion", version);
+ if (ipa_topo_get_plugin_active()) {
+ slapi_entry_attr_set_charptr(e, "ipaTopologyIsManaged", "on");
+ } else {
+ slapi_entry_attr_set_charptr(e, "ipaTopologyIsManaged", "off");
+ }
+
+ /* we expose temporarily the domain level in this function, should
+ * finally be handled in a plugin managing the domain level
+ */
+ char *level = slapi_ch_smprintf("%d", ipa_topo_get_domain_level_major());
+ slapi_entry_attr_set_charptr(e, "ipaDomainLevel", level);
+ slapi_ch_free_string(&version);
+ slapi_ch_free_string(&level);
+ return SLAPI_DSE_CALLBACK_OK;
+}
+void
+ipa_topo_be_state_change(void *handle, char *be_name,
+ int old_be_state, int new_be_state)
+{
+ Slapi_Backend *be=NULL;
+ const char *be_suffix;
+
+ /* check if different backends require different actions */
+ be = slapi_be_select_by_instance_name(be_name);
+ be_suffix = slapi_sdn_get_dn(slapi_be_getsuffix(be, 0));
+ if (0 == ipa_topo_cfg_plugin_suffix_is_managed(be_suffix)) {
+ /* nothing to do */
+ return;
+ }
+
+ if (new_be_state == SLAPI_BE_STATE_ON) {
+ /* backend came back online - check change in domain level */
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_be_state_change - "
+ "backend %s is coming online; "
+ "checking domain level and init shared topology\n",
+ be_name);
+ ipa_topo_util_set_domain_level();
+ ipa_topo_util_check_plugin_active();
+ if (ipa_topo_get_plugin_active()) {
+ ipa_topo_util_start(1);
+ }
+ } else if (new_be_state == SLAPI_BE_STATE_OFFLINE) {
+ /* backend is about to be taken down - inactivate plugin */
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_be_state_change"
+ "backend %s is going offline; inactivate plugin\n", be_name);
+ } else if (new_be_state == SLAPI_BE_STATE_DELETE) {
+ /* backend is about to be removed - disable replication */
+ if (old_be_state == SLAPI_BE_STATE_ON) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_be_state_change"
+ "backend %s is about to be deleted; inactivate plugin\n", be_name);
+ }
+ }
+}
diff --git a/daemons/ipa-slapi-plugins/topology/topology_post.c b/daemons/ipa-slapi-plugins/topology/topology_post.c
new file mode 100644
index 000000000..33ded2ad3
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/topology/topology_post.c
@@ -0,0 +1,272 @@
+#include "topology.h"
+
+/*
+ * detect if the plugin should handle this entry and return the entry type
+ */
+int
+ipa_topo_check_entry_type(Slapi_Entry *entry)
+{
+ int ret = TOPO_IGNORE_ENTRY;
+ Slapi_DN *add_dn = NULL;
+ char **ocs;
+
+ add_dn = slapi_entry_get_sdn(entry);
+ if (slapi_sdn_issuffix(add_dn,ipa_topo_get_plugin_shared_topo_dn())) {
+ /* check if it is a toplogy or a segment */
+ /* check if segment's left or right node is the local server*/
+ int i;
+ ocs = slapi_entry_attr_get_charray(entry,"objectclass");
+
+ for (i=0; ocs && ocs[i]; i++) {
+ if (strcasecmp(ocs[i],"ipaReplTopoConf") == 0) {
+ ret = TOPO_CONFIG_ENTRY;
+ break;
+ } else if (strcasecmp(ocs[i],"ipaReplTopoSegment") == 0) {
+ ret = TOPO_SEGMENT_ENTRY;
+ break;
+ }
+ }
+ } else if (slapi_sdn_isparent(ipa_topo_get_plugin_shared_hosts_dn(),add_dn)) {
+ ret = TOPO_HOST_ENTRY;
+ } else if (slapi_sdn_issuffix(add_dn,ipa_topo_get_domain_level_entry_dn())) {
+ ret = TOPO_DOMLEVEL_ENTRY;
+ }
+
+ return ret;
+}
+int
+ipa_topo_post_add(Slapi_PBlock *pb)
+{
+ int result = SLAPI_PLUGIN_SUCCESS;
+ int entry_type;
+ Slapi_Entry *add_entry = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "--> ipa_topo_post_add\n");
+
+ /* 1. get entry */
+ slapi_pblock_get(pb,SLAPI_ENTRY_POST_OP,&add_entry);
+
+ if (add_entry == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM, "no entry\n");
+ return 1;
+ }
+ /* 2. check if it is in scope and type
+ * and if plugin is active
+ */
+ entry_type = ipa_topo_check_entry_type(add_entry);
+ if (0 == ipa_topo_get_plugin_active() &&
+ entry_type != TOPO_DOMLEVEL_ENTRY) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_post_add - plugin not active\n");
+ return 0;
+ }
+ switch (entry_type) {
+ case TOPO_CONFIG_ENTRY:
+ /* initialize the shared topology data for a replica */
+ break;
+ case TOPO_SEGMENT_ENTRY: {
+ TopoReplicaSegment *tsegm;
+ TopoReplica *tconf = ipa_topo_util_get_conf_for_segment(add_entry);
+ char *status;
+ /* TBD check that one node is the current server and
+ * that the other node is also managed by the
+ * shared config.
+ * If all checks pass create the replication agreement
+ */
+ tsegm = ipa_topo_util_segment_from_entry(tconf, add_entry);
+ status = slapi_entry_attr_get_charptr(add_entry, "ipaReplTopoSegmentStatus");
+ if (status == NULL || strcasecmp(status,"autogen")) {
+ ipa_topo_util_missing_agmts_add(tconf, tsegm,
+ ipa_topo_get_plugin_hostname());
+ }
+ /* keep the new segment in tconf data */
+ ipa_topo_cfg_segment_add(tconf, tsegm);
+ /* TBD: do we know if the replica already has been initialized ?
+ * should the agreement be enabled ?
+ * For now assume everything is ok and enable
+ */
+ /* check if it is unidirectional and if other direction exists */
+ ipa_topo_util_segment_merge(tconf, tsegm);
+ slapi_ch_free_string(&status);
+ break;
+ }
+ case TOPO_HOST_ENTRY: {
+ /* add to list of managed hosts */
+ ipa_topo_cfg_host_add(add_entry);
+ /* we are adding a new master, there could be
+ * a segment which so far was inactive since
+ * the host was not managed
+ */
+ ipa_topo_util_update_segments_for_host(add_entry);
+ break;
+ }
+ case TOPO_DOMLEVEL_ENTRY: {
+ /* the domain level entry was just added
+ * check and set the level, if plugin gets activated
+ * do initialization.
+ */
+ char *domlevel = slapi_entry_attr_get_charptr(add_entry, "ipaDomainLevel");
+ ipa_topo_set_domain_level(domlevel);
+ ipa_topo_util_check_plugin_active();
+ if (ipa_topo_get_plugin_active()) {
+ ipa_topo_util_start(0);
+ }
+ slapi_ch_free_string(&domlevel);
+ break;
+ }
+ case TOPO_IGNORE_ENTRY:
+ break;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_post_add\n");
+ return result;
+}
+int
+ipa_topo_post_mod(Slapi_PBlock *pb)
+{
+ int result = SLAPI_PLUGIN_SUCCESS;
+ int entry_type;
+ Slapi_Entry *mod_entry = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "--> ipa_topo_post_mod\n");
+
+ /* 1. get entry */
+ slapi_pblock_get(pb,SLAPI_ENTRY_POST_OP,&mod_entry);
+
+ if (mod_entry == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM, "no entry\n");
+ return (1);
+ }
+ /* 2. check if it is in scope */
+ entry_type = ipa_topo_check_entry_type(mod_entry);
+ if (0 == ipa_topo_get_plugin_active() &&
+ entry_type != TOPO_DOMLEVEL_ENTRY) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_post_mod - plugin not active\n");
+ return 0;
+ }
+
+ switch (entry_type) {
+ case TOPO_CONFIG_ENTRY:
+ break;
+ case TOPO_SEGMENT_ENTRY: {
+ LDAPMod **mods;
+ TopoReplica *tconf = ipa_topo_util_get_conf_for_segment(mod_entry);
+ TopoReplicaSegment *tsegm;
+ tsegm = ipa_topo_util_find_segment(tconf, mod_entry);
+ if (tsegm == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_post_mod - segment to be modified does not exist\n");
+ break;
+ }
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ ipa_topo_util_segment_update(tconf, tsegm, mods,ipa_topo_get_plugin_hostname());
+ ipa_topo_util_existing_agmts_update(tconf, tsegm, mods,
+ ipa_topo_get_plugin_hostname());
+ /* also update local segment in tconf */
+ break;
+ }
+ case TOPO_DOMLEVEL_ENTRY: {
+ /* the domain level entry was just modified
+ * check and set the level, if plugin gets activated
+ * do initialization.
+ */
+ char *domlevel = slapi_entry_attr_get_charptr(mod_entry, "ipaDomainLevel");
+ int already_active = ipa_topo_get_plugin_active();
+ ipa_topo_set_domain_level(domlevel);
+ ipa_topo_util_check_plugin_active();
+ if (!already_active && ipa_topo_get_plugin_active()) {
+ ipa_topo_util_start(0);
+ }
+ slapi_ch_free_string(&domlevel);
+ break;
+ }
+ case TOPO_HOST_ENTRY:
+ case TOPO_IGNORE_ENTRY:
+ break;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_post_mod\n");
+ return result;
+}
+int
+ipa_topo_post_del(Slapi_PBlock *pb)
+{
+ int result = SLAPI_PLUGIN_SUCCESS;
+ int entry_type;
+ Slapi_Entry *del_entry = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "--> ipa_topo_post_del\n");
+
+ /* 1. get entry */
+ slapi_pblock_get(pb,SLAPI_ENTRY_PRE_OP,&del_entry);
+
+ if (del_entry == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM, "no entry\n");
+ return 1;
+ }
+ /* 2. check if it is in scope */
+ entry_type = ipa_topo_check_entry_type(del_entry);
+ if (0 == ipa_topo_get_plugin_active() &&
+ entry_type != TOPO_DOMLEVEL_ENTRY) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_post_del - plugin not active\n");
+ return 0;
+ }
+ switch (entry_type) {
+ case TOPO_CONFIG_ENTRY:
+ break;
+ case TOPO_SEGMENT_ENTRY: {
+ /* check if corresponding agreement exists and delete */
+ TopoReplica *tconf = ipa_topo_util_get_conf_for_segment(del_entry);
+ TopoReplicaSegment *tsegm;
+ char *status;
+ tsegm = ipa_topo_util_find_segment(tconf, del_entry);
+ if (tsegm == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "segment to be deleted does not exist\n");
+ break;
+ }
+ status = slapi_entry_attr_get_charptr(del_entry, "ipaReplTopoSegmentStatus");
+ if (status == NULL || strcasecmp(status, SEGMENT_OBSOLETE_STR)) {
+ /* obsoleted segments are a result of merge, do not remove repl agmt */
+ ipa_topo_util_existing_agmts_del(tconf, tsegm,
+ ipa_topo_get_plugin_hostname());
+ }
+ /* also remove segment from local topo conf */
+ ipa_topo_cfg_segment_del(tconf, tsegm);
+ slapi_ch_free_string(&status);
+ break;
+ }
+ case TOPO_DOMLEVEL_ENTRY: {
+ /* the domain level entry was just deleted
+ * this should not happen, but it is identical
+ * to setting domlevel to 0
+ * log an error and inactivate plugin
+ */
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "postop_del: domainlevel entry deleted - "
+ "plugin will be inactivated \n");
+ break;
+ }
+ case TOPO_HOST_ENTRY:
+ /* deleting an host entry means that the host becomes
+ * unmanaged, probably because a replica is removed.
+ * remove all marked replication agreements connecting
+ * this host.
+ */
+ ipa_topo_util_delete_host(del_entry);
+ ipa_topo_cfg_host_del(del_entry);
+ break;
+ case TOPO_IGNORE_ENTRY:
+ break;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_post_del\n");
+ return result;
+}
diff --git a/daemons/ipa-slapi-plugins/topology/topology_pre.c b/daemons/ipa-slapi-plugins/topology/topology_pre.c
new file mode 100644
index 000000000..528f72b69
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/topology/topology_pre.c
@@ -0,0 +1,458 @@
+#include "topology.h"
+
+/* the preoperation plugins check if the managed replication config
+ * is attempted to be directly modified.
+ * This is only allowed for internal operations triggerd by the
+ * topology plugin itself
+ */
+
+static int ipa_topo_pre_entry_in_scope(Slapi_PBlock *pb)
+{
+ Slapi_DN *dn;
+ static Slapi_DN *config_dn = NULL;;
+
+ slapi_pblock_get(pb, SLAPI_TARGET_SDN, &dn);
+ if (config_dn == NULL) {
+ config_dn = slapi_sdn_new_dn_byval("cn=mapping tree,cn=config");
+ /* this rules out entries in regular backends and most of
+ * cn=config entries.
+ */
+ }
+ return slapi_sdn_issuffix(dn,config_dn);
+
+}
+int ipa_topo_is_entry_managed(Slapi_PBlock *pb)
+{
+ Slapi_Entry *e;
+ char *pi;
+ int op_type;
+
+ if (!ipa_topo_pre_entry_in_scope(pb)) {
+ /* we don't care for general mods, only specific
+ * entries in the mapping tree
+ */
+ return 0;
+ }
+ slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
+ if (op_type == SLAPI_OPERATION_ADD) {
+ slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
+ } else {
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
+ }
+ if (!ipa_topo_util_entry_is_candidate(e)) {
+ /* entry has no objectclass the plugin controls */
+ return 0;
+ }
+
+ /* we have to check if the operation is triggered by the
+ * topology plugin itself - allow it
+ */
+ slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY,&pi);
+ if (pi && 0 == strcasecmp(pi, ipa_topo_get_plugin_id())) {
+ return 0;
+ }
+ /* last check: is the endpoint of the agreement amanaged host ? */
+ if (ipa_topo_util_target_is_managed(e)) {
+ return 1;
+ } else {
+ return 0;
+ }
+
+}
+int
+ipa_topo_is_modattr_restricted(Slapi_PBlock *pb)
+{
+ LDAPMod **mods;
+ int i;
+ int rc = 0;
+
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ for (i = 0; (mods != NULL) && (mods[i] != NULL); i++) {
+ if (ipa_topo_cfg_attr_is_restricted(mods[i]->mod_type)) {
+ rc = 1;
+ break;
+ }
+ }
+ return rc;
+}
+
+/* connectivity check for topology
+ * checks if the nodes of a segment would still be connected after
+ * removal of the segments.
+ * For description of the algorithm see design page
+ */
+struct node_list {
+ struct node_list *next;
+ char *node;
+};
+
+struct node_fanout {
+ struct node_fanout *next;
+ char *node;
+ struct node_list *targets;
+ int visited;
+};
+struct node_list *
+node_list_dup (struct node_list *orig)
+{
+ struct node_list *dup = NULL;
+ struct node_list *cursor = orig;
+ struct node_list *start_dup = NULL;
+ while (cursor) {
+ if (dup) {
+ dup->next = (struct node_list *)slapi_ch_malloc(sizeof(struct node_list));
+ dup = dup->next;
+ } else {
+ dup = (struct node_list *)slapi_ch_malloc(sizeof(struct node_list));
+ start_dup = dup;
+ }
+ dup->next = NULL;
+ dup->node = slapi_ch_strdup(cursor->node);
+ cursor = cursor->next;
+ }
+ return start_dup;
+}
+
+void
+node_list_free(struct node_list *orig)
+{
+ struct node_list *cursor = orig;
+ struct node_list *cur_next = NULL;
+ while (cursor) {
+ cur_next = cursor->next;
+ slapi_ch_free_string(&cursor->node);
+ slapi_ch_free((void **)&cursor);
+ cursor = cur_next;
+ }
+}
+
+struct node_fanout *
+ipa_topo_connection_fanout_new (char *from, char *to)
+{
+ struct node_fanout *new_fanout = (struct node_fanout *)
+ slapi_ch_malloc(sizeof(struct node_fanout));
+ struct node_list *targets = (struct node_list *)
+ slapi_ch_malloc(sizeof(struct node_list));
+ targets->next = NULL;
+ targets->node = slapi_ch_strdup(to);
+ new_fanout->next = NULL;
+ new_fanout->node = slapi_ch_strdup(from);
+ new_fanout->targets = targets;
+ new_fanout->visited = 0;
+ return new_fanout;
+}
+
+void
+ipa_topo_connection_fanout_free (struct node_fanout *fanout)
+{
+ struct node_fanout *cursor = fanout;
+ struct node_fanout *cur_next = NULL;
+ while (cursor) {
+ cur_next = cursor->next;
+ slapi_ch_free_string(&cursor->node);
+ node_list_free(cursor->targets);
+ slapi_ch_free((void **)&cursor);
+ cursor = cur_next;
+ }
+}
+
+struct node_fanout *
+ipa_topo_connection_fanout_extend (struct node_fanout *fanout_in, char *from, char *to)
+{
+ struct node_fanout *cursor;
+ if (fanout_in == NULL) {
+ /* init fanout */
+ return ipa_topo_connection_fanout_new(from,to);
+ }
+ /* extend existing fanout struct */
+ cursor = fanout_in;
+ while (cursor) {
+ if (strcasecmp(cursor->node, from) == 0) break;
+ cursor = cursor->next;
+ }
+ if (cursor) {
+ struct node_list *target = (struct node_list *)
+ slapi_ch_malloc(sizeof(struct node_list));
+ target->next = cursor->targets;
+ target->node = slapi_ch_strdup(to);
+ cursor->targets = target;
+ return fanout_in;
+ } else {
+ cursor = ipa_topo_connection_fanout_new(from,to);
+ cursor->next = fanout_in;
+ return cursor;
+ }
+}
+struct node_fanout *
+ipa_topo_connection_fanout(TopoReplica *tconf, TopoReplicaSegment *tseg)
+{
+ struct node_fanout *fout = NULL;
+ TopoReplicaSegment *segm;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_connection_fanout for segment: %s\n",tseg->name);
+ /* lock it */
+ TopoReplicaSegmentList *seglist = tconf->repl_segments;
+ while (seglist) {
+ segm = seglist->segm;
+ if (strcasecmp(segm->name, tseg->name)) {
+ if (segm->direct == SEGMENT_LEFT_RIGHT ||
+ segm->direct == SEGMENT_BIDIRECTIONAL ) {
+ fout = ipa_topo_connection_fanout_extend(fout, segm->from, segm->to);
+ }
+ if (segm->direct == SEGMENT_RIGHT_LEFT ||
+ segm->direct == SEGMENT_BIDIRECTIONAL) {
+ fout = ipa_topo_connection_fanout_extend(fout, segm->to, segm->from);
+ }
+ }
+ seglist = seglist->next;
+ }
+ return fout;
+}
+
+void
+ipa_topo_connection_append(struct node_fanout *fanout, struct node_list *reachable)
+{
+ struct node_fanout *cursor = fanout;
+
+ while (cursor) {
+ if (strcasecmp(reachable->node, cursor->node) == 0 &&
+ cursor->visited == 0) {
+ struct node_list *tail;
+ struct node_list *extend;
+ cursor->visited = 1;
+ extend = node_list_dup(cursor->targets);
+ tail = reachable;
+ while (tail->next) {
+ tail = tail->next;
+ }
+ tail->next = extend;
+ break;
+ }
+ cursor = cursor->next;
+ }
+}
+
+int
+ipa_topo_connection_exists(struct node_fanout *fanout, char* from, char *to)
+{
+ struct node_list *reachable = NULL;
+ struct node_fanout *cursor = fanout;
+ int connected = 0;
+ /* init reachable nodes */
+ while (cursor) {
+ if (strcasecmp(cursor->node, from) == 0) {
+ cursor->visited = 1;
+ reachable = node_list_dup(cursor->targets);
+ } else {
+ cursor->visited = 0;
+ }
+ cursor = cursor->next;
+ }
+ /* check if target is in reachable nodes, if
+ * not, expand reachables
+ */
+ if (reachable == NULL) return 0;
+ while (reachable) {
+ if (strcasecmp(reachable->node, to) == 0) {
+ connected = 1;
+ break;
+ }
+ ipa_topo_connection_append(fanout, reachable);
+ reachable = reachable->next;
+ }
+ node_list_free(reachable);
+ return connected;
+}
+
+int
+ipa_topo_check_connect_reject(Slapi_PBlock *pb)
+{
+ int rc = 0;
+ Slapi_Entry *add_entry;
+ char *pi;
+
+ /* we have to check if the operation is triggered by the
+ * topology plugin itself - allow it
+ */
+ slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY,&pi);
+ if (pi && 0 == strcasecmp(pi, ipa_topo_get_plugin_id())) {
+ return 0;
+ }
+ slapi_pblock_get(pb,SLAPI_DELETE_EXISTING_ENTRY,&add_entry);
+ if (TOPO_SEGMENT_ENTRY != ipa_topo_check_entry_type(add_entry)) {
+ return 0;
+ } else {
+ /* a new segment is added
+ * verify that the segment does not yet exist
+ */
+ TopoReplicaSegment *tsegm;
+ TopoReplica *tconf = ipa_topo_util_get_conf_for_segment(add_entry);
+ tsegm = ipa_topo_util_find_segment(tconf, add_entry);
+ if (tsegm) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "segment to be added does already exist\n");
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
+int
+ipa_topo_check_disconnect_reject(Slapi_PBlock *pb)
+{
+ int rc = 1;
+ Slapi_Entry *del_entry;
+ struct node_fanout *fanout = NULL;
+ char *pi;
+
+ /* we have to check if the operation is triggered by the
+ * topology plugin itself - allow it
+ */
+ slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY,&pi);
+ if (pi && 0 == strcasecmp(pi, ipa_topo_get_plugin_id())) {
+ return 0;
+ }
+ slapi_pblock_get(pb,SLAPI_DELETE_EXISTING_ENTRY,&del_entry);
+ if (TOPO_SEGMENT_ENTRY != ipa_topo_check_entry_type(del_entry)) {
+ return 0;
+ } else {
+ TopoReplica *tconf = ipa_topo_util_get_conf_for_segment(del_entry);
+ TopoReplicaSegment *tsegm;
+ tsegm = ipa_topo_util_find_segment(tconf, del_entry);
+ if (tsegm == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "segment to be deleted does not exist\n");
+ goto done;
+ }
+ /* check if removal of segment would break connectivity */
+ fanout = ipa_topo_connection_fanout(tconf, tsegm);
+ if (fanout == NULL) goto done;
+
+ if (ipa_topo_connection_exists(fanout, tsegm->from, tsegm->to) &&
+ ipa_topo_connection_exists(fanout, tsegm->to, tsegm->from)) {
+ rc = 0;
+ }
+ ipa_topo_connection_fanout_free(fanout);
+ }
+
+done:
+ return rc;
+}
+
+static int
+ipa_topo_pre_ignore_op(Slapi_PBlock *pb)
+{
+ int repl_op = 0;
+ /* changes to cn=config aren't replicated, for changes to
+ * shared topology area checks have been done on master
+ * accepting the operation
+ */
+ slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
+ return repl_op;
+}
+
+int ipa_topo_pre_add(Slapi_PBlock *pb)
+{
+ int result = SLAPI_PLUGIN_SUCCESS;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "--> ipa_topo_pre_add\n");
+
+ if (0 == ipa_topo_get_plugin_active()) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_pre_add - plugin not active\n");
+ return 0;
+ }
+
+ if (ipa_topo_pre_ignore_op(pb)) return result;
+
+ if (ipa_topo_is_entry_managed(pb)) {
+ int rc = LDAP_UNWILLING_TO_PERFORM;
+ char *errtxt;
+ errtxt = slapi_ch_smprintf("Entry is managed by topology plugin."
+ " Adding of entry not allowed.\n");
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errtxt);
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
+ result = SLAPI_PLUGIN_FAILURE;
+ } else if (ipa_topo_check_connect_reject(pb)) {
+ int rc = LDAP_UNWILLING_TO_PERFORM;
+ char *errtxt;
+ errtxt = slapi_ch_smprintf("Segment already exists in topology."
+ "Add rejected.\n");
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errtxt);
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
+ result = SLAPI_PLUGIN_FAILURE;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_pre_add\n");
+ return result;
+}
+int
+ipa_topo_pre_mod(Slapi_PBlock *pb)
+{
+
+ int result = SLAPI_PLUGIN_SUCCESS;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "--> ipa_topo_pre_mod\n");
+
+ if (0 == ipa_topo_get_plugin_active()) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_pre_mod - plugin not active\n");
+ return 0;
+ }
+
+ if (ipa_topo_pre_ignore_op(pb)) return result;
+
+ if (ipa_topo_is_entry_managed(pb) && ipa_topo_is_modattr_restricted(pb)) {
+ int rc = LDAP_UNWILLING_TO_PERFORM;
+ char *errtxt;
+ errtxt = slapi_ch_smprintf("Entry and attributes are managed by topology plugin."
+ "No direct modifications allowed.\n");
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errtxt);
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
+ result = SLAPI_PLUGIN_FAILURE;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_pre_mod\n");
+ return result;
+}
+
+int
+ipa_topo_pre_del(Slapi_PBlock *pb)
+{
+ int result = SLAPI_PLUGIN_SUCCESS;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "--> ipa_topo_pre_del\n");
+
+ if (0 == ipa_topo_get_plugin_active()) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_pre_del - plugin not active\n");
+ return 0;
+ }
+
+ if (ipa_topo_pre_ignore_op(pb)) return result;
+
+ if (ipa_topo_is_entry_managed(pb)) {
+ int rc = LDAP_UNWILLING_TO_PERFORM;
+ char *errtxt;
+ errtxt = slapi_ch_smprintf("Entry is managed by topology plugin."
+ "Deletion not allowed.\n");
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errtxt);
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
+ result = SLAPI_PLUGIN_FAILURE;
+ } else if (ipa_topo_check_disconnect_reject(pb)) {
+ int rc = LDAP_UNWILLING_TO_PERFORM;
+ char *errtxt;
+ errtxt = slapi_ch_smprintf("Removal of Segment disconnects topology."
+ "Deletion not allowed.\n");
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, errtxt);
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
+ result = SLAPI_PLUGIN_FAILURE;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_pre_del\n");
+ return result;
+}
diff --git a/daemons/ipa-slapi-plugins/topology/topology_util.c b/daemons/ipa-slapi-plugins/topology/topology_util.c
new file mode 100644
index 000000000..94d8b33fd
--- /dev/null
+++ b/daemons/ipa-slapi-plugins/topology/topology_util.c
@@ -0,0 +1,1441 @@
+#include "topology.h"
+
+
+int
+ipa_topo_util_modify(Slapi_DN *entrySDN, Slapi_Mods *smods)
+{
+ int rc = 0;
+ Slapi_PBlock *mod_pb;
+ LDAPMod **mods;
+
+ mod_pb = slapi_pblock_new();
+ slapi_pblock_init(mod_pb);
+
+ mods = (slapi_mods_get_ldapmods_passout(smods));
+ slapi_modify_internal_set_pb_ext(mod_pb, entrySDN, mods, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_modify_internal_pb(mod_pb);
+ slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ slapi_pblock_destroy(mod_pb);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_modify: "
+ "failed to modify entry (%s): error %d\n", slapi_sdn_get_dn(entrySDN), rc);
+ }
+ return rc;
+
+}
+
+Slapi_Entry *
+ipa_topo_util_get_entry (char *dn)
+{
+ int rc = 0;
+ Slapi_Entry *res_entry = NULL;
+ Slapi_Entry **entries;
+ Slapi_PBlock *pb = NULL;
+
+ pb = slapi_pblock_new();
+
+ slapi_search_internal_set_pb(pb, dn, LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_entry: "
+ "unable to read entry (%s): error %d\n", dn, rc);
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_entry: entry not found: %s\n", dn);
+ } else {
+ res_entry = slapi_entry_dup(entries[0]);
+ }
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return res_entry;
+}
+
+/*
+ * the plugin needs to determine if segments in the shared topology
+ * affect the instance it is running in. There are many ways to determine
+ * this "pluginhost":
+ * - get the machines hostname
+ * - define hostname in plugin conf
+ * - use nsslapd-localhost from cn=config
+ * - ...
+ * This first version will use the nsslapd-localhost
+ */
+char *
+ipa_topo_util_get_pluginhost(void)
+{
+ int rc = 0;
+ Slapi_Entry **entries;
+ Slapi_PBlock *pb = NULL;
+ char *host = NULL;
+ char *host_attrs[] = {"nsslapd-localhost", NULL};
+
+ pb = slapi_pblock_new();
+
+ slapi_search_internal_set_pb(pb, "cn=config", LDAP_SCOPE_BASE,
+ "objectclass=*", host_attrs, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_localhost: "
+ "unable to read server configuration: error %d\n", rc);
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_localhost: server configuration missing\n");
+ } else {
+ host = slapi_entry_attr_get_charptr(entries[0], "nsslapd-localhost");
+ }
+ }
+
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return host;
+}
+
+void
+ipa_topo_util_check_plugin_active(void)
+{
+ if (ipa_topo_get_plugin_version_major() < ipa_topo_get_domain_level_major() ||
+ (ipa_topo_get_plugin_version_major() == ipa_topo_get_domain_level_major() &&
+ ipa_topo_get_plugin_version_minor() <= ipa_topo_get_domain_level_minor())) {
+ ipa_topo_set_plugin_active(1);
+ } else {
+ ipa_topo_set_plugin_active(0);
+ }
+}
+
+void
+ipa_topo_util_set_domain_level(void)
+{
+ int rc = 0;
+ Slapi_Entry **entries;
+ Slapi_PBlock *pb = NULL;
+
+ pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(pb, ipa_topo_get_domain_level_entry(),
+ LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_set_domain_level: "
+ "failed to lookup domain level entry: error %d\n", rc);
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_set_domain_level: domain level"
+ " entry does not exist, use default domain level of 0\n");
+ ipa_topo_set_domain_level(NULL);
+ } else {
+ char *domlevel = slapi_entry_attr_get_charptr(entries[0], "ipaDomainLevel");
+ ipa_topo_set_domain_level(domlevel);
+ slapi_ch_free_string(&domlevel);
+ }
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+}
+
+TopoReplica *
+ipa_topo_util_get_replica_conf(char *repl_root)
+{
+ int rc = 0;
+ Slapi_Entry **entries;
+ Slapi_PBlock *pb = NULL;
+ char *filter;
+ TopoReplica *topoRepl = NULL;
+
+ pb = slapi_pblock_new();
+ filter = slapi_ch_smprintf("(ipaReplTopoConfRoot=%s)",repl_root);
+ slapi_search_internal_set_pb(pb, ipa_topo_get_plugin_shared_topo(),
+ LDAP_SCOPE_ONELEVEL,
+ filter, NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_replica_conf: "
+ "no replica configuration found: error %d\n", rc);
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_replica_conf: "
+ "server configuration missing\n");
+ } else {
+ topoRepl = ipa_topo_cfg_replica_new();
+ topoRepl->shared_config_base =
+ slapi_ch_strdup(slapi_entry_get_dn_const(entries[0]));
+ topoRepl->repl_root = slapi_ch_strdup(repl_root);
+ }
+ }
+ slapi_ch_free_string(&filter);
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+
+ if (0 != ipa_topo_cfg_replica_add(topoRepl)) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_replica_conf: "
+ "replica already exists\n");
+ ipa_topo_cfg_replica_free(topoRepl);
+ topoRepl = NULL;
+ }
+
+ return topoRepl;
+}
+
+TopoReplicaSegmentList *
+ipa_topo_util_get_replica_segments(TopoReplica *replica)
+{
+ TopoReplicaSegment *repl_segment = NULL;
+ int rc = 0;
+ Slapi_Entry **entries;
+ Slapi_PBlock *pb = NULL;
+ char *filter;
+
+ pb = slapi_pblock_new();
+ filter = "objectclass=*";
+ slapi_search_internal_set_pb(pb, replica->shared_config_base,
+ LDAP_SCOPE_ONELEVEL, filter, NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_replica_segments: "
+ "no replica configuration found: error %d\n", rc);
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_replica_segments: no segments found\n");
+ } else {
+ /* get number of segments and allocate */
+ int i = 0;
+ for (i=0;entries[i];i++) {
+ repl_segment = ipa_topo_util_segment_from_entry(replica, entries[i]);
+ ipa_topo_cfg_segment_add(replica, repl_segment);
+ }
+ }
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return replica->repl_segments;
+}
+
+int
+ipa_topo_util_setup_servers(void)
+{
+ int rc = 0;
+ Slapi_Entry **entries;
+ Slapi_PBlock *pb = NULL;
+ char *filter;
+
+ pb = slapi_pblock_new();
+ filter = "objectclass=*";
+ slapi_search_internal_set_pb(pb,ipa_topo_get_plugin_shared_hosts(),
+ LDAP_SCOPE_ONELEVEL,
+ filter, NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc == LDAP_NO_SUCH_OBJECT) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_setup_servers: "
+ "search for servers failed (continuing): error %d\n", rc);
+ /* masters not yet configured, continue plugin startup */
+ rc = 0;
+ } else if (rc != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_setup_servers: "
+ "search for servers failed: error %d\n", rc);
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_setup_servers: no servers found\n");
+ } else {
+ int i = 0;
+ for (i=0;entries[i];i++) {
+ ipa_topo_cfg_host_add(entries[i]);
+ }
+ }
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return rc;
+
+}
+
+TopoReplicaAgmt *
+ipa_topo_util_agmt_from_entry(Slapi_Entry *entry, char *replRoot, char *fromHost,
+ char *toHost, char *direction)
+{
+ TopoReplicaAgmt *agmt = NULL;
+ char **mattrs;
+ char *mattr;
+ char *mval;
+ int i;
+
+ agmt = (TopoReplicaAgmt *) slapi_ch_calloc(1,sizeof(TopoReplicaAgmt));
+ agmt->origin = slapi_ch_strdup(fromHost);
+ agmt->target = slapi_ch_strdup(toHost);
+ agmt->repl_root = slapi_ch_strdup(replRoot);
+
+ mattr = slapi_ch_smprintf("ipaReplTopoSegmentGenerated;%s",direction);
+ mval = slapi_entry_attr_get_charptr(entry,mattr);
+ if (mval == 0) {
+ mval = slapi_entry_attr_get_charptr(entry,"ipaReplTopoSegmentGenerated");
+ }
+ if (mval) {
+ agmt->rdn = ipa_topo_agmt_gen_rdn(fromHost,toHost);
+ } else {
+ agmt->rdn = ipa_topo_agmt_std_rdn(toHost);
+ }
+ slapi_ch_free_string(&mattr);
+ slapi_ch_free_string(&mval);
+
+ mattrs = ipa_topo_get_plugin_managed_attrs();
+ for (i=0; mattrs[i]; i++) {
+ mattr = slapi_ch_smprintf("%s;%s",mattrs[i],direction);
+ mval = slapi_entry_attr_get_charptr(entry,mattr);
+ slapi_ch_free_string(&mattr);
+ if (mval == 0) {
+ mval = slapi_entry_attr_get_charptr(entry,mattrs[i]);
+ }
+ if (mval) {
+ ipa_topo_util_set_segm_attr(agmt, mattrs[i], mval);
+ }
+ }
+ if (agmt->repl_bind_method == NULL) {
+ agmt->repl_bind_method = slapi_ch_strdup("SASL/GSSAPI");
+ }
+ return agmt;
+}
+TopoReplicaSegment *
+ipa_topo_util_find_segment(TopoReplica *conf, Slapi_Entry *entry)
+{
+ char *leftHost;
+ char *rightHost;
+ TopoReplicaSegment *segment = NULL;
+
+ leftHost = slapi_entry_attr_get_charptr(entry,"ipaReplTopoSegmentLeftNode");
+ rightHost = slapi_entry_attr_get_charptr(entry,"ipaReplTopoSegmentRightNode");
+
+ segment = ipa_topo_cfg_segment_find(conf->repl_root, leftHost, rightHost);
+
+ slapi_ch_free((void **)&leftHost);
+ slapi_ch_free((void **)&rightHost);
+ return segment;
+}
+
+TopoReplicaSegment *
+ipa_topo_util_segment_from_entry(TopoReplica *conf, Slapi_Entry *entry)
+{
+ char *leftHost;
+ char *rightHost;
+ char *direction;
+ char *name;
+ char *state;
+
+ TopoReplicaSegment *segment = NULL;
+ segment = (TopoReplicaSegment *) slapi_ch_calloc(1,sizeof(TopoReplicaSegment));
+ leftHost = slapi_entry_attr_get_charptr(entry,"ipaReplTopoSegmentLeftNode");
+ rightHost = slapi_entry_attr_get_charptr(entry,"ipaReplTopoSegmentRightNode");
+ direction = slapi_entry_attr_get_charptr(entry,"ipaReplTopoSegmentDirection");
+ name = slapi_entry_attr_get_charptr(entry,"cn");
+ if (strcasecmp(direction,SEGMENT_DIR_BOTH) == 0){
+ segment->direct = SEGMENT_BIDIRECTIONAL;
+ segment->left = ipa_topo_util_agmt_from_entry(entry,conf->repl_root,
+ leftHost,rightHost, "left");
+ segment->right = ipa_topo_util_agmt_from_entry(entry,conf->repl_root,
+ rightHost,leftHost, "right");
+ } else if (strcasecmp(direction,SEGMENT_DIR_LEFT_ORIGIN) == 0) {
+ segment->direct = SEGMENT_LEFT_RIGHT;
+ segment->left = ipa_topo_util_agmt_from_entry(entry,conf->repl_root,
+ leftHost,rightHost, "left");
+ } else if (strcasecmp(direction,SEGMENT_DIR_RIGHT_ORIGIN) == 0) {
+ segment->direct = SEGMENT_RIGHT_LEFT;
+ segment->right = ipa_topo_util_agmt_from_entry(entry,conf->repl_root,
+ rightHost,leftHost, "right");
+ }
+ state = slapi_entry_attr_get_charptr(entry,"ipaReplTopoSegmentStatus");
+ if (state && 0 == strcasecmp(state, SEGMENT_OBSOLETE_STR)) {
+ /* state obsolete was set during merge */
+ segment->state = SEGMENT_OBSOLETE;
+ } else if (state && 0 == strcasecmp(state, SEGMENT_REMOVED_STR)) {
+ /* state removed was set during host delete */
+ segment->state = SEGMENT_REMOVED;
+ } else {
+ segment->state = 0;
+ }
+ segment->from = leftHost;
+ segment->to = rightHost;
+ segment->name = name;
+ slapi_ch_free((void **)&direction);
+ slapi_ch_free((void **)&state);
+
+ return segment;
+}
+
+TopoReplicaSegment *
+ipa_topo_util_segm_from_agmt(Slapi_Entry *repl_agmt)
+{
+ TopoReplicaSegment *segment = NULL;
+ TopoReplicaAgmt *agmt = NULL;
+ segment = (TopoReplicaSegment *) slapi_ch_calloc(1,sizeof(TopoReplicaSegment));
+ agmt = (TopoReplicaAgmt *) slapi_ch_calloc(1,sizeof(TopoReplicaAgmt));
+ segment->from = slapi_ch_strdup(ipa_topo_get_plugin_hostname());
+ segment->to = slapi_entry_attr_get_charptr(repl_agmt, "nsds5replicahost");
+ segment->direct = SEGMENT_LEFT_RIGHT;
+ segment->state = SEGMENT_AUTOGEN;
+ segment->name = slapi_ch_smprintf("%s-to-%s", segment->from, segment->to);
+ segment->left = agmt;
+ segment->right = NULL;
+
+ agmt->origin = slapi_ch_strdup(segment->from);
+ agmt->target = slapi_ch_strdup(segment->to);
+ agmt->repl_timeout = slapi_entry_attr_get_charptr(repl_agmt, "nsds5replicatimeout");
+ agmt->repl_root = slapi_entry_attr_get_charptr(repl_agmt, "nsds5replicaroot");
+
+ agmt->repl_attrs = slapi_entry_attr_get_charptr(repl_agmt, "nsDS5ReplicatedAttributeList");
+ agmt->strip_attrs = slapi_entry_attr_get_charptr(repl_agmt, "nsds5ReplicaStripAttrs");
+ agmt->total_attrs = slapi_entry_attr_get_charptr(repl_agmt, "nsDS5ReplicatedAttributeListTotal");
+ agmt->repl_bind_dn = slapi_entry_attr_get_charptr(repl_agmt, "nsds5replicabinddn");
+ agmt->repl_bind_cred = slapi_entry_attr_get_charptr(repl_agmt, "nsds5replicacredentials");
+ agmt->repl_transport = slapi_entry_attr_get_charptr(repl_agmt, "nsds5replicatransportinfo");
+ agmt->repl_bind_method = slapi_entry_attr_get_charptr(repl_agmt, "nsds5replicabindmethod");
+
+ return segment;
+
+}
+
+TopoReplica *
+ipa_topo_util_get_conf_for_segment(Slapi_Entry *segment_entry)
+{
+ /* we have a segment entry and need to determine the corresponding
+ * replica conf, to get the replica root */
+ TopoReplica *tconf = NULL;
+ char *parent = slapi_dn_parent(slapi_entry_get_dn_const(segment_entry));
+
+ Slapi_Entry *conf = ipa_topo_util_get_entry(parent);
+ tconf = ipa_topo_util_conf_from_entry(conf);
+ slapi_entry_free(conf);
+
+ return tconf;
+}
+
+TopoReplica *
+ipa_topo_util_conf_from_entry(Slapi_Entry *entry)
+{
+ TopoReplica *conf = NULL;
+ char *repl_root = NULL;
+ repl_root = slapi_entry_attr_get_charptr(entry,"ipaReplTopoConfRoot");
+ conf = ipa_topo_cfg_replica_find(repl_root, 1);
+ if (conf) {
+ slapi_ch_free((void **)&repl_root);
+ return conf;
+ } else {
+ conf = (TopoReplica *) slapi_ch_calloc(1,sizeof(TopoReplica));
+ conf->repl_root = repl_root;
+ /* TBD read defined managed attrs as defaults */
+ return conf;
+ }
+}
+
+int
+ipa_topo_util_update_agmt_list(TopoReplica *conf, TopoReplicaSegmentList *repl_segments)
+{
+ int rc = 0;
+ int i;
+ int nentries;
+ Slapi_Entry **entries;
+ Slapi_Entry *repl_agmt;
+ Slapi_PBlock *pb = NULL;
+ char *filter;
+
+ /* find all replication agreements */
+
+ pb = slapi_pblock_new();
+ filter = slapi_ch_smprintf("(&(objectclass=nsds5replicationagreement)(nsds5replicaroot=%s))",
+ conf->repl_root);
+ slapi_search_internal_set_pb(pb, "cn=config", LDAP_SCOPE_SUB,
+ filter, NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_agmts_list: "
+ "cannot read replication agreeements: error %d\n", rc);
+ goto error_return;
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_agmts_list: "
+ "no agrements found\n");
+ goto update_only;
+ }
+ }
+
+ /* for each agreement find segment */
+ nentries = 0;
+ repl_agmt = entries[0];
+ while (repl_agmt) {
+ char *targetHost;
+ TopoReplicaAgmt *topo_agmt;
+ TopoReplicaSegment *topo_segm;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_agmts_list: processing agreement: %s\n",
+ slapi_entry_get_dn_const(repl_agmt));
+
+ targetHost = slapi_entry_attr_get_charptr(repl_agmt,"nsDS5ReplicaHost");
+ if(!targetHost){
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_agmts: "
+ "cannot read targethost: error %d\n", rc);
+ continue;
+ }
+ topo_agmt = ipa_topo_util_find_segment_agmt(conf->repl_segments,
+ ipa_topo_get_plugin_hostname(),
+ targetHost);
+ if (topo_agmt) {
+ /* if segment found update agreement params */
+ char * segm_attr_val;
+ char * agmt_attr_val;
+ Slapi_Mods *smods = slapi_mods_new();
+ char **mattrs = ipa_topo_get_plugin_managed_attrs();
+ for (i=0; mattrs[i]; i++) {
+ segm_attr_val = ipa_topo_util_get_segm_attr(topo_agmt,mattrs[i]);
+ if (segm_attr_val) {
+ agmt_attr_val = slapi_entry_attr_get_charptr(repl_agmt,mattrs[i]);
+ if (agmt_attr_val == NULL ||
+ strcasecmp(agmt_attr_val,segm_attr_val)) {
+ /* value does not exist in agmt or
+ * is different from segment: replace
+ */
+ slapi_mods_add_string(smods,
+ LDAP_MOD_REPLACE,
+ mattrs[i],
+ segm_attr_val);
+ }
+
+ }
+ }
+ if (slapi_mods_get_num_mods(smods) > 0) {
+ ipa_topo_util_modify((Slapi_DN *)slapi_entry_get_sdn_const(repl_agmt),
+ smods);
+ }
+ slapi_mods_free(&smods);
+ } else {
+ if (ipa_topo_util_agmt_is_marked(repl_agmt)) {
+ /* agreement is marked and no segment exists, delete agreement */
+ ipa_topo_agmt_del_dn((char *)slapi_sdn_get_dn(slapi_entry_get_sdn_const(repl_agmt)));
+ } else {
+ /* generate segment from agreement */
+ topo_segm = ipa_topo_util_segm_from_agmt(repl_agmt);
+ rc = ipa_topo_util_segment_write(conf, topo_segm);
+ if ( rc != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_agmts_list: "
+ "failed to write segment: error %d\n", rc);
+ }
+ rc = ipa_topo_util_agmt_mark(conf, repl_agmt, topo_segm);
+ if (rc != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_agmt_list: "
+ "failed to mark agreement for host %s: error %d\n", targetHost, rc);
+ }
+ /* segment has been added in postop of segment write,
+ * prevent adding an agreement again
+ */
+ ipa_topo_cfg_segment_set_visited(conf, topo_segm);
+ }
+ }
+
+ repl_agmt = entries[++nentries];
+ }
+ slapi_free_search_results_internal(pb);
+
+update_only:
+ /* check if segments not covered by agreement exist
+ * add agreeement
+ */
+ ipa_topo_util_missing_agmts_add_list(conf, conf->repl_segments,
+ ipa_topo_get_plugin_hostname());
+
+error_return:
+ slapi_ch_free_string(&filter);
+ slapi_pblock_destroy(pb);
+ return rc;
+}
+
+TopoReplicaAgmt *
+ipa_topo_util_find_segment_agmt(TopoReplicaSegmentList *repl_segments,
+ char *fromHost, char *toHost)
+{
+ TopoReplicaAgmt *agmt = NULL;
+ TopoReplicaAgmt *agmtfound = NULL;
+ TopoReplicaSegmentList *segment = repl_segments;
+
+ while (segment) {
+ if (segment->visited) {
+ segment = segment->next;
+ continue;
+ }
+ agmt = segment->segm->left;
+ if (agmt && (0 == strcasecmp(agmt->origin, fromHost)) &&
+ (0 == strcasecmp(agmt->target, toHost))) {
+ agmtfound = agmt;
+ break;
+ }
+ agmt = segment->segm->right;
+ if (agmt && (0 == strcasecmp(agmt->origin, fromHost)) &&
+ (0 == strcasecmp(agmt->target, toHost))) {
+ agmtfound = agmt;
+ break;
+ }
+ segment = segment->next;
+ }
+ if (segment) {
+ segment->visited = 1;
+ }
+ return agmtfound;
+}
+
+void
+ipa_topo_util_missing_agmts_add_list(TopoReplica *repl_conf,
+ TopoReplicaSegmentList *repl_segments,
+ char *fromHost)
+{
+ TopoReplicaSegmentList *segment = repl_segments;
+
+ while (segment) {
+ if (segment->visited) {
+ segment->visited = 0;
+ segment = segment->next;
+ continue;
+ }
+ ipa_topo_util_missing_agmts_add(repl_conf, segment->segm, fromHost);
+ segment = segment->next;
+ }
+}
+
+void
+ipa_topo_util_missing_agmts_add(TopoReplica *repl_conf,
+ TopoReplicaSegment *segment,
+ char *fromHost)
+{
+ if (0 == strcasecmp(segment->from, fromHost)) {
+ if (segment->left) {
+ ipa_topo_agmt_new(segment->to,repl_conf, segment->left);
+ }
+ } else if (0 == strcasecmp(segment->to, fromHost)) {
+ if (segment->right) {
+ ipa_topo_agmt_new(segment->from,repl_conf, segment->right);
+ }
+ }
+}
+
+void
+ipa_topo_util_existing_agmts_del_list(TopoReplica *repl_conf,
+ TopoReplicaSegmentList *repl_segments,
+ char *fromHost)
+{
+ TopoReplicaSegmentList *segment = repl_segments;
+
+ while (segment) {
+ if (segment->visited) {
+ segment->visited = 0;
+ segment = segment->next;
+ continue;
+ }
+ ipa_topo_util_existing_agmts_del(repl_conf, segment->segm,fromHost);
+ segment = segment->next;
+ }
+}
+
+void
+ipa_topo_util_existing_agmts_del(TopoReplica *repl_conf,
+ TopoReplicaSegment *segment,
+ char *fromHost)
+{
+ if (0 == strcasecmp(segment->from, fromHost)) {
+ if (segment->left) {
+ ipa_topo_agmt_del(segment->to,repl_conf, segment->left);
+ }
+ } else if (0 == strcasecmp(segment->to, fromHost)) {
+ if (segment->right) {
+ ipa_topo_agmt_del(segment->from,repl_conf, segment->right);
+ }
+ }
+}
+
+void
+ipa_topo_util_existing_agmts_update_list(TopoReplica *repl_conf,
+ TopoReplicaSegmentList *repl_segments,
+ LDAPMod **mods ,char *fromHost)
+{
+ TopoReplicaSegmentList *segment = repl_segments;
+
+ while (segment) {
+ if (segment->visited) {
+ segment->visited = 0;
+ segment = segment->next;
+ continue;
+ }
+ ipa_topo_util_existing_agmts_update(repl_conf, segment->segm, mods, fromHost);
+ segment = segment->next;
+ }
+}
+
+void
+ipa_topo_util_existing_agmts_update(TopoReplica *repl_conf,
+ TopoReplicaSegment *segment,
+ LDAPMod **mods ,char *fromHost)
+{
+ TopoReplicaAgmt *l_agmt = NULL;
+ TopoReplicaAgmt *r_agmt = NULL;
+ l_agmt = segment->left;
+ r_agmt = segment->right;
+ if (l_agmt && r_agmt) {
+ if (0 == strcasecmp(l_agmt->origin, fromHost)) {
+ ipa_topo_agmt_mod(repl_conf, l_agmt, mods, "left");
+ } else if (0 == strcasecmp(r_agmt->origin, fromHost)) {
+ ipa_topo_agmt_mod(repl_conf, r_agmt, mods, "right");
+ }
+ }
+}
+
+void
+ipa_topo_util_segment_update(TopoReplica *repl_conf,
+ TopoReplicaSegment *segment,
+ LDAPMod **mods ,char *fromHost)
+{
+ int i;
+ for (i = 0; (mods != NULL) && (mods[i] != NULL); i++) {
+ switch (mods[i]->mod_op & ~LDAP_MOD_BVALUES) {
+ case LDAP_MOD_DELETE:
+ break;
+ case LDAP_MOD_ADD:
+ case LDAP_MOD_REPLACE:
+ if (0 == strcasecmp(mods[i]->mod_type,"ipaReplTopoSegmentDirection")) {
+ if (0 == strcasecmp(mods[i]->mod_bvalues[0]->bv_val,"both")) {
+ if (segment->direct == SEGMENT_LEFT_RIGHT) {
+ segment->right = ipa_topo_cfg_agmt_dup_reverse(segment->left);
+ } else if (segment->direct == SEGMENT_RIGHT_LEFT) {
+ segment->left = ipa_topo_cfg_agmt_dup_reverse(segment->right);
+ }
+ segment->direct = SEGMENT_BIDIRECTIONAL;
+ } else {
+ /* only onedirectionl --> bidirectional handled so far */
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_segment_update: no downgrade of direction\n");
+ }
+ } else if (0 == strcasecmp(mods[i]->mod_type,"ipaReplTopoSegmentStatus")) {
+ if (0 == strcasecmp(mods[i]->mod_bvalues[0]->bv_val,SEGMENT_OBSOLETE_STR)) {
+ segment->state = SEGMENT_OBSOLETE;
+ } else if (0 == strcasecmp(mods[i]->mod_bvalues[0]->bv_val,SEGMENT_AUTOGEN_STR)) {
+ segment->state = SEGMENT_AUTOGEN;
+ }
+ }
+ break;
+ }
+ }
+}
+
+char *
+ipa_topo_util_get_segm_attr(TopoReplicaAgmt *agmt, char *attr_type)
+{
+ char *attr = NULL;
+ if (strcasecmp(attr_type, "nsds5ReplicaEnabled") == 0) {
+ attr = agmt->enabled;
+ } else if (strcasecmp(attr_type, "nsds5ReplicaStripAttrs") == 0){
+ attr = agmt->strip_attrs;
+ } else if (strcasecmp(attr_type, "nsds5ReplicatedAttributeList") == 0){
+ attr = agmt->repl_attrs;
+ } else if (strcasecmp(attr_type, "nsDS5ReplicatedAttributeListTotal") == 0) {
+ attr = agmt->total_attrs;
+ } else if (strcasecmp(attr_type, "nsds5BeginReplicaRefresh") == 0){
+ attr = agmt->repl_refresh;
+ } else if (strcasecmp(attr_type, "nsds5replicaTimeout") == 0) {
+ attr = agmt->repl_timeout;
+ } else if (strcasecmp(attr_type, "nsds5ReplicaEnabled") == 0) {
+ attr = agmt->enabled;
+ } else if (strcasecmp(attr_type, "nsds5replicaSessionPauseTime") == 0) {
+ attr = agmt->repl_pause;
+ } else if (strcasecmp(attr_type, "nsds5replicabinddn") == 0) {
+ attr = agmt->repl_bind_dn;
+ } else if (strcasecmp(attr_type, "nsds5replicacredentials") == 0) {
+ attr = agmt->repl_bind_cred;
+ } else if (strcasecmp(attr_type, "nsds5replicatransportinfo") == 0) {
+ attr = agmt->repl_transport;
+ } else if (strcasecmp(attr_type, "nsds5replicabindmethod") == 0) {
+ attr = agmt->repl_bind_method;
+ }
+ return attr;
+}
+
+void
+ipa_topo_util_set_segm_attr(TopoReplicaAgmt *agmt, char *attr_type, char *attr_val)
+{
+ if (strcasecmp(attr_type, "nsds5ReplicaEnabled") == 0) {
+ agmt->enabled = attr_val;
+ } else if (strcasecmp(attr_type, "nsds5ReplicaStripAttrs") == 0){
+ agmt->strip_attrs = attr_val;
+ } else if (strcasecmp(attr_type, "nsds5ReplicatedAttributeList") == 0){
+ agmt->repl_attrs = attr_val;
+ } else if (strcasecmp(attr_type, "nsDS5ReplicatedAttributeListTotal") == 0) {
+ agmt->total_attrs = attr_val;
+ } else if (strcasecmp(attr_type, "nsds5BeginReplicaRefresh") == 0){
+ agmt->repl_refresh = attr_val;
+ } else if (strcasecmp(attr_type, "nsds5replicaTimeout") == 0) {
+ agmt->repl_timeout = attr_val;
+ } else if (strcasecmp(attr_type, "nsds5ReplicaEnabled") == 0) {
+ agmt->enabled = attr_val;
+ } else if (strcasecmp(attr_type, "nsds5replicaSessionPauseTime") == 0) {
+ agmt->repl_pause = attr_val;
+ } else if (strcasecmp(attr_type, "nsds5replicabinddn") == 0) {
+ agmt->repl_bind_dn = attr_val;
+ } else if (strcasecmp(attr_type, "nsds5replicacredentials") == 0) {
+ agmt->repl_bind_cred = attr_val;
+ } else if (strcasecmp(attr_type, "nsds5replicatransportinfo") == 0) {
+ agmt->repl_transport = attr_val;
+ } else if (strcasecmp(attr_type, "nsds5replicabindmethod") == 0) {
+ agmt->repl_bind_method = attr_val;
+ }
+}
+
+/* check if the entry is a standard replication agreement (ignore winsync)
+ * and if the replication suffix is in the list of managed replication roots.
+ * This qualifies the entry as a candidate, further checks have to be done.
+ */
+int
+ipa_topo_util_entry_is_candidate(Slapi_Entry *e)
+{
+ char **ocs;
+ char *oc = NULL;
+ char *repl_root;
+ char **shared_root;
+ int rc = 0;
+ int i;
+
+ ocs = slapi_entry_attr_get_charray(e,"objectclass");
+
+ for (i=0; ocs && ocs[i]; i++) {
+ if (strcasecmp(ocs[i],"nsds5ReplicationAgreement") == 0) {
+ oc = ocs[i];
+ break;
+ }
+ }
+
+ if (oc) {
+ repl_root = slapi_entry_attr_get_charptr(e,"nsDS5ReplicaRoot");
+ shared_root = ipa_topo_get_plugin_replica_root();
+ for (i=0; shared_root && shared_root[i]; i++) {
+ if (strcasecmp(repl_root,shared_root[i]) == 0) {
+ rc = 1;
+ break;
+ }
+ }
+ slapi_ch_free((void **) &repl_root);
+ }
+ slapi_ch_array_free(ocs);
+ return rc;
+}
+
+int
+ipa_topo_util_target_is_managed(Slapi_Entry *e)
+{
+ char *targethost;
+ char *repl_root;
+ TopoReplica *replica;
+ int ret = 0;
+
+ /* first check: is the entry managed alreday by the topology plugin */
+ /* at the moment only replication agreements are managed */
+ if (ipa_topo_util_agmt_is_marked(e)) return 1;
+
+ /* next check: is the replcation agreement targeting a meanged server
+ * deny agreements to an managed server
+ * allow other agreements
+ */
+ targethost = slapi_entry_attr_get_charptr(e,"nsDS5ReplicaHost");
+ repl_root = slapi_entry_attr_get_charptr(e,"nsDS5ReplicaRoot");
+ replica = ipa_topo_cfg_replica_find(repl_root,1);
+ if (targethost && replica &&
+ ipa_topo_cfg_host_find(replica, targethost, 1)) {
+ ret = 1;
+ }
+ slapi_ch_free_string(&targethost);
+ slapi_ch_free_string(&repl_root);
+
+ return ret;
+
+}
+
+void
+ipa_topo_util_segm_update (TopoReplica *tconf,
+ TopoReplicaSegment *tsegm,
+ int property)
+{
+ char *dn = NULL;
+ Slapi_Mods *smods;
+
+ dn = ipa_topo_segment_dn(tconf, tsegm->name);
+
+ if (dn == NULL) return;
+
+ /* apply mods to entry */
+ smods = slapi_mods_new();
+ switch (property) {
+ case SEGMENT_BIDIRECTIONAL:
+ tsegm->direct = SEGMENT_BIDIRECTIONAL;
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "ipaReplTopoSegmentDirection", "both");
+ break;
+ case SEGMENT_LEFT_RIGHT:
+ tsegm->direct = SEGMENT_LEFT_RIGHT;
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "ipaReplTopoSegmentDirection", "left-right");
+ break;
+ case SEGMENT_RIGHT_LEFT:
+ tsegm->direct = SEGMENT_RIGHT_LEFT;
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "ipaReplTopoSegmentDirection", "right-left");
+ break;
+ case SEGMENT_OBSOLETE:
+ tsegm->state = SEGMENT_OBSOLETE;
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "ipaReplTopoSegmentStatus", SEGMENT_OBSOLETE_STR);
+ break;
+ case SEGMENT_REMOVED:
+ tsegm->state = SEGMENT_OBSOLETE;
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
+ "ipaReplTopoSegmentStatus", SEGMENT_REMOVED_STR);
+ break;
+ }
+ if (slapi_mods_get_num_mods(smods) > 0) {
+ Slapi_DN *sdn = slapi_sdn_new_normdn_byref(dn);
+ ipa_topo_util_modify(sdn, smods);
+ slapi_sdn_free(&sdn);
+ }
+
+ slapi_mods_free(&smods);
+ slapi_ch_free_string(&dn);
+
+}
+
+void
+ipa_topo_util_segm_remove(TopoReplica *tconf,
+ TopoReplicaSegment *tsegm)
+{
+ Slapi_PBlock *pb;
+ char *dn = NULL;
+ int ret;
+
+ /* remove it from the database */
+ dn = ipa_topo_segment_dn(tconf, tsegm->name);
+ if (dn == NULL) return;
+
+ pb = slapi_pblock_new();
+ slapi_delete_internal_set_pb(pb, dn, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+
+ slapi_delete_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ slapi_pblock_destroy(pb);
+
+ slapi_ch_free_string(&dn);
+
+ /* removed from the internal data struct in the delete postop */
+ /* ipa_topo_cfg_segment_del(tconf, tsegm); */
+}
+
+/* for merging segments the result should be the same on any server
+ * an deliberate decision is to compare hostnames to get a preference
+ */
+static int
+ipa_topo_util_segm_order(TopoReplicaSegment *l, TopoReplicaSegment *r)
+{
+ return strcasecmp(l->from, r->from);
+}
+
+void
+ipa_topo_util_segment_merge(TopoReplica *tconf,
+ TopoReplicaSegment *tsegm)
+{
+ TopoReplicaSegment *ex_segm;
+
+ if (tsegm->direct == SEGMENT_BIDIRECTIONAL) return;
+
+ if (strcasecmp(tsegm->from,ipa_topo_get_plugin_hostname()) &&
+ strcasecmp(tsegm->to,ipa_topo_get_plugin_hostname())) {
+ /* merging is only done on one of the endpoints of the segm */
+ return;
+ }
+
+ ex_segm = ipa_topo_cfg_replica_segment_find(tconf, tsegm->to, tsegm->from, 1 /*lock*/);
+ if (ex_segm == NULL) return;
+
+ /* to avoid conflicts merging has to be done only once and
+ * so there is a preference which segment survives and on
+ * which server it will be done
+ */
+ if (ipa_topo_util_segm_order(ex_segm, tsegm) > 0) {
+ if (0 == strcasecmp(tsegm->from,ipa_topo_get_plugin_hostname())) {
+ tsegm->right = ipa_topo_cfg_agmt_dup(ex_segm->left);
+ ipa_topo_util_segm_update(tconf,ex_segm, SEGMENT_OBSOLETE);
+ ipa_topo_util_segm_remove(tconf, ex_segm);
+ ipa_topo_util_segm_update(tconf,tsegm, SEGMENT_BIDIRECTIONAL);
+ }
+ } else {
+ if (0 == strcasecmp(ex_segm->from,ipa_topo_get_plugin_hostname())) {
+ ex_segm->right = ipa_topo_cfg_agmt_dup(tsegm->left);
+ ipa_topo_util_segm_update(tconf,tsegm, SEGMENT_OBSOLETE);
+ ipa_topo_util_segm_remove(tconf, tsegm);
+ ipa_topo_util_segm_update(tconf,ex_segm, SEGMENT_BIDIRECTIONAL);
+ }
+ }
+
+}
+int
+ipa_topo_util_segment_write(TopoReplica *tconf, TopoReplicaSegment *tsegm)
+{
+ Slapi_Entry *e = NULL;
+ Slapi_PBlock *pb;
+ char *dn = NULL;
+ Slapi_DN *sdn = NULL;
+ int ret = 0;
+ /* Set up the new segment entry */
+ dn = ipa_topo_segment_dn(tconf, tsegm->name);
+ if (dn == NULL) return -1;
+ sdn = slapi_sdn_new_normdn_byref(dn);
+
+ e = slapi_entry_alloc();
+ /* the entry now owns the dup'd dn */
+ slapi_entry_init_ext(e, sdn, NULL); /* sdn is copied into e */
+ slapi_sdn_free(&sdn);
+
+ slapi_entry_add_string(e, SLAPI_ATTR_OBJECTCLASS, "iparepltoposegment");
+ slapi_entry_add_string(e, "cn",tsegm->name);
+ slapi_entry_add_string(e, "iparepltoposegmentleftnode",tsegm->from);
+ slapi_entry_add_string(e, "iparepltoposegmentrightnode",tsegm->to);
+ slapi_entry_add_string(e, "iparepltoposegmentdirection", "left-right");
+ /* write other attributes of the segment if present */
+ if (tsegm->state == SEGMENT_AUTOGEN) {
+ slapi_entry_add_string(e, "iparepltoposegmentstatus", "autogen");
+ }
+
+ pb = slapi_pblock_new();
+ slapi_pblock_init(pb);
+
+ /* e will be consumed by slapi_add_internal() */
+ slapi_add_entry_internal_set_pb(pb, e, NULL, ipa_topo_get_plugin_id(), 0);
+ slapi_add_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ slapi_pblock_destroy(pb);
+
+ return ret;
+
+}
+/*
+ * to distinguish replication agreements created by the topology plugin
+ * and agreemens created by admins or legacy tools a "marker" objectclass is used.
+ * Witheout extending the schema the description attribute is used and a
+ * specific value is added:
+ * - when a segment is created from an agreement an so put under control of
+ * the plugin:
+ * "ipaReplTopoManagedAgreementState: managed agreement - controlled by topology plugin"
+ * - when an agreement is created from a segment:
+ * "ipaReplTopoManagedAgreementState: managed agreement - generated by topology plugin"
+ */
+int
+ipa_topo_util_agmt_mark(TopoReplica *tconf, Slapi_Entry *repl_agmt,
+ TopoReplicaSegment *tsegm)
+{
+ int ret = 0;
+
+ Slapi_Mods *smods = slapi_mods_new();
+ slapi_mods_add_string(smods, LDAP_MOD_ADD, "objectclass",
+ "ipaReplTopoManagedAgreement");
+ slapi_mods_add_string(smods, LDAP_MOD_ADD, "ipaReplTopoManagedAgreementState",
+ "managed agreement - controlled by topology plugin");
+ if (slapi_mods_get_num_mods(smods) > 0) {
+ ret = ipa_topo_util_modify(
+ (Slapi_DN *)slapi_entry_get_sdn_const(repl_agmt), smods);
+ }
+ slapi_mods_free(&smods);
+
+ return ret;
+}
+
+int
+ipa_topo_util_agmt_is_marked(Slapi_Entry *repl_agmt)
+{
+ int ret = 0;
+ int i;
+ char **descs;
+
+ descs = slapi_entry_attr_get_charray(repl_agmt, "objectclass");
+ for (i=0; descs &&descs[i]; i++) {
+ if (strcasecmp(descs[i],"ipaReplTopoManagedAgreement") == 0) {
+ ret = 1;
+ break;
+ }
+ }
+ slapi_ch_array_free(descs);
+ return ret;
+}
+
+void
+ipa_topo_util_update_segments_for_host(Slapi_Entry *hostentry)
+{
+ int rc = 0;
+ int nentries;
+ char* newhost = NULL;
+ Slapi_Entry **entries;
+ Slapi_Entry *repl_agmt;
+ Slapi_PBlock *pb = NULL;
+ char *filter;
+
+ /* find all replication agreements to the new host entry
+ * Since the host was not yet managed new segments ghave to be
+ * created
+ */
+ newhost = slapi_entry_attr_get_charptr(hostentry,"cn");
+
+ pb = slapi_pblock_new();
+ filter = slapi_ch_smprintf("(&(objectclass=nsds5replicationagreement)(nsds5replicahost=%s))",
+ newhost);
+ slapi_search_internal_set_pb(pb, "cn=config", LDAP_SCOPE_SUB,
+ filter, NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_segments_for_host: "
+ "no replication agreeements for host %s: error %d\n",
+ newhost, rc);
+ goto error_return;
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_segments_for_host: "
+ "no agrements found\n");
+ goto error_return;
+ }
+ }
+
+ /* for each agreement find segment */
+ nentries = 0;
+ repl_agmt = entries[0];
+ while (repl_agmt) {
+ TopoReplica *conf = NULL;
+ TopoReplicaSegment *topo_segm;
+ char *repl_root = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_segments_for_host: "
+ "processing agreement: %s\n",
+ slapi_entry_get_dn_const(repl_agmt));
+
+ /* generate segment from agreement */
+ repl_root = slapi_entry_attr_get_charptr(repl_agmt,"nsds5replicaroot");
+ conf = ipa_topo_cfg_replica_find(repl_root,1);
+ if (conf == NULL) goto next_agmt;
+ topo_segm = ipa_topo_util_segm_from_agmt(repl_agmt);
+ rc = ipa_topo_util_segment_write(conf, topo_segm);
+ if (rc != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_segments_for_host: "
+ "failed to write segment for host %s: error %d\n",
+ newhost, rc);
+ }
+ rc = ipa_topo_util_agmt_mark(conf, repl_agmt, topo_segm);
+ if (rc != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_update_segments_for_host: "
+ "failed to mark agreement for host %s: error %d\n",
+ newhost, rc);
+ }
+ ipa_topo_cfg_segment_add(conf, topo_segm);
+next_agmt:
+ slapi_ch_free_string(&repl_root);
+ repl_agmt = entries[++nentries];
+
+ }
+
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+
+error_return:
+ slapi_ch_free_string(&newhost);
+
+}
+
+void
+ipa_topo_util_disable_repl_from_host(char *repl_root, char *delhost)
+{
+ char *principal = ipa_topo_util_get_ldap_principal(repl_root, delhost);
+ ipa_topo_util_disable_repl_for_principal(repl_root, principal);
+}
+
+void
+ipa_topo_util_delete_segments_for_host(char *repl_root, char *delhost)
+{
+ TopoReplicaSegment *segm = NULL;
+ TopoReplica *tconf = ipa_topo_cfg_replica_find(repl_root, 1);
+ int check_reverse = 1;
+
+ /* first check if a segment originating at localhost exists */
+ segm = ipa_topo_cfg_segment_find(repl_root,
+ ipa_topo_get_plugin_hostname(), delhost);
+ if (segm) {
+ /* mark segment as removable, bypass connectivity check when replicated */
+ if (segm->direct == SEGMENT_BIDIRECTIONAL) check_reverse = 0;
+ ipa_topo_util_segm_update(tconf,segm, SEGMENT_REMOVED);
+ /* delete segment */
+ /* the replication agreement will be deleted in the postop_del*/
+ ipa_topo_util_segm_remove(tconf, segm);
+ }
+ /* check if one directional segment in reverse direction exists */
+ if (check_reverse) {
+ segm = ipa_topo_cfg_segment_find(repl_root,
+ delhost, ipa_topo_get_plugin_hostname());
+ if (segm) {
+ ipa_topo_util_segm_update(tconf,segm, SEGMENT_REMOVED);
+ /* mark and delete, no repl agmt on this server */
+ ipa_topo_util_segm_remove(tconf, segm);
+ }
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_delete_segments_for_host <-- done\n");
+}
+
+void
+ipa_topo_util_delete_host(Slapi_Entry *hostentry)
+{
+ char* delhost = NULL;
+
+ delhost = slapi_entry_attr_get_charptr(hostentry,"cn");
+ /* if the deleted host is the current host, do not
+ * delete the segments, deleting segments will trigger
+ * removal of replication agreements and it cannot be
+ * ensured that the deletion of the host will reach
+ * other servers in the replica before.
+ * So wait until the delete is received on the other
+ * servers and the deletion of segments is received.
+ */
+ if (0 == strcasecmp(delhost,ipa_topo_get_plugin_hostname())) {
+ return;
+ } else {
+ /* find all segments connecting the local master to the
+ * deleted master.
+ * - mark the segments as no longer managed
+ * - delete the segments
+ * - if the segment originates at the local host
+ * remove the corresponding replication agreement
+ */
+ int i = 0;
+ char **shared_root = ipa_topo_get_plugin_replica_root();
+
+ while (shared_root[i]) {
+ ipa_topo_util_disable_repl_from_host(shared_root[i], delhost);
+ ipa_topo_util_delete_segments_for_host(shared_root[i], delhost);
+ i++;
+ }
+ }
+
+}
+
+int
+ipa_topo_util_start(int delay)
+{
+ /* main routine to synchronize data in the shared tree and
+ * config data. It will be called:
+ * - at startup of the server
+ * - if the domain level increases above the plugin version
+ * and the plugin becomes active
+ * - after a backup state change, eg after online initialization
+ * when there is no guarantee that data in the shared tree
+ * and plugin data still match.
+ *
+ * the parameter delay controls if the operation is performed
+ * immediately or after some delay. This delay is necessary
+ * during startup because the plugins only become active after
+ * all plugins have been started and modifications would not be
+ * logged in the changelog and replicated
+ */
+
+ time_t now;
+ int rc = 0;
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "--> ipa_topo_util_start - deleay: %d\n",delay);
+
+ ipa_topo_init_shared_config();
+
+ /* initialize the config data from the shared tree and apply to
+ * the managed data under cn=config
+ */
+ if (delay) {
+ time(&now);
+ if (!slapi_eq_once(ipa_topo_queue_apply_shared_config,NULL,now +
+ ipa_topo_get_plugin_startup_delay())) {
+ slapi_log_error(SLAPI_LOG_FATAL, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "unable to queue configuration update\n");
+ return -1;
+ }
+ } else {
+ rc = ipa_topo_apply_shared_config();
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_util_start\n");
+ return rc;
+}
+
+char *
+ipa_topo_util_get_ldap_principal(char *repl_root, char *hostname)
+{
+ int rc = 0;
+ Slapi_Entry **entries;
+ Slapi_PBlock *pb = NULL;
+ char *filter;
+ char *dn;
+
+ filter = slapi_ch_smprintf("krbprincipalname=ldap/%s*",hostname);
+ pb = slapi_pblock_new();
+
+ slapi_search_internal_set_pb(pb, repl_root, LDAP_SCOPE_SUBTREE,
+ filter, NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_ldap_principal: "
+ "unable to search for entry (%s): error %d\n", filter, rc);
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_util_get_ldap_principal: entry not found: (%s)\n", filter);
+ } else {
+ dn = slapi_ch_strdup(slapi_entry_get_dn(entries[0]));
+ }
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ slapi_ch_free_string(&filter);
+ return dn;
+}
+
+void
+ipa_topo_util_disable_repl_for_principal(char *repl_root, char *principal)
+{
+ Slapi_DN *sdn;
+ char *filter;
+ Slapi_PBlock *pb;
+ Slapi_Entry **entries;
+ Slapi_Mods *smods;
+ int ret;
+
+ /* to disable replication for a user/principal it ahs to be removed from the
+ * allowed bind dns in the replica object and from the bind dn group
+ */
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "--> ipa_topo_util_disable_repl_for_principal\n");
+ /* find replica object */
+ pb = slapi_pblock_new();
+ filter = slapi_ch_smprintf("(&(objectclass=nsds5replica)(nsds5replicaroot=%s))", repl_root);
+ slapi_search_internal_set_pb(pb, "cn=config", LDAP_SCOPE_SUB,
+ filter, NULL, 0, NULL, NULL,
+ ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret != 0) {
+ sdn = NULL;
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_agreement_dn: no replica found\n");
+ sdn = NULL;
+ } else {
+ sdn = slapi_sdn_dup(slapi_entry_get_sdn(entries[0]));
+ }
+ }
+ slapi_free_search_results_internal(pb);
+
+ /* remove principal from binddns */
+ smods = slapi_mods_new();
+ slapi_mods_add_string(smods, LDAP_MOD_DELETE,
+ "nsds5replicabinddn", principal);
+ ret = ipa_topo_util_modify(sdn, smods);
+ slapi_sdn_free(&sdn);
+
+ /* find binddn group */
+ slapi_pblock_init(pb);
+
+ slapi_search_internal_set_pb(pb, ipa_topo_get_plugin_shared_bindgroup(), LDAP_SCOPE_BASE,
+ "(objectclass=groupofnames)",
+ NULL, 0, NULL, NULL, ipa_topo_get_plugin_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret != 0) {
+ sdn = NULL;
+ } else {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "ipa_topo_agreement_dn: no replica found\n");
+ sdn = NULL;
+ } else {
+ sdn = slapi_sdn_dup(slapi_entry_get_sdn(entries[0]));
+ }
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+
+ /* delete principal as binddn group member */
+ smods = slapi_mods_new();
+ slapi_mods_add_string(smods, LDAP_MOD_DELETE,
+ "member", principal);
+ ret = ipa_topo_util_modify(sdn, smods);
+ slapi_mods_free(&smods);
+ slapi_sdn_free(&sdn);
+ slapi_log_error(SLAPI_LOG_PLUGIN, IPA_TOPO_PLUGIN_SUBSYSTEM,
+ "<-- ipa_topo_util_disable_repl_for_principal\n");
+
+}
diff --git a/freeipa.spec.in b/freeipa.spec.in
index b14acee63..7dc576256 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -405,6 +405,7 @@ rm %{buildroot}/%{plugin_dir}/libipa_extdom_extop.la
rm %{buildroot}/%{plugin_dir}/libipa_range_check.la
rm %{buildroot}/%{plugin_dir}/libipa_otp_counter.la
rm %{buildroot}/%{plugin_dir}/libipa_otp_lasttoken.la
+rm %{buildroot}/%{plugin_dir}/libtopology.la
rm %{buildroot}/%{_libdir}/krb5/plugins/kdb/ipadb.la
rm %{buildroot}/%{_libdir}/samba/pdb/ipasam.la
@@ -798,6 +799,7 @@ fi
%attr(755,root,root) %{plugin_dir}/libipa_range_check.so
%attr(755,root,root) %{plugin_dir}/libipa_otp_counter.so
%attr(755,root,root) %{plugin_dir}/libipa_otp_lasttoken.so
+%attr(755,root,root) %{plugin_dir}/libtopology.so
%dir %{_localstatedir}/lib/ipa
%attr(700,root,root) %dir %{_localstatedir}/lib/ipa/backup
%attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore
diff --git a/install/share/70topology.ldif b/install/share/70topology.ldif
new file mode 100644
index 000000000..5a13255ac
--- /dev/null
+++ b/install/share/70topology.ldif
@@ -0,0 +1,15 @@
+# IPA Topology Plugin schema
+# BaseOID: 2.16.840.1.113730.3.8.20
+dn: cn=schema
+attributetypes: ( 2.16.840.1.113730.3.8.20.2.1 NAME 'ipaReplTopoConfRoot' DESC 'IPA defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'FreeIPA' )
+attributetypes: ( 2.16.840.1.113730.3.8.20.2.2 NAME 'ipaReplTopoSegmentDirection' DESC 'IPA defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'FreeIPA' )
+attributetypes: ( 2.16.840.1.113730.3.8.20.2.3 NAME 'ipaReplTopoSegmentLeftNode' DESC 'IPA defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'FreeIPA' )
+attributetypes: ( 2.16.840.1.113730.3.8.20.2.4 NAME 'ipaReplTopoSegmentRightNode' DESC 'IPA defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'FreeIPA' )
+attributetypes: ( 2.16.840.1.113730.3.8.20.2.5 NAME 'ipaReplTopoSegmentStatus' DESC 'IPA defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'FreeIPA' )
+attributetypes: ( 2.16.840.1.113730.3.8.20.2.6 NAME 'ipaReplTopoSegmentGenerated' DESC 'IPA defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'FreeIPA' )
+attributetypes: ( 2.16.840.1.113730.3.8.20.2.7 NAME 'ipaReplTopoManagedAgreementState' DESC 'IPA defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'FreeIPA' )
+attributetypes: ( 2.16.840.1.113730.3.8.20.2.8 NAME 'ipaReplTopoManagedSuffix' DESC 'IPA defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'FreeIPA' )
+objectclasses: ( 2.16.840.1.113730.3.8.20.1.1 NAME 'ipaReplTopoConf' DESC 'IPA defined objectclass' SUP top STRUCTURAL MUST ipaReplTopoConfRoot MAY ( cn $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal ) X-ORIGIN 'Free IPA' )
+objectclasses: ( 2.16.840.1.113730.3.8.20.1.2 NAME 'ipaReplTopoSegment' DESC 'IPA defined objectclass' SUP top STRUCTURAL MUST ( ipaReplTopoSegmentDirection $ ipaReplTopoSegmentLeftNode $ ipaReplTopoSegmentRightNode) MAY ( cn $ ipaReplTopoSegmentStatus $ ipaReplTopoSegmentGenerated $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsds5BeginReplicaRefresh $ description $ nsds5replicaTimeout $ nsds5ReplicaEnabled $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime $ nsds5ReplicaProtocolTimeout ) X-ORIGIN 'Free IPA' )
+objectclasses: ( 2.16.840.1.113730.3.8.20.1.3 NAME 'ipaReplTopoManagedAgreement' DESC 'marker objectclass for managed replication agreements' SUP top AUXILIARY MAY ( ipaReplTopoManagedAgreementState ) X-ORIGIN 'Free IPA' )
+objectclasses: ( 2.16.840.1.113730.3.8.20.1.4 NAME 'ipaReplTopoManagedServer' DESC 'part of managed replication topology' SUP top AUXILIARY MAY ( ipaReplTopoManagedSuffix ) X-ORIGIN 'Free IPA' )
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index ca6128e29..da3ed3176 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -20,6 +20,7 @@ app_DATA = \
65ipacertstore.ldif \
65ipasudo.ldif \
70ipaotp.ldif \
+ 70topology.ldif \
71idviews.ldif \
anonymous-vlv.ldif \
bootstrap-template.ldif \