This patch enables transaction support in 389-ds-base and fixes a few transaction issues within IPA.

This converts parts of the password and modrnd plugins to support transactions. The password plugin still largely runs as non-transactional because extop plugins aren't supported in transactions yet.

I've left the wait_for_attr code in place for now but on reflection we should probably remove it. I'll leave that up to the reviewer, but I can't see the need for it any more.

In order for this to work you'll need to apply the last two patches (both 0001) to slapi-nis and spin it up yourself, otherwise you'll have serious deadlock issues. I know this is extra work but this patch is potentially disruptive so I figure the earlier it is out the better.

Noriko/Rich/Nalin, can you guys review the slapi-nis pieces? I may have been too aggressive in my cleanup.

Noriko/Rich, can you review the 389-ds plugin parts of my 1072 patch?

Once we have an official slapi-nis build with these patches we'll need to set the minimum n-v-r in our spec file.

rob
>From aaeb6c0efd0289ca17731ab8cc8e62e39e8b1c5d Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Thu, 15 Nov 2012 21:38:26 -0500
Subject: [PATCH] Enable transactions by default, make password and modrdn
 TXN-aware

The password and modrdn plugins needed to be made transaction aware
for the pre and post operations.

Remove the reverse member hoop jumping. Just fetch the entry once
and all the memberof data is there (plus objectclass).

Fix some unit tests that are failing because we actually get the data
now due to transactions.

Add small bit of code in user plugin to retrieve the user again
ala wait_for_attr but in the case of transactions we need do it only
once.

https://fedorahosted.org/freeipa/ticket/1263
https://fedorahosted.org/freeipa/ticket/1891
https://fedorahosted.org/freeipa/ticket/2056
https://fedorahosted.org/freeipa/ticket/3043
https://fedorahosted.org/freeipa/ticket/3191
https://fedorahosted.org/freeipa/ticket/3046
---
 daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c  | 26 ++++++++--
 .../ipa-slapi-plugins/ipa-modrdn/modrdn-conf.ldif  |  2 +-
 .../ipa-pwd-extop/ipa_pwd_extop.c                  | 21 ++++++++
 daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h   |  2 +
 .../ipa-pwd-extop/ipapwd_prepost.c                 | 24 +++++++++
 .../ipa-pwd-extop/pwd-extop-conf.ldif              |  1 +
 install/share/nis.uldif                            |  1 +
 install/share/schema_compat.uldif                  |  1 +
 install/updates/10-disable-betxn.update            | 37 -------------
 install/updates/10-enable-betxn.update             | 43 ++++++++++++++++
 install/updates/Makefile.am                        |  2 +-
 ipalib/plugins/baseldap.py                         | 60 +++-------------------
 ipalib/plugins/user.py                             |  5 ++
 ipaserver/install/dsinstance.py                    |  4 --
 tests/test_xmlrpc/test_automember_plugin.py        | 10 ++++
 tests/test_xmlrpc/test_nesting.py                  |  1 +
 tests/test_xmlrpc/test_permission_plugin.py        |  2 +-
 tests/test_xmlrpc/test_privilege_plugin.py         |  7 +++
 tests/test_xmlrpc/test_role_plugin.py              |  5 ++
 19 files changed, 152 insertions(+), 102 deletions(-)
 delete mode 100644 install/updates/10-disable-betxn.update
 create mode 100644 install/updates/10-enable-betxn.update

diff --git a/daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c b/daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c
index 70a4ea82144829015e663c37212af7196a9ad72a..6cec5f242b7d23d3752e5bc30c67e034abc96abb 100644
--- a/daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c
+++ b/daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c
@@ -201,6 +201,12 @@ ipamodrdn_init(Slapi_PBlock *pb)
 {
     int status = EOK;
     char *plugin_identity = NULL;
+    Slapi_Entry *plugin_entry = NULL;
+    char *plugin_type = NULL;
+    int delfn = SLAPI_PLUGIN_POST_DELETE_FN;
+    int mdnfn = SLAPI_PLUGIN_POST_MODRDN_FN;
+    int modfn = SLAPI_PLUGIN_POST_MODIFY_FN;
+    int addfn = SLAPI_PLUGIN_POST_ADD_FN;
 
     LOG_TRACE("--in-->\n");
 
@@ -213,6 +219,18 @@ ipamodrdn_init(Slapi_PBlock *pb)
     PR_ASSERT(plugin_identity);
     setPluginID(plugin_identity);
 
+    if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
+        plugin_entry &&
+        (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
+        plugin_type && strstr(plugin_type, "betxn"))
+    {
+        addfn = SLAPI_PLUGIN_BE_TXN_POST_ADD_FN;
+        mdnfn = SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN;
+        delfn = SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN;
+        modfn = SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN;
+    }
+    slapi_ch_free_string(&plugin_type);
+
     if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
                          SLAPI_PLUGIN_VERSION_01) != 0 ||
         slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
@@ -221,13 +239,13 @@ ipamodrdn_init(Slapi_PBlock *pb)
                          (void *) ipamodrdn_start) != 0 ||
         slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
                          (void *) ipamodrdn_close) != 0 ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
+        slapi_pblock_set(pb, addfn,
                          (void *) ipamodrdn_config_check_post_op) != 0 ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN,
+        slapi_pblock_set(pb, mdnfn,
                          (void *) ipamodrdn_post_op) != 0 ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN,
+        slapi_pblock_set(pb, delfn,
                          (void *) ipamodrdn_config_check_post_op) != 0 ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN,
+        slapi_pblock_set(pb, modfn,
                          (void *) ipamodrdn_config_check_post_op) != 0) {
         LOG_FATAL("failed to register plugin\n");
         status = EFAIL;
diff --git a/daemons/ipa-slapi-plugins/ipa-modrdn/modrdn-conf.ldif b/daemons/ipa-slapi-plugins/ipa-modrdn/modrdn-conf.ldif
index 176f8becfcc0c394ecf8b9fdd56589f85c1170b6..3ae1ee2fdcbf26358bb88ea277149a57d89dd69f 100644
--- a/daemons/ipa-slapi-plugins/ipa-modrdn/modrdn-conf.ldif
+++ b/daemons/ipa-slapi-plugins/ipa-modrdn/modrdn-conf.ldif
@@ -6,7 +6,7 @@ objectclass: extensibleObject
 cn: IPA MODRDN
 nsslapd-pluginpath: libipa_modrdn
 nsslapd-plugininitfunc: ipamodrdn_init
-nsslapd-plugintype: postoperation
+nsslapd-plugintype: betxnpostoperation
 nsslapd-pluginenabled: on
 nsslapd-pluginid: ipamodrdn_version
 nsslapd-pluginversion: 1.0
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
index f9cff70cbaec782b9f3da29c34eb49a425ebc548..425b1c07d8e165231443dd36bfc5a59306f9f044 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
@@ -1270,6 +1270,15 @@ static char *ipapwd_name_list[] = {
 int ipapwd_init( Slapi_PBlock *pb )
 {
     int ret;
+    Slapi_Entry *plugin_entry = NULL;
+    int is_betxn = 0;
+
+    /* get args */
+    if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
+        plugin_entry) {
+            is_betxn = slapi_entry_attr_get_bool(plugin_entry,
+                                                 "nsslapd-pluginbetxn");
+    }
 
     /* Get the arguments appended to the plugin extendedop directive. The first argument
      * (after the standard arguments for the directive) should contain the OID of the
@@ -1301,6 +1310,18 @@ int ipapwd_init( Slapi_PBlock *pb )
         return -1;
     }
 
+    if (is_betxn) {
+        slapi_register_plugin("betxnpreoperation", 1,
+                              "ipapwd_pre_init_betxn", ipapwd_pre_init_betxn,
+                              "IPA pwd pre ops betxn", NULL,
+                              ipapwd_plugin_id);
+
+        slapi_register_plugin("betxnpostoperation", 1,
+                              "ipapwd_post_init_betxn", ipapwd_post_init_betxn,
+                              "IPA pwd post ops betxn", NULL,
+                              ipapwd_plugin_id);
+    } 
+
     slapi_register_plugin("preoperation", 1,
                           "ipapwd_pre_init", ipapwd_pre_init,
                           "IPA pwd pre ops", NULL,
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
index 0edd2dcad580b25d108a762bd78271b3d8244bc5..3689783ca2bd46e63aa528e3e0f8e49490c01b8d 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
@@ -152,4 +152,6 @@ int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg,
 int ipapwd_ext_init(void);
 int ipapwd_pre_init(Slapi_PBlock *pb);
 int ipapwd_post_init(Slapi_PBlock *pb);
+int ipapwd_pre_init_betxn(Slapi_PBlock *pb);
+int ipapwd_post_init_betxn(Slapi_PBlock *pb);
 
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
index e4909c94585b6fac6b7f8347b806a8841107f3d0..0e4a63b493347f8c88efdaeac09cf7da92dfcd63 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
@@ -1307,6 +1307,19 @@ int ipapwd_pre_init(Slapi_PBlock *pb)
     return ret;
 }
 
+int ipapwd_pre_init_betxn(Slapi_PBlock *pb)
+{
+    int ret;
+
+    ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_BIND_FN, (void *)ipapwd_pre_bind);
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN, (void *)ipapwd_pre_add);
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN, (void *)ipapwd_pre_mod);
+
+    return ret;
+}
+
 /* Init post ops */
 int ipapwd_post_init(Slapi_PBlock *pb)
 {
@@ -1320,3 +1333,14 @@ int ipapwd_post_init(Slapi_PBlock *pb)
     return ret;
 }
 
+int ipapwd_post_init_betxn(Slapi_PBlock *pb)
+{
+    int ret;
+
+    ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN, (void *)ipapwd_post_op);
+    if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN, (void *)ipapwd_post_op);
+
+    return ret;
+}
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/pwd-extop-conf.ldif b/daemons/ipa-slapi-plugins/ipa-pwd-extop/pwd-extop-conf.ldif
index e31a8e79b3b303f4631ef46d5f63e8ae2afbafee..4d4e6e6b53ab49a7462e6e7021e4906855873714 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/pwd-extop-conf.ldif
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/pwd-extop-conf.ldif
@@ -7,6 +7,7 @@ cn: ipa_pwd_extop
 nsslapd-pluginpath: libipa_pwd_extop
 nsslapd-plugininitfunc: ipapwd_init
 nsslapd-plugintype: extendedop
+nsslapd-pluginbetxn: on
 nsslapd-pluginenabled: on
 nsslapd-pluginid: ipa_pwd_extop
 nsslapd-pluginversion: 1.0
diff --git a/install/share/nis.uldif b/install/share/nis.uldif
index 1e548289008b6655e9b9a7eaccac4d42d52affb7..1735fb55299d28ab40d864b24062309fca43241f 100644
--- a/install/share/nis.uldif
+++ b/install/share/nis.uldif
@@ -6,6 +6,7 @@ default:cn: NIS Server
 default:nsslapd-pluginpath: /usr/lib$LIBARCH/dirsrv/plugins/nisserver-plugin.so
 default:nsslapd-plugininitfunc: nis_plugin_init
 default:nsslapd-plugintype: object
+default:nsslapd-pluginbetxn: on
 default:nsslapd-pluginenabled: on
 default:nsslapd-pluginid: nis-server
 default:nsslapd-pluginversion: 0.10
diff --git a/install/share/schema_compat.uldif b/install/share/schema_compat.uldif
index deca1bb416c352ee6cbca0a67576706a317d8b2e..a93b32771491bf1851937955ba30afd788291fc3 100644
--- a/install/share/schema_compat.uldif
+++ b/install/share/schema_compat.uldif
@@ -14,6 +14,7 @@ default:nsslapd-plugintype: object
 default:nsslapd-pluginenabled: on
 default:nsslapd-pluginid: schema-compat-plugin
 default:nsslapd-pluginversion: 0.8
+default:nsslapd-pluginbetxn: on
 default:nsslapd-pluginvendor: redhat.com
 default:nsslapd-plugindescription: Schema Compatibility Plugin
 
diff --git a/install/updates/10-disable-betxn.update b/install/updates/10-disable-betxn.update
deleted file mode 100644
index 8fca4a5e8c20938dc5eff0505b4ac27bb0a9b007..0000000000000000000000000000000000000000
--- a/install/updates/10-disable-betxn.update
+++ /dev/null
@@ -1,37 +0,0 @@
-# Disable transactions in 389-ds-base
-
-dn: cn=7-bit check,cn=plugins,cn=config
-only: nsslapd-pluginType: preoperation
-
-dn: cn=attribute uniqueness,cn=plugins,cn=config
-only: nsslapd-pluginType: preoperation
-
-dn: cn=Auto Membership Plugin,cn=plugins,cn=config
-only: nsslapd-pluginType: preoperation
-
-dn: cn=Linked Attributes,cn=plugins,cn=config
-only: nsslapd-pluginType: preoperation
-
-dn: cn=Managed Entries,cn=plugins,cn=config
-only: nsslapd-pluginType: preoperation
-
-dn: cn=MemberOf Plugin,cn=plugins,cn=config
-only: nsslapd-pluginType: postoperation
-
-dn: cn=Multimaster Replication Plugin,cn=plugins,cn=config
-only: nsslapd-pluginbetxn: off
-
-dn: cn=PAM Pass Through Auth,cn=plugins,cn=config
-only: nsslapd-pluginType: preoperation
-
-dn: cn=referential integrity postoperation,cn=plugins,cn=config
-only: nsslapd-pluginType: postoperation
-
-dn: cn=Roles Plugin,cn=plugins,cn=config
-only: nsslapd-pluginbetxn: off
-
-dn: cn=State Change Plugin,cn=plugins,cn=config
-only: nsslapd-pluginType: postoperation
-
-dn: cn=USN,cn=plugins,cn=config
-only: nsslapd-pluginbetxn: off
diff --git a/install/updates/10-enable-betxn.update b/install/updates/10-enable-betxn.update
new file mode 100644
index 0000000000000000000000000000000000000000..08c9152d9785d86e22334b32a8dba6a5e13595eb
--- /dev/null
+++ b/install/updates/10-enable-betxn.update
@@ -0,0 +1,43 @@
+# Enable transactions in 389-ds-base
+
+dn: cn=7-bit check,cn=plugins,cn=config
+only: nsslapd-pluginType: betxnpreoperation
+
+dn: cn=attribute uniqueness,cn=plugins,cn=config
+only: nsslapd-pluginType: betxnpreoperation
+
+dn: cn=Auto Membership Plugin,cn=plugins,cn=config
+only: nsslapd-pluginType: betxnpreoperation
+
+dn: cn=Linked Attributes,cn=plugins,cn=config
+only: nsslapd-pluginType: betxnpreoperation
+
+dn: cn=Managed Entries,cn=plugins,cn=config
+only: nsslapd-pluginType: betxnpreoperation
+
+dn: cn=MemberOf Plugin,cn=plugins,cn=config
+only: nsslapd-pluginType: betxnpostoperation
+
+dn: cn=Multimaster Replication Plugin,cn=plugins,cn=config
+only: nsslapd-pluginbetxn: on
+
+dn: cn=PAM Pass Through Auth,cn=plugins,cn=config
+only: nsslapd-pluginType: betxnpreoperation
+
+dn: cn=referential integrity postoperation,cn=plugins,cn=config
+only: nsslapd-pluginType: betxnpostoperation
+
+dn: cn=Roles Plugin,cn=plugins,cn=config
+only: nsslapd-pluginbetxn: on
+
+dn: cn=State Change Plugin,cn=plugins,cn=config
+only: nsslapd-pluginType: betxnpostoperation
+
+dn: cn=USN,cn=plugins,cn=config
+only: nsslapd-pluginbetxn: on
+
+dn: cn=IPA MODRDN,cn=plugins,cn=config
+only: nsslapd-plugintype: betxnpostoperation
+
+dn: cn=ipa_pwd_extop,cn=plugins,cn=config
+only: nsslapd-pluginbetxn: on
diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am
index a675af8b48f69ed8e4fa7fd4335ad75de7de86b8..2e4f0a2644f8f21cdbe5057895d36bf11e78ad46 100644
--- a/install/updates/Makefile.am
+++ b/install/updates/Makefile.am
@@ -7,7 +7,7 @@ app_DATA =				\
 	10-RFC2307bis.update		\
 	10-RFC4876.update		\
 	10-config.update		\
-	10-disable-betxn.update		\
+	10-enable-betxn.update		\
 	10-selinuxusermap.update	\
 	10-sudo.update			\
 	10-ssh.update			\
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index a55a23244b65dd98b8bcd63b587471e436bf3743..85e2bec36b011fd4539dfadc8d97535bb157bca7 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -231,50 +231,6 @@ def entry_from_entry(entry, newentry):
     for e in newentry:
         entry[e] = newentry[e]
 
-def wait_for_memberof(keys, entry_start, completed, show_command, adding=True):
-    """
-    When adding or removing reverse members we are faking an update to
-    object A by updating the member attribute in object B. The memberof
-    plugin makes this work by adding or removing the memberof attribute
-    to/from object A, it just takes a little bit of time.
-
-    This will loop for 6+ seconds, retrieving object A so we can see
-    if all the memberof attributes have been updated.
-    """
-    if completed == 0:
-        # nothing to do
-        return api.Command[show_command](keys[-1])['result']
-
-    if 'memberof' in entry_start:
-        starting_memberof = len(entry_start['memberof'])
-    else:
-        starting_memberof = 0
-
-    # Loop a few times to give the memberof plugin a chance to add the
-    # entries. Don't sleep for more than 6 seconds.
-    memberof = 0
-    x = 0
-    while x < 20:
-        # sleep first because the first search, even on a quiet system,
-        # almost always fails to have memberof set.
-        time.sleep(.3)
-        x = x + 1
-
-        # FIXME: put a try/except around here? I think it is probably better
-        # to just let the exception filter up to the caller.
-        entry_attrs = api.Command[show_command](keys[-1])['result']
-        if 'memberof' in entry_attrs:
-            memberof = len(entry_attrs['memberof'])
-
-        if adding:
-            if starting_memberof + completed >= memberof:
-                break
-        else:
-            if starting_memberof + completed <= memberof:
-                break
-
-    return entry_attrs
-
 def wait_for_value(ldap, dn, attr, value):
     """
     389-ds postoperation plugins are executed after the data has been
@@ -2029,11 +1985,9 @@ class LDAPAddReverseMember(LDAPModReverseMember):
             except errors.PublicError, e:
                 failed['member'][self.reverse_attr].append((attr, unicode(msg)))
 
-        # Wait for the memberof plugin to update the entry
-        try:
-            entry_attrs = wait_for_memberof(keys, entry_start, completed, self.show_command, adding=True)
-        except Exception, e:
-            raise errors.ReverseMemberError(verb=_('added'), exc=str(e))
+        # Update the member data.
+        (dn, entry_attrs) = ldap.get_entry(dn, ['*'])
+        self.obj.convert_attribute_members(entry_attrs, *keys, **options)
 
         for callback in self.get_callbacks('post'):
             (completed, dn) = callback(
@@ -2131,11 +2085,9 @@ class LDAPRemoveReverseMember(LDAPModReverseMember):
             except errors.PublicError, e:
                 failed['member'][self.reverse_attr].append((attr, unicode(msg)))
 
-        # Wait for the memberof plugin to update the entry
-        try:
-            entry_attrs = wait_for_memberof(keys, entry_start, completed, self.show_command, adding=False)
-        except Exception, e:
-            raise errors.ReverseMemberError(verb=_('removed'), exc=str(e))
+        # Update the member data.
+        (dn, entry_attrs) = ldap.get_entry(dn, ['*'])
+        self.obj.convert_attribute_members(entry_attrs, *keys, **options)
 
         for callback in self.get_callbacks('post'):
             (completed, dn) = callback(
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index 5d667dc94d483c2775d4a1d793624fc081615047..5a490bb730a1c945c45972d63fb2a99b7ef35de9 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -568,6 +568,11 @@ class user_add(LDAPCreate):
                 newentry = wait_for_value(ldap, dn, 'objectclass', 'mepOriginEntry')
                 entry_from_entry(entry_attrs, newentry)
 
+        if not self.api.env.wait_for_attr:
+            # have to update memberof, mep data in entry to return
+            (newdn, newentry) = ldap.get_entry(dn, ['*'])
+            entry_attrs.update(newentry)
+
         if options.get('random', False):
             try:
                 entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword'))
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index b48e7d7681b585a3f348cfe08b35ea8f723c0485..fe42282dc3a09fecaee2068b30ef16410b7b072d 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -202,7 +202,6 @@ class DsInstance(service.Service):
         self.step("configuring replication version plugin", self.__config_version_module)
         self.step("enabling IPA enrollment plugin", self.__add_enrollment_module)
         self.step("enabling ldapi", self.__enable_ldapi)
-        self.step("disabling betxn plugins", self.__disable_betxn)
         self.step("configuring uniqueness plugin", self.__set_unique_attrs)
         self.step("configuring uuid plugin", self.__config_uuid_module)
         self.step("configuring modrdn plugin", self.__config_modrdn_module)
@@ -476,9 +475,6 @@ class DsInstance(service.Service):
     def __add_referint_module(self):
         self._ldap_mod("referint-conf.ldif")
 
-    def __disable_betxn(self):
-        self._ldap_mod("disable-betxn.ldif", self.sub_dict)
-
     def __set_unique_attrs(self):
         self._ldap_mod("unique-attributes.ldif", self.sub_dict)
 
diff --git a/tests/test_xmlrpc/test_automember_plugin.py b/tests/test_xmlrpc/test_automember_plugin.py
index fcd9facb4184b87d4fd5ff1be5b8fdb92c1d9eeb..fdf3c73af351c6c78a20330598e98c89589faeb8 100644
--- a/tests/test_xmlrpc/test_automember_plugin.py
+++ b/tests/test_xmlrpc/test_automember_plugin.py
@@ -886,6 +886,8 @@ class test_automember(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[fqdn1],
+                    memberof_hostgroup=[hostgroup1],
+                    memberofindirect_netgroup=[hostgroup1],
                 ),
             ),
         ),
@@ -914,6 +916,8 @@ class test_automember(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[fqdn2],
+                    memberof_hostgroup=[defaulthostgroup1],
+                    memberofindirect_netgroup=[defaulthostgroup1],
                 ),
             ),
         ),
@@ -942,6 +946,8 @@ class test_automember(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[fqdn3],
+                    memberof_hostgroup=[hostgroup2],
+                    memberofindirect_netgroup=[hostgroup2],
                 ),
             ),
         ),
@@ -970,6 +976,8 @@ class test_automember(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[fqdn4],
+                    memberof_hostgroup=[hostgroup3],
+                    memberofindirect_netgroup=[hostgroup3],
                 ),
             ),
         ),
@@ -998,6 +1006,8 @@ class test_automember(Declarative):
                     objectclass=objectclasses.host,
                     ipauniqueid=[fuzzy_uuid],
                     managedby_host=[fqdn5],
+                    memberof_hostgroup=[hostgroup4],
+                    memberofindirect_netgroup=[hostgroup4],
                 ),
             ),
         ),
diff --git a/tests/test_xmlrpc/test_nesting.py b/tests/test_xmlrpc/test_nesting.py
index 6af9c9d23d0f5732bf00dbb3413856b6467f24ca..a09a7989e120866d7e46dced4941696b13a17fc1 100644
--- a/tests/test_xmlrpc/test_nesting.py
+++ b/tests/test_xmlrpc/test_nesting.py
@@ -750,6 +750,7 @@ class test_nesting(Declarative):
                     'cn': [hostgroup1],
                     'description': [u'Test hostgroup 1'],
                     'member_hostgroup': [hostgroup2],
+                    'memberindirect_host': [fqdn1],
                 },
             ),
         ),
diff --git a/tests/test_xmlrpc/test_permission_plugin.py b/tests/test_xmlrpc/test_permission_plugin.py
index eda96d0e31d28931b9e0b630ffa69bb9cbad0d1f..565e18efd0843857fc6050c54ff56555c9d35bc3 100644
--- a/tests/test_xmlrpc/test_permission_plugin.py
+++ b/tests/test_xmlrpc/test_permission_plugin.py
@@ -194,6 +194,7 @@ class test_permission(Declarative):
                     'cn': [privilege1],
                     'description': [u'privilege desc. 1'],
                     'memberof_permission': [permission1],
+                    'objectclass': objectclasses.privilege,
                 }
             ),
         ),
@@ -504,7 +505,6 @@ class test_permission(Declarative):
                         'permissions' : [u'write'],
                         'attrs': [u'servicecategory', u'sourcehostcategory', u'cn', u'description', u'ipaenabledflag', u'accesstime', u'usercategory', u'hostcategory', u'accessruletype', u'sourcehost'],
                         'subtree' : u'ldap:///%s' % DN(('ipauniqueid', '*'), ('cn', 'hbac'), api.env.basedn),
-                        'memberindirect': [DN(('cn', 'it security specialist'), ('cn', 'roles'), ('cn', 'accounts'), api.env.basedn)],
                     },
                 ],
             ),
diff --git a/tests/test_xmlrpc/test_privilege_plugin.py b/tests/test_xmlrpc/test_privilege_plugin.py
index d4784af8c65a99cc4fefc840315df1a2cc582db7..81e51d5e193c5c6d2c199c1832f3513d0c921266 100644
--- a/tests/test_xmlrpc/test_privilege_plugin.py
+++ b/tests/test_xmlrpc/test_privilege_plugin.py
@@ -142,6 +142,7 @@ class test_privilege(Declarative):
                     'cn': [privilege1],
                     'description': [u'privilege desc. 1'],
                     'memberof_permission': [permission1],
+                    'objectclass': objectclasses.privilege,
                 }
             ),
         ),
@@ -240,6 +241,7 @@ class test_privilege(Declarative):
                     'cn': [privilege1],
                     'description': [u'privilege desc. 1'],
                     'memberof_permission': [permission1, permission2],
+                    'objectclass': objectclasses.privilege,
                 }
             ),
         ),
@@ -262,6 +264,7 @@ class test_privilege(Declarative):
                     'cn': [privilege1],
                     'description': [u'privilege desc. 1'],
                     'memberof_permission': [permission1, permission2],
+                    'objectclass': objectclasses.privilege,
                 }
             ),
         ),
@@ -320,6 +323,7 @@ class test_privilege(Declarative):
                     'cn': [privilege1],
                     'description': [u'New desc 1'],
                     'memberof_permission': [permission2],
+                    'objectclass': objectclasses.privilege,
                 }
             ),
         ),
@@ -342,6 +346,7 @@ class test_privilege(Declarative):
                     'cn': [privilege1],
                     'description': [u'New desc 1'],
                     'memberof_permission': [permission2],
+                    'objectclass': objectclasses.privilege,
                 }
             ),
         ),
@@ -364,6 +369,7 @@ class test_privilege(Declarative):
                     'cn': [privilege1],
                     'description': [u'New desc 1'],
                     'memberof_permission': [permission2],
+                    'objectclass': objectclasses.privilege,
                 }
             ),
         ),
@@ -386,6 +392,7 @@ class test_privilege(Declarative):
                     'cn': [privilege1],
                     'description': [u'New desc 1'],
                     'memberof_permission': [permission2],
+                    'objectclass': objectclasses.privilege,
                 }
             ),
         ),
diff --git a/tests/test_xmlrpc/test_role_plugin.py b/tests/test_xmlrpc/test_role_plugin.py
index b847ca9eb4e3b1d701bc6adebf5f1e8d6f96ee91..be3fecebc8d94d6255fbd30b0a2ee20d3913f711 100644
--- a/tests/test_xmlrpc/test_role_plugin.py
+++ b/tests/test_xmlrpc/test_role_plugin.py
@@ -196,6 +196,7 @@ class test_role(Declarative):
                     'cn': [role1],
                     'description': [u'role desc 1'],
                     'memberof_privilege': [privilege1],
+                    'objectclass': objectclasses.role,
                 }
             ),
         ),
@@ -217,6 +218,7 @@ class test_role(Declarative):
                     'cn': [role1],
                     'description': [u'role desc 1'],
                     'memberof_privilege': [privilege1],
+                    'objectclass': objectclasses.role,
                 }
             ),
         ),
@@ -238,6 +240,7 @@ class test_role(Declarative):
                     'cn': [role1],
                     'description': [u'role desc 1'],
                     'memberof_privilege': [privilege1],
+                    'objectclass': objectclasses.role,
                 }
             ),
         ),
@@ -518,6 +521,7 @@ class test_role(Declarative):
                     'dn': role1_dn,
                     'cn': [role1],
                     'description': [u'New desc 1'],
+                    'objectclass': objectclasses.role,
                 }
             ),
         ),
@@ -539,6 +543,7 @@ class test_role(Declarative):
                     'dn': role1_dn,
                     'cn': [role1],
                     'description': [u'New desc 1'],
+                    'objectclass': objectclasses.role,
                 }
             ),
         ),
-- 
1.8.0

>From f0521cc895386972c791178a168812cead8ce66d Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nho...@redhat.com>
Date: Fri, 31 Aug 2012 14:42:05 -0700
Subject: [PATCH] make NIS Plugin and Schema Compatibility Plugin betxn aware

When NIS Plugin and Schema Compatibility Plugin config entries include
  nsslapd-pluginbetxn: on
  (the value could be yes, true or 1, too),
the plugins' update callbacks (add, delete, modify, and modrdn) are
called at the betxn pre/postop timing. By default, the value of
nsslapd-pluginbetxn is off.
(See also https://fedorahosted.org/389/ticket/351)
---
 src/back-sch.c |  80 ++++++++++++++++++++++++++++-------
 src/back-shr.c |  47 ++++++++++++++-------
 src/backend.h  |   1 +
 src/plug-nis.c |  34 +++++++++++----
 src/plug-sch.c | 129 +++++++++++++++++++++++++++++++++++++++++++++------------
 5 files changed, 226 insertions(+), 65 deletions(-)

diff --git a/src/back-sch.c b/src/back-sch.c
index aecea67..e889458 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1441,52 +1441,104 @@ backend_startup(Slapi_PBlock *pb, struct plugin_state *state)
 int
 backend_init_preop(Slapi_PBlock *pb, struct plugin_state *state)
 {
+	int bindfn = SLAPI_PLUGIN_PRE_BIND_FN;
+	int cmpfn = SLAPI_PLUGIN_PRE_COMPARE_FN;
+	int srchfn = SLAPI_PLUGIN_PRE_SEARCH_FN;
+	int addfn = SLAPI_PLUGIN_PRE_ADD_FN;
+	int modfn = SLAPI_PLUGIN_PRE_MODIFY_FN;
+	int mdnfn = SLAPI_PLUGIN_PRE_MODRDN_FN;
+	int delfn = SLAPI_PLUGIN_PRE_DELETE_FN;
+	Slapi_Entry *plugin_entry = NULL;
+	char *plugin_type = NULL;
+	int is_betxn = 0;
+
+	if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
+	     plugin_entry &&
+	    (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
+	    plugin_type && strstr(plugin_type, "betxn")) {
+		is_betxn = 1;
+	}
+	slapi_ch_free_string(&plugin_type);
+
 	slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 			"hooking up preoperation callbacks\n");
 	/* Intercept bind requests and return a referral or failure for entries
 	 * that we're managing. */
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_BIND_FN,
-			     backend_bind_cb) != 0) {
+	if (slapi_pblock_set(pb, bindfn, backend_bind_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up bind callback\n");
 		return -1;
 	}
 	/* Intercept compare requests and return the right data. */
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_COMPARE_FN,
-			     backend_compare_cb) != 0) {
+	if (slapi_pblock_set(pb, cmpfn, backend_compare_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up compare callback\n");
 		return -1;
 	}
 	/* Intercept search requests and return the right data. */
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_SEARCH_FN,
-			     backend_search_cb) != 0) {
+	if (slapi_pblock_set(pb, srchfn, backend_search_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up search callback\n");
 		return -1;
 	}
+	if (!is_betxn) {
+		/* if is_betxn, these callbacks are registered for betxnpreop */
+		/* Intercept write requests and return an insufficient-access error for
+		 * attempts to write to anything we're managing. */
+		if (slapi_pblock_set(pb, addfn, backend_write_cb) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+					"error hooking up add callback\n");
+			return -1;
+		}
+		if (slapi_pblock_set(pb, modfn, backend_write_cb) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+					"error hooking up modify callback\n");
+			return -1;
+		}
+		if (slapi_pblock_set(pb, mdnfn, backend_write_cb) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+					"error hooking up modrdn callback\n");
+			return -1;
+		}
+		if (slapi_pblock_set(pb, delfn, backend_write_cb) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+					"error hooking up delete callback\n");
+			return -1;
+		}
+	}
+	/* We don't hook abandonment requests. */
+	/* We don't hook unbind requests. */
+	return 0;
+}
+
+int
+backend_init_betxnpreop(Slapi_PBlock *pb, struct plugin_state *state)
+{
+	int addfn = SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN;
+	int modfn = SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN;
+	int mdnfn = SLAPI_PLUGIN_BE_TXN_PRE_MODRDN_FN;
+	int delfn = SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN;
+
+	slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+	                "hooking up betxn preoperation callbacks\n");
 	/* Intercept write requests and return an insufficient-access error for
 	 * attempts to write to anything we're managing. */
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN,
-			     backend_write_cb) != 0) {
+	if (slapi_pblock_set(pb, addfn, backend_write_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up add callback\n");
 		return -1;
 	}
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN,
-			     backend_write_cb) != 0) {
+	if (slapi_pblock_set(pb, modfn, backend_write_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up modify callback\n");
 		return -1;
 	}
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODRDN_FN,
-			     backend_write_cb) != 0) {
+	if (slapi_pblock_set(pb, mdnfn, backend_write_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up modrdn callback\n");
 		return -1;
 	}
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_DELETE_FN,
-			     backend_write_cb) != 0) {
+	if (slapi_pblock_set(pb, delfn, backend_write_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up delete callback\n");
 		return -1;
diff --git a/src/back-shr.c b/src/back-shr.c
index a2c31c9..99955b6 100644
--- a/src/back-shr.c
+++ b/src/back-shr.c
@@ -2245,26 +2245,40 @@ backend_shr_internal_delete_cb(Slapi_PBlock *pb)
 int
 backend_shr_postop_init(Slapi_PBlock *pb, struct plugin_state *state)
 {
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
-			     backend_shr_add_cb) != 0) {
+	int addfn = SLAPI_PLUGIN_POST_ADD_FN;
+	int modfn = SLAPI_PLUGIN_POST_MODIFY_FN;
+	int mdnfn = SLAPI_PLUGIN_POST_MODRDN_FN;
+	int delfn = SLAPI_PLUGIN_POST_DELETE_FN;
+	Slapi_Entry *plugin_entry = NULL;
+	char *plugin_type = NULL;
+
+	if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
+	     plugin_entry &&
+	    (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
+	    plugin_type && strstr(plugin_type, "betxn")) {
+		addfn = SLAPI_PLUGIN_BE_TXN_POST_ADD_FN;
+		modfn = SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN;
+		mdnfn = SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN;
+		delfn = SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN;
+	}
+	slapi_ch_free_string(&plugin_type);
+
+	if (slapi_pblock_set(pb, addfn, backend_shr_add_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up add callback\n");
 		return -1;
 	}
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN,
-			     backend_shr_modify_cb) != 0) {
+	if (slapi_pblock_set(pb, modfn, backend_shr_modify_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up modify callback\n");
 		return -1;
 	}
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN,
-			     backend_shr_modrdn_cb) != 0) {
+	if (slapi_pblock_set(pb, mdnfn, backend_shr_modrdn_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up modrdn callback\n");
 		return -1;
 	}
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN,
-			     backend_shr_delete_cb) != 0) {
+	if (slapi_pblock_set(pb, delfn, backend_shr_delete_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up delete callback\n");
 		return -1;
@@ -2275,26 +2289,27 @@ backend_shr_postop_init(Slapi_PBlock *pb, struct plugin_state *state)
 int
 backend_shr_internal_postop_init(Slapi_PBlock *pb, struct plugin_state *state)
 {
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN,
-			     backend_shr_internal_add_cb) != 0) {
+	int addfn = SLAPI_PLUGIN_INTERNAL_POST_ADD_FN;
+	int modfn = SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN;
+	int mdnfn = SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN;
+	int delfn = SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN;
+	
+	if (slapi_pblock_set(pb, addfn, backend_shr_internal_add_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up internal add callback\n");
 		return -1;
 	}
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN,
-			     backend_shr_internal_modify_cb) != 0) {
+	if (slapi_pblock_set(pb, modfn, backend_shr_internal_modify_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up internal modify callback\n");
 		return -1;
 	}
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN,
-			     backend_shr_internal_modrdn_cb) != 0) {
+	if (slapi_pblock_set(pb, mdnfn, backend_shr_internal_modrdn_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up internal modrdn callback\n");
 		return -1;
 	}
-	if (slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN,
-			     backend_shr_internal_delete_cb) != 0) {
+	if (slapi_pblock_set(pb, delfn, backend_shr_internal_delete_cb) != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 				"error hooking up internal delete callback\n");
 		return -1;
diff --git a/src/backend.h b/src/backend.h
index 7f52915..6dff74f 100644
--- a/src/backend.h
+++ b/src/backend.h
@@ -52,6 +52,7 @@ struct backend_shr_set_data {
 /* Startup/initialization functions called through the map. */
 void backend_startup(struct slapi_pblock *pb, struct plugin_state *state);
 int backend_init_preop(struct slapi_pblock *pb, struct plugin_state *state);
+int backend_init_betxnpreop(struct slapi_pblock *pb, struct plugin_state *state);
 int backend_init_postop(struct slapi_pblock *pb, struct plugin_state *state);
 int backend_init_internal_postop(struct slapi_pblock *pb,
 				 struct plugin_state *state);
diff --git a/src/plug-nis.c b/src/plug-nis.c
index 4c7ba98..201ba4e 100644
--- a/src/plug-nis.c
+++ b/src/plug-nis.c
@@ -482,6 +482,18 @@ int
 nis_plugin_init(Slapi_PBlock *pb)
 {
 	struct plugin_state *state = NULL;
+	Slapi_Entry *plugin_entry = NULL;
+	int is_betxn = 0;
+	char *plugin_type = "postoperation";
+
+	/* get args */
+	if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
+	    plugin_entry) {
+		is_betxn = slapi_entry_attr_get_bool(plugin_entry,
+		                                     "nsslapd-pluginbetxn");
+		plugin_type = "betxnpostoperation";
+	}
+
 	/* Allocate the module-global data and set up listening sockets. */
 	if (plugin_state_init(pb, &state) == -1) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
@@ -498,7 +510,7 @@ nis_plugin_init(Slapi_PBlock *pb)
 	slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, state);
 	/* Register the sub-plugins. */
 	global_plugin_state = state;
-	if (slapi_register_plugin("postoperation", TRUE,
+	if (slapi_register_plugin(plugin_type, TRUE,
 				  "nis_plugin_init_postop",
 				  nis_plugin_init_postop,
 				  PLUGIN_POSTOP_ID, NULL,
@@ -507,14 +519,18 @@ nis_plugin_init(Slapi_PBlock *pb)
 				"error registering postoperation plugin\n");
 		return -1;
 	}
-	if (slapi_register_plugin("internalpostoperation", TRUE,
-				  "nis_plugin_init_internal_postop",
-				  nis_plugin_init_internal_postop,
-				  PLUGIN_INTERNAL_POSTOP_ID, NULL,
-				  state->plugin_identity) != 0) {
-		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
-				"error registering internal postoperation plugin\n");
-		return -1;
+	if (!is_betxn) {
+		/* if betxn is on, the plugin is called inside of backend transaction,
+		 * which does not distinguish the internal operation. */
+		if (slapi_register_plugin("internalpostoperation", TRUE,
+					  "nis_plugin_init_internal_postop",
+					  nis_plugin_init_internal_postop,
+					  PLUGIN_INTERNAL_POSTOP_ID, NULL,
+					  state->plugin_identity) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+					"error registering internal postoperation plugin\n");
+			return -1;
+		}
 	}
 	slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 			"registered plugin hooks\n");
diff --git a/src/plug-sch.c b/src/plug-sch.c
index 44b0918..cb4a63e 100644
--- a/src/plug-sch.c
+++ b/src/plug-sch.c
@@ -123,6 +123,7 @@ plugin_shutdown(Slapi_PBlock *pb)
 	return 0;
 }
 
+/* preoperation: all callbacks are called at preop */
 static int
 schema_compat_plugin_init_preop(Slapi_PBlock *pb)
 {
@@ -137,6 +138,39 @@ schema_compat_plugin_init_preop(Slapi_PBlock *pb)
 	}
 	return 0;
 }
+
+/* betxnpreoperation: bind, compare and search callbacks are called at preop */
+static int
+schema_compat_plugin_init_betxnpreop_preop(Slapi_PBlock *pb)
+{
+	slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, &plugin_description);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, global_plugin_state);
+	if (backend_init_preop(pb, global_plugin_state) == -1) {
+		slapi_log_error(SLAPI_LOG_PLUGIN,
+				global_plugin_state->plugin_desc->spd_id,
+				"error registering preoperation hooks\n");
+		return -1;
+	}
+	return 0;
+}
+
+/* betxnpreoperation: add, delete, modify and modrdn callbacks are called at betxnpreop */
+static int
+schema_compat_plugin_init_betxnpreop(Slapi_PBlock *pb)
+{
+	slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, &plugin_description);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, global_plugin_state);
+	if (backend_init_betxnpreop(pb, global_plugin_state) == -1) {
+		slapi_log_error(SLAPI_LOG_PLUGIN,
+				global_plugin_state->plugin_desc->spd_id,
+				"error registering preoperation hooks\n");
+		return -1;
+	}
+	return 0;
+}
+
 static int
 schema_compat_plugin_init_postop(Slapi_PBlock *pb)
 {
@@ -169,6 +203,16 @@ int
 schema_compat_plugin_init(Slapi_PBlock *pb)
 {
 	struct plugin_state *state = NULL;
+	Slapi_Entry *plugin_entry = NULL;
+	int is_betxn = 0;
+
+	/* get args */
+	if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
+	    plugin_entry) {
+		is_betxn = slapi_entry_attr_get_bool(plugin_entry,
+		                                     "nsslapd-pluginbetxn");
+	}
+
 	/* Allocate a memory pool. */
 	if (plugin_state_init(pb, &state) == -1) {
 		slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
@@ -185,32 +229,65 @@ schema_compat_plugin_init(Slapi_PBlock *pb)
 	slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, state);
 	/* Register the sub-plugins. */
 	global_plugin_state = state;
-	if (slapi_register_plugin("preoperation", TRUE,
-				  "schema_compat_plugin_init_preop",
-				  schema_compat_plugin_init_preop,
-				  PLUGIN_PREOP_ID, NULL,
-				  state->plugin_identity) != 0) {
-		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
-				"error registering preoperation plugin\n");
-		return -1;
-	}
-	if (slapi_register_plugin("postoperation", TRUE,
-				  "schema_compat_plugin_init_postop",
-				  schema_compat_plugin_init_postop,
-				  PLUGIN_POSTOP_ID, NULL,
-				  state->plugin_identity) != 0) {
-		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
-				"error registering postoperation plugin\n");
-		return -1;
-	}
-	if (slapi_register_plugin("internalpostoperation", TRUE,
-				  "schema_compat_plugin_init_internal_postop",
-				  schema_compat_plugin_init_internal_postop,
-				  PLUGIN_INTERNAL_POSTOP_ID, NULL,
-				  state->plugin_identity) != 0) {
-		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
-				"error registering internal postoperation plugin\n");
-		return -1;
+	if (is_betxn) {
+		/* bind, compare and search callbacks are called at preop */
+		if (slapi_register_plugin("preoperation", TRUE,
+		                          "schema_compat_plugin_init_betxnpreop_preop",
+		                          schema_compat_plugin_init_betxnpreop_preop,
+		                          PLUGIN_PREOP_ID, NULL,
+		                          state->plugin_identity) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+			                "error registering betxn preoperation plugin\n");
+			return -1;
+		}
+		/* add, delete, modify and modrdn callbacks are called at betxnpreop */
+		if (slapi_register_plugin("betxnpreoperation", TRUE,
+		                          "schema_compat_plugin_init_betxnpreop",
+		                          schema_compat_plugin_init_betxnpreop,
+		                          PLUGIN_PREOP_ID, NULL,
+		                          state->plugin_identity) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+			                "error registering betxn preoperation plugin\n");
+			return -1;
+		}
+		if (slapi_register_plugin("betxnpostoperation", TRUE,
+		                          "schema_compat_plugin_init_postop",
+		                          schema_compat_plugin_init_postop,
+		                          PLUGIN_POSTOP_ID, NULL,
+		                          state->plugin_identity) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+			                "error registering postoperation plugin\n");
+			return -1;
+		}
+	} else {
+		/* preoperation: all callbacks are called at preop */
+		if (slapi_register_plugin("preoperation", TRUE,
+		                          "schema_compat_plugin_init_preop",
+		                          schema_compat_plugin_init_preop,
+		                          PLUGIN_PREOP_ID, NULL,
+		                          state->plugin_identity) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+			                "error registering preoperation plugin\n");
+			return -1;
+		}
+		if (slapi_register_plugin("postoperation", TRUE,
+		                          "schema_compat_plugin_init_postop",
+		                          schema_compat_plugin_init_postop,
+		                          PLUGIN_POSTOP_ID, NULL,
+		                          state->plugin_identity) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+			                "error registering postoperation plugin\n");
+			return -1;
+		}
+		if (slapi_register_plugin("internalpostoperation", TRUE,
+		                          "schema_compat_plugin_init_internal_postop",
+		                          schema_compat_plugin_init_internal_postop,
+		                          PLUGIN_INTERNAL_POSTOP_ID, NULL,
+		                          state->plugin_identity) != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+			                "error registering internal postoperation plugin\n");
+			return -1;
+		}
 	}
 	slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 			"registered plugin hooks\n");
-- 
1.7.11.4

>From bf6e4be1d7ffeb2a8ef3595b60537a901d8d4bbf Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Thu, 15 Nov 2012 10:33:34 -0500
Subject: [PATCH] Code cleanup

---
 src/back-sch.c |  9 +++------
 src/plug-nis.c |  4 +++-
 src/plug-sch.c | 40 ++++------------------------------------
 3 files changed, 10 insertions(+), 43 deletions(-)

diff --git a/src/back-sch.c b/src/back-sch.c
index e889458..d428469 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1449,16 +1449,13 @@ backend_init_preop(Slapi_PBlock *pb, struct plugin_state *state)
 	int mdnfn = SLAPI_PLUGIN_PRE_MODRDN_FN;
 	int delfn = SLAPI_PLUGIN_PRE_DELETE_FN;
 	Slapi_Entry *plugin_entry = NULL;
-	char *plugin_type = NULL;
 	int is_betxn = 0;
 
 	if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
-	     plugin_entry &&
-	    (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
-	    plugin_type && strstr(plugin_type, "betxn")) {
-		is_betxn = 1;
+	     plugin_entry) { 
+		is_betxn = slapi_entry_attr_get_bool(plugin_entry,
+							"nsslapd-pluginbetxn");
 	}
-	slapi_ch_free_string(&plugin_type);
 
 	slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 			"hooking up preoperation callbacks\n");
diff --git a/src/plug-nis.c b/src/plug-nis.c
index 201ba4e..ea50a64 100644
--- a/src/plug-nis.c
+++ b/src/plug-nis.c
@@ -491,7 +491,9 @@ nis_plugin_init(Slapi_PBlock *pb)
 	    plugin_entry) {
 		is_betxn = slapi_entry_attr_get_bool(plugin_entry,
 		                                     "nsslapd-pluginbetxn");
-		plugin_type = "betxnpostoperation";
+		if (is_betxn) {
+			plugin_type = "betxnpostoperation";
+		}
 	}
 
 	/* Allocate the module-global data and set up listening sockets. */
diff --git a/src/plug-sch.c b/src/plug-sch.c
index cb4a63e..775c164 100644
--- a/src/plug-sch.c
+++ b/src/plug-sch.c
@@ -139,38 +139,6 @@ schema_compat_plugin_init_preop(Slapi_PBlock *pb)
 	return 0;
 }
 
-/* betxnpreoperation: bind, compare and search callbacks are called at preop */
-static int
-schema_compat_plugin_init_betxnpreop_preop(Slapi_PBlock *pb)
-{
-	slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
-	slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, &plugin_description);
-	slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, global_plugin_state);
-	if (backend_init_preop(pb, global_plugin_state) == -1) {
-		slapi_log_error(SLAPI_LOG_PLUGIN,
-				global_plugin_state->plugin_desc->spd_id,
-				"error registering preoperation hooks\n");
-		return -1;
-	}
-	return 0;
-}
-
-/* betxnpreoperation: add, delete, modify and modrdn callbacks are called at betxnpreop */
-static int
-schema_compat_plugin_init_betxnpreop(Slapi_PBlock *pb)
-{
-	slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
-	slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, &plugin_description);
-	slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, global_plugin_state);
-	if (backend_init_betxnpreop(pb, global_plugin_state) == -1) {
-		slapi_log_error(SLAPI_LOG_PLUGIN,
-				global_plugin_state->plugin_desc->spd_id,
-				"error registering preoperation hooks\n");
-		return -1;
-	}
-	return 0;
-}
-
 static int
 schema_compat_plugin_init_postop(Slapi_PBlock *pb)
 {
@@ -232,8 +200,8 @@ schema_compat_plugin_init(Slapi_PBlock *pb)
 	if (is_betxn) {
 		/* bind, compare and search callbacks are called at preop */
 		if (slapi_register_plugin("preoperation", TRUE,
-		                          "schema_compat_plugin_init_betxnpreop_preop",
-		                          schema_compat_plugin_init_betxnpreop_preop,
+		                          "schema_compat_plugin_init_preop",
+		                          schema_compat_plugin_init_preop,
 		                          PLUGIN_PREOP_ID, NULL,
 		                          state->plugin_identity) != 0) {
 			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
@@ -242,8 +210,8 @@ schema_compat_plugin_init(Slapi_PBlock *pb)
 		}
 		/* add, delete, modify and modrdn callbacks are called at betxnpreop */
 		if (slapi_register_plugin("betxnpreoperation", TRUE,
-		                          "schema_compat_plugin_init_betxnpreop",
-		                          schema_compat_plugin_init_betxnpreop,
+		                          "schema_compat_plugin_init_preop",
+		                          schema_compat_plugin_init_preop,
 		                          PLUGIN_PREOP_ID, NULL,
 		                          state->plugin_identity) != 0) {
 			slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
-- 
1.8.0

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to