Branch '389-ds-base-1.2.11' - 2 commits - ldap/schema ldap/servers
by Noriko Hosoi
ldap/schema/01core389.ldif | 4
ldap/servers/plugins/replication/cl5_api.c | 48 ++++-
ldap/servers/plugins/replication/repl5.h | 11 +
ldap/servers/plugins/replication/repl5_agmt.c | 160 +++++++++++++++++
ldap/servers/plugins/replication/repl5_agmtlist.c | 26 ++
ldap/servers/plugins/replication/repl5_connection.c | 165 +++++++++++++++++-
ldap/servers/plugins/replication/repl5_inc_protocol.c | 32 +++
ldap/servers/plugins/replication/repl5_prot_private.h | 2
ldap/servers/plugins/replication/repl5_tot_protocol.c | 52 +++++
ldap/servers/plugins/replication/repl_globals.c | 3
ldap/servers/plugins/retrocl/retrocl_po.c | 6
ldap/servers/slapd/add.c | 13 -
ldap/servers/slapd/libglobs.c | 84 ++++++++-
ldap/servers/slapd/modify.c | 47 ++---
ldap/servers/slapd/opshared.c | 35 +--
ldap/servers/slapd/proto-slap.h | 2
ldap/servers/slapd/slap.h | 8
ldap/servers/slapd/slapi-plugin.h | 8
ldap/servers/slapd/slapi-private.h | 1
ldap/servers/slapd/util.c | 11 -
20 files changed, 644 insertions(+), 74 deletions(-)
New commits:
commit 88ecf0c9b43060822e5bc9a3ba38b48438c296e6
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Thu Apr 2 13:09:12 2015 -0700
Ticket #47942 - DS hangs during online total update
Backported the patch in the master branch to 389-ds-base-1.2.11
by Jatin Nansi (jnansi(a)redhat.com).
commit fbafee54dc17e0673004d6d26d739ea1b19dd578
Author: Thierry bordaz (tbordaz) <tbordaz(a)redhat.com>
Date: Mon Dec 15 15:12:35 2014 +0100
Ticket 47942: DS hangs during online total update
Reviewed by tbordaz(a)redhat.com and nhosoi(a)redhat.com.
https://fedorahosted.org/389/ticket/47942
diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif
index 7febc9f..ba5b0aa 100644
--- a/ldap/schema/01core389.ldif
+++ b/ldap/schema/01core389.ldif
@@ -153,6 +153,8 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2152 NAME 'nsds5ReplicaProtocolTimeout'
attributeTypes: ( 2.16.840.1.113730.3.1.2154 NAME 'nsds5ReplicaBackoffMin' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.2155 NAME 'nsds5ReplicaBackoffMax' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.2156 NAME 'nsslapd-sasl-max-buffer-size' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2310 NAME 'nsds5ReplicaFlowControlWindow' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2311 NAME 'nsds5ReplicaFlowControlPause' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
#
# objectclasses
#
@@ -164,7 +166,7 @@ objectClasses: ( 2.16.840.1.113730.3.2.110 NAME 'nsMappingTree' DESC 'Netscape d
objectClasses: ( 2.16.840.1.113730.3.2.104 NAME 'nsContainer' DESC 'Netscape defined objectclass' SUP top MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.108 NAME 'nsDS5Replica' DESC 'Netscape defined objectclass' SUP top MUST ( nsDS5ReplicaRoot $ nsDS5ReplicaId ) MAY (cn $ nsds5ReplicaCleanRUV $ nsds5ReplicaAbortCleanRUV $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( nsParentUniqueId $ nscpEntryDN ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsds5ReplicaCleanRUVNotified $ nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsds5ReplicaCleanRUVNotified $ nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime $ nsds5ReplicaFlowControlWindow $ nsds5ReplicaFlowControlPause ) X-ORIGIN 'Netscape Directory
Server' )
objectClasses: ( 2.16.840.1.113730.3.2.39 NAME 'nsslapdConfig' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.43 NAME 'nsSNMP' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSNMPEnabled ) MAY ( nsSNMPOrganization $ nsSNMPLocation $ nsSNMPContact $ nsSNMPDescription $ nsSNMPName $ nsSNMPMasterHost $ nsSNMPMasterPort ) X-ORIGIN 'Netscape Directory Server' )
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index a5761be..231daf5 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -168,6 +168,9 @@ extern const char *type_nsds5ReplicaSessionPauseTime;
extern const char *type_nsds5ReplicaEnabled;
extern const char *type_nsds5ReplicaStripAttrs;
extern const char *type_nsds5ReplicaCleanRUVnotified;
+extern const char *type_nsds5ReplicaFlowControlWindow;
+extern const char *type_nsds5ReplicaFlowControlPause;
+
/* Attribute names for windows replication agreements */
extern const char *type_nsds7WindowsReplicaArea;
@@ -312,6 +315,8 @@ int agmt_get_auto_initialize(const Repl_Agmt *ra);
long agmt_get_timeout(const Repl_Agmt *ra);
long agmt_get_busywaittime(const Repl_Agmt *ra);
long agmt_get_pausetime(const Repl_Agmt *ra);
+long agmt_get_flowcontrolwindow(const Repl_Agmt *ra);
+long agmt_get_flowcontrolpause(const Repl_Agmt *ra);
int agmt_start(Repl_Agmt *ra);
int windows_agmt_start(Repl_Agmt *ra);
int agmt_stop(Repl_Agmt *ra);
@@ -332,6 +337,8 @@ int agmt_replarea_matches(const Repl_Agmt *ra, const Slapi_DN *name);
int agmt_schedule_in_window_now(const Repl_Agmt *ra);
int agmt_set_schedule_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
int agmt_set_timeout_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
+int agmt_set_flowcontrolwindow_from_entry(Repl_Agmt *ra, const Slapi_Entry *e);
+int agmt_set_flowcontrolpause_from_entry(Repl_Agmt *ra, const Slapi_Entry *e);
int agmt_set_busywaittime_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
int agmt_set_pausetime_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
int agmt_set_credentials_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
@@ -463,6 +470,10 @@ void conn_lock(Repl_Connection *conn);
void conn_unlock(Repl_Connection *conn);
void conn_delete_internal_ext(Repl_Connection *conn);
const char* conn_get_bindmethod(Repl_Connection *conn);
+void conn_set_tot_update_cb(Repl_Connection *conn, void *cb_data);
+void conn_set_tot_update_cb_nolock(Repl_Connection *conn, void *cb_data);
+void conn_get_tot_update_cb(Repl_Connection *conn, void **cb_data);
+void conn_get_tot_update_cb_nolock(Repl_Connection *conn, void **cb_data);
/* In repl5_protocol.c */
typedef struct repl_protocol Repl_Protocol;
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
index 708966a..41a81ca 100644
--- a/ldap/servers/plugins/replication/repl5_agmt.c
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -87,6 +87,8 @@
#include "slapi-plugin.h"
#define DEFAULT_TIMEOUT 600 /* (seconds) default outbound LDAP connection */
+#define DEFAULT_FLOWCONTROL_WINDOW 1000 /* #entries sent without acknowledgment */
+#define DEFAULT_FLOWCONTROL_PAUSE 2000 /* msec of pause when #entries sent witout acknowledgment */
#define STATUS_LEN 1024
struct changecounter {
@@ -142,6 +144,12 @@ typedef struct repl5agmt {
char **attrs_to_strip; /* for fractional replication, if a "mod" is empty, strip out these attributes:
* modifiersname, modifytimestamp, internalModifiersname, internalModifyTimestamp, etc */
int agreement_type;
+ long flowControlWindow; /* This is the maximum number of entries
+ * sent without acknowledgment
+ */
+ long flowControlPause; /* When nb of not acknowledged entries overpass totalUpdateWindow
+ * This is the duration (in msec) that the RA will pause before sending the next entry
+ */
} repl5agmt;
/* Forward declarations */
@@ -332,6 +340,27 @@ agmt_new_from_entry(Slapi_Entry *e)
ra->timeout = slapi_value_get_long(sval);
}
}
+ /* flow control update window. */
+ ra->flowControlWindow = DEFAULT_FLOWCONTROL_WINDOW;
+ if (slapi_entry_attr_find(e, type_nsds5ReplicaFlowControlWindow, &sattr) == 0)
+ {
+ Slapi_Value *sval;
+ if (slapi_attr_first_value(sattr, &sval) == 0)
+ {
+ ra->flowControlWindow = slapi_value_get_long(sval);
+ }
+ }
+
+ /* flow control update pause. */
+ ra->flowControlPause = DEFAULT_FLOWCONTROL_PAUSE;
+ if (slapi_entry_attr_find(e, type_nsds5ReplicaFlowControlPause, &sattr) == 0)
+ {
+ Slapi_Value *sval;
+ if (slapi_attr_first_value(sattr, &sval) == 0)
+ {
+ ra->flowControlPause = slapi_value_get_long(sval);
+ }
+ }
/* DN of entry at root of replicated area */
tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaRoot);
@@ -963,6 +992,26 @@ agmt_get_pausetime(const Repl_Agmt *ra)
return return_value;
}
+long
+agmt_get_flowcontrolwindow(const Repl_Agmt *ra)
+{
+ long return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->flowControlWindow;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+long
+agmt_get_flowcontrolpause(const Repl_Agmt *ra)
+{
+ long return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->flowControlPause;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
/*
* Warning - reference to the long name of the agreement is returned.
* The long name of an agreement is the DN of the agreement entry,
@@ -1694,6 +1743,90 @@ agmt_set_timeout_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
return return_value;
}
+/*
+ * Set or reset the windows of entries sent without acknowledgment.
+ * The window is used during update to determine the number of
+ * entries will be send by the replica agreement without acknowledgment from the consumer
+ *
+ * Returns 0 if window set, or -1 if an error occurred.
+ */
+int
+agmt_set_flowcontrolwindow_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ Slapi_Attr *sattr = NULL;
+ int return_value = -1;
+
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress)
+ {
+ PR_Unlock(ra->lock);
+ return return_value;
+ }
+
+ slapi_entry_attr_find(e, type_nsds5ReplicaFlowControlWindow, &sattr);
+ if (NULL != sattr)
+ {
+ Slapi_Value *sval = NULL;
+ slapi_attr_first_value(sattr, &sval);
+ if (NULL != sval)
+ {
+ long tmpval = slapi_value_get_long(sval);
+ if (tmpval >= 0) {
+ ra->flowControlWindow = tmpval;
+ return_value = 0; /* success! */
+ }
+ }
+ }
+ PR_Unlock(ra->lock);
+ if (return_value == 0)
+ {
+ prot_notify_agmt_changed(ra->protocol, ra->long_name);
+ }
+ return return_value;
+}
+
+/*
+ * Set or reset the pause duration when #entries sent without acknowledgment overpass flow control window
+ *
+ * Returns 0 if pause set, or -1 if an error occurred.
+ */
+int
+agmt_set_flowcontrolpause_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ Slapi_Attr *sattr = NULL;
+ int return_value = -1;
+
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress)
+ {
+ PR_Unlock(ra->lock);
+ return return_value;
+ }
+
+ slapi_entry_attr_find(e, type_nsds5ReplicaFlowControlPause, &sattr);
+ if (NULL != sattr)
+ {
+ Slapi_Value *sval = NULL;
+ slapi_attr_first_value(sattr, &sval);
+ if (NULL != sval)
+ {
+ long tmpval = slapi_value_get_long(sval);
+ if (tmpval >= 0) {
+ ra->flowControlPause = tmpval;
+ return_value = 0; /* success! */
+ }
+ }
+ }
+ PR_Unlock(ra->lock);
+ if (return_value == 0)
+ {
+ prot_notify_agmt_changed(ra->protocol, ra->long_name);
+ }
+ return return_value;
+}
+
int
agmt_set_timeout(Repl_Agmt *ra, long timeout)
{
@@ -1708,6 +1841,33 @@ agmt_set_timeout(Repl_Agmt *ra, long timeout)
return 0;
}
+int
+agmt_set_flowcontrolwindow(Repl_Agmt *ra, long window)
+{
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress){
+ PR_Unlock(ra->lock);
+ return -1;
+ }
+ ra->flowControlWindow = window;
+ PR_Unlock(ra->lock);
+
+ return 0;
+}
+int
+agmt_set_flowcontrolpause(Repl_Agmt *ra, long pause)
+{
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress){
+ PR_Unlock(ra->lock);
+ return -1;
+ }
+ ra->flowControlPause = pause;
+ PR_Unlock(ra->lock);
+
+ return 0;
+}
+
/*
* Set or reset the busywaittime
*
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
index d37704d..caa41af 100644
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
@@ -345,6 +345,32 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
}
}
else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ type_nsds5ReplicaFlowControlWindow))
+ {
+ /* New replica timeout */
+ if (agmt_set_flowcontrolwindow_from_entry(agmt, e) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "failed to update the flow control window for agreement %s\n",
+ agmt_get_long_name(agmt));
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ type_nsds5ReplicaFlowControlPause))
+ {
+ /* New replica timeout */
+ if (agmt_set_flowcontrolpause_from_entry(agmt, e) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "failed to update the flow control pause for agreement %s\n",
+ agmt_get_long_name(agmt));
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
type_nsds5ReplicaBusyWaitTime))
{
/* New replica busywaittime */
diff --git a/ldap/servers/plugins/replication/repl5_connection.c b/ldap/servers/plugins/replication/repl5_connection.c
index 5efd0e6..e080a3f 100644
--- a/ldap/servers/plugins/replication/repl5_connection.c
+++ b/ldap/servers/plugins/replication/repl5_connection.c
@@ -52,6 +52,7 @@ replica locked. Seems like right thing to do.
*/
#include "repl5.h"
+#include "repl5_prot_private.h"
#if defined(USE_OPENLDAP)
#include "ldap.h"
#else
@@ -90,6 +91,7 @@ typedef struct repl_connection
struct timeval timeout;
int flag_agmt_changed;
char *plain;
+ void *tot_init_callback; /* Used during total update to do flow control */
} repl_connection;
/* #define DEFAULT_LINGER_TIME (5 * 60) */ /* 5 minutes */
@@ -277,6 +279,32 @@ conn_get_error(Repl_Connection *conn, int *operation, int *error)
PR_Unlock(conn->lock);
}
+void
+conn_set_tot_update_cb_nolock(Repl_Connection *conn, void *cb_data)
+{
+ conn->tot_init_callback = (void *) cb_data;
+}
+void
+conn_set_tot_update_cb(Repl_Connection *conn, void *cb_data)
+{
+ PR_Lock(conn->lock);
+ conn_set_tot_update_cb_nolock(conn, cb_data);
+ PR_Unlock(conn->lock);
+}
+
+void
+conn_get_tot_update_cb_nolock(Repl_Connection *conn, void **cb_data)
+{
+ *cb_data = (void *) conn->tot_init_callback;
+}
+void
+conn_get_tot_update_cb(Repl_Connection *conn, void **cb_data)
+{
+ PR_Lock(conn->lock);
+ conn_get_tot_update_cb_nolock(conn, cb_data);
+ PR_Unlock(conn->lock);
+}
+
/*
* Return the last operation type processed by the connection
* object, and the LDAP error encountered.
@@ -629,6 +657,133 @@ see_if_write_available(Repl_Connection *conn, PRIntervalTime timeout)
}
#endif /* ! USE_OPENLDAP */
+/*
+ * During a total update, this function checks how much entries
+ * have been sent to the consumer without having received their acknowledgment.
+ * Basically it checks how late is the consumer.
+ *
+ * If the consumer is too late, it pause the RA.sender (releasing the lock) to
+ * let the consumer to catch up and RA.reader to receive the acknowledgments.
+ *
+ * Caller must hold conn->lock
+ */
+static void
+check_flow_control_tot_init(Repl_Connection *conn, int optype, const char *extop_oid, int sent_msgid)
+{
+ int rcv_msgid;
+ int once;
+
+ if ((sent_msgid != 0) && (optype == CONN_EXTENDED_OPERATION) && (strcmp(extop_oid, REPL_NSDS50_REPLICATION_ENTRY_REQUEST_OID) == 0)) {
+ /* We are sending entries part of the total update of a consumer
+ * Wait a bit if the consumer needs to catchup from the current sent entries
+ */
+ rcv_msgid = repl5_tot_last_rcv_msgid(conn);
+ if (rcv_msgid == -1) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: check_flow_control_tot_init no callback data [ msgid sent: %d]\n",
+ agmt_get_long_name(conn->agmt),
+ sent_msgid);
+ } else if (sent_msgid < rcv_msgid) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: check_flow_control_tot_init invalid message ids [ msgid sent: %d, rcv: %d]\n",
+ agmt_get_long_name(conn->agmt),
+ sent_msgid,
+ rcv_msgid);
+ } else if ((sent_msgid - rcv_msgid) > agmt_get_flowcontrolwindow(conn->agmt)) {
+ int totalUpdatePause;
+
+ totalUpdatePause = agmt_get_flowcontrolpause(conn->agmt);
+ if (totalUpdatePause) {
+ /* The consumer is late. Last sent entry compare to last acknowledged entry
+ * overpass the allowed limit (flowcontrolwindow)
+ * Give some time to the consumer to catch up
+ */
+ once = repl5_tot_flowcontrol_detection(conn, 1);
+ PR_Unlock(conn->lock);
+ if (once == 1) {
+ /* This is the first time we hit total update flow control.
+ * Log it at least once to inform administrator there is
+ * a potential configuration issue here
+ */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Total update flow control gives time (%d msec) to the consumer before sending more entries [ msgid sent: %d, rcv: %d])\n"
+ "If total update fails you can try to increase %s and/or decrease %s in the replica agreement configuration\n",
+ agmt_get_long_name(conn->agmt),
+ totalUpdatePause,
+ sent_msgid,
+ rcv_msgid,
+ type_nsds5ReplicaFlowControlPause,
+ type_nsds5ReplicaFlowControlWindow);
+ }
+ DS_Sleep(PR_MillisecondsToInterval(totalUpdatePause));
+ PR_Lock(conn->lock);
+ }
+ }
+ }
+
+}
+/*
+ * Test if the connection is available to do a write.
+ * This function is doing a periodic polling of the connection.
+ * If the polling times out:
+ * - it releases the connection lock (to let other thread ,i.e.
+ * replication result thread, the opportunity to use the connection)
+ * - Sleeps for a short period (100ms)
+ * - acquires the connection lock
+ *
+ * It loops until
+ * - it is available
+ * - exceeds RA complete timeout
+ * - server is shutdown
+ * - connection is disconnected (Disable, stop, delete the RA
+ * 'terminate' the replication protocol and disconnect the connection)
+ *
+ * Return:
+ * - CONN_OPERATION_SUCCESS if the connection is available
+ * - CONN_TIMEOUT if the overall polling/sleeping delay exceeds RA timeout
+ * - CONN_NOT_CONNECTED if the replication connection state is disconnected
+ * - other ConnResult
+ *
+ * Caller must hold conn->Lock. At the exit, conn->lock is held
+ */
+static ConnResult
+conn_is_available(Repl_Connection *conn)
+{
+ time_t poll_timeout_sec = 1; /* Polling for 1sec */
+ time_t yield_delay_msec = 100; /* Delay to wait */
+ time_t start_time = time( NULL );
+ time_t time_now;
+ ConnResult return_value = CONN_OPERATION_SUCCESS;
+
+ while (!slapi_is_shutting_down() && (conn->state != STATE_DISCONNECTED)) {
+ return_value = see_if_write_available(conn, PR_SecondsToInterval(poll_timeout_sec));
+ if (return_value == CONN_TIMEOUT) {
+ /* in case of timeout we return CONN_TIMEOUT only
+ * if the RA.timeout is exceeded
+ */
+ time_now = time(NULL);
+ if (conn->timeout.tv_sec <= (time_now - start_time)) {
+ break;
+ } else {
+ /* Else give connection to others threads */
+ PR_Unlock(conn->lock);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: perform_operation transient timeout. retry)\n",
+ agmt_get_long_name(conn->agmt));
+ DS_Sleep(PR_MillisecondsToInterval(yield_delay_msec));
+ PR_Lock(conn->lock);
+ }
+ } else {
+ break;
+ }
+ }
+ if (conn->state == STATE_DISCONNECTED) {
+ return_value = CONN_NOT_CONNECTED;
+ }
+ return return_value;
+}
+
+
/*
* Common code to send an LDAPv3 operation and collect the result.
* Return values:
@@ -670,10 +825,13 @@ perform_operation(Repl_Connection *conn, int optype, const char *dn,
Slapi_Eq_Context eqctx = repl5_start_debug_timeout(&setlevel);
- return_value = see_if_write_available(
- conn, PR_SecondsToInterval(conn->timeout.tv_sec));
+ return_value = conn_is_available(conn);
if (return_value != CONN_OPERATION_SUCCESS) {
PR_Unlock(conn->lock);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: perform_operation connection is not available (%d)\n",
+ agmt_get_long_name(conn->agmt),
+ return_value);
return return_value;
}
conn->last_operation = optype;
@@ -745,6 +903,9 @@ perform_operation(Repl_Connection *conn, int optype, const char *dn,
*/
return_value = CONN_NOT_CONNECTED;
}
+
+ check_flow_control_tot_init(conn, optype, extop_oid, msgid);
+
PR_Unlock(conn->lock); /* release the lock */
if (message_id)
{
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
index ae26380..f5516a3 100644
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
@@ -108,6 +108,7 @@ typedef struct result_data
int stop_result_thread; /* Flag used to tell the result thread to exit */
int last_message_id_sent;
int last_message_id_received;
+ int flowcontrol_detection;
int result; /* The UPDATE_TRANSIENT_ERROR etc */
} result_data;
@@ -460,6 +461,23 @@ repl5_inc_destroy_async_result_thread(result_data *rd)
return retval;
}
+/* The interest of this routine is to give time to the consumer
+ * to apply the sent updates and return the acks.
+ * So the caller should not hold the replication connection lock
+ * to let the RA.reader receives the acks.
+ */
+static void
+repl5_inc_flow_control_results(Repl_Agmt *agmt, result_data *rd)
+{
+ PR_Lock(rd->lock);
+ if ((rd->last_message_id_received <= rd->last_message_id_sent) &&
+ ((rd->last_message_id_sent - rd->last_message_id_received) >= agmt_get_flowcontrolwindow(agmt))) {
+ rd->flowcontrol_detection++;
+ DS_Sleep(PR_MillisecondsToInterval(agmt_get_flowcontrolpause(agmt)));
+ }
+ PR_Unlock(rd->lock);
+}
+
static void
repl5_inc_waitfor_async_results(result_data *rd)
{
@@ -1669,7 +1687,7 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
{
int finished = 0;
ConnResult replay_crc;
- char csn_str[CSN_STRSIZE];
+ char csn_str[CSN_STRSIZE];
/* Start the results reading thread */
rd = repl5_inc_rd_new(prp);
@@ -1804,6 +1822,7 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
sop->replica_id = replica_id;
PL_strncpyz(sop->uniqueid, uniqueid, sizeof(sop->uniqueid));
repl5_int_push_operation(rd,sop);
+ repl5_inc_flow_control_results(prp->agmt, rd);
} else {
slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
"%s: Skipping update operation with no message_id (uniqueid %s, CSN %s):\n",
@@ -1892,6 +1911,17 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
}
*num_changes_sent = rd->num_changes_sent;
}
+ PR_Lock(rd->lock);
+ if (rd->flowcontrol_detection) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Incremental update flow control triggered %d times\n"
+ "You may increase %s and/or decrease %s in the replica agreement configuration\n",
+ agmt_get_long_name(prp->agmt),
+ rd->flowcontrol_detection,
+ type_nsds5ReplicaFlowControlPause,
+ type_nsds5ReplicaFlowControlWindow);
+ }
+ PR_Unlock(rd->lock);
repl5_inc_rd_destroy(&rd);
cl5_operation_parameters_done ( entry.op );
diff --git a/ldap/servers/plugins/replication/repl5_prot_private.h b/ldap/servers/plugins/replication/repl5_prot_private.h
index 10aa02b..7ca31ca 100644
--- a/ldap/servers/plugins/replication/repl5_prot_private.h
+++ b/ldap/servers/plugins/replication/repl5_prot_private.h
@@ -79,6 +79,8 @@ typedef struct private_repl_protocol
extern Private_Repl_Protocol *Repl_5_Inc_Protocol_new();
extern Private_Repl_Protocol *Repl_5_Tot_Protocol_new();
+extern int repl5_tot_last_rcv_msgid(Repl_Connection *conn);
+extern int repl5_tot_flowcontrol_detection(Repl_Connection *conn, int increment);
extern Private_Repl_Protocol *Windows_Inc_Protocol_new();
extern Private_Repl_Protocol *Windows_Tot_Protocol_new();
diff --git a/ldap/servers/plugins/replication/repl5_tot_protocol.c b/ldap/servers/plugins/replication/repl5_tot_protocol.c
index 9829984..e514dc6 100644
--- a/ldap/servers/plugins/replication/repl5_tot_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_tot_protocol.c
@@ -82,6 +82,7 @@ typedef struct callback_data
int stop_result_thread; /* Flag used to tell the result thread to exit */
int last_message_id_sent;
int last_message_id_received;
+ int flowcontrol_detection;
} callback_data;
/*
@@ -416,12 +417,17 @@ repl5_tot_run(Private_Repl_Protocol *prp)
LDAP_SCOPE_SUBTREE, "(|(objectclass=ldapsubentry)(objectclass=nstombstone)(nsuniqueid=*))", NULL, 0, ctrls, NULL,
repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
- cb_data.prp = prp;
- cb_data.rc = 0;
+ cb_data.prp = prp;
+ cb_data.rc = 0;
cb_data.num_entries = 0UL;
cb_data.sleep_on_busy = 0UL;
cb_data.last_busy = current_time ();
+ cb_data.flowcontrol_detection = 0;
cb_data.lock = PR_NewLock();
+ /* This allows during perform_operation to check the callback data
+ * especially to do flow contol on delta send msgid / recv msgid
+ */
+ conn_set_tot_update_cb(prp->conn, (void *) &cb_data);
/* Before we get started on sending entries to the replica, we need to
* setup things for async propagation:
@@ -492,6 +498,17 @@ repl5_tot_run(Private_Repl_Protocol *prp)
done:
slapi_sdn_free(&area_sdn);
slapi_ch_free_string(&hostname);
+ if (cb_data.flowcontrol_detection > 1)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Total update flow control triggered %d times\n"
+ "You may increase %s and/or decrease %s in the replica agreement configuration\n",
+ agmt_get_long_name(prp->agmt),
+ cb_data.flowcontrol_detection,
+ type_nsds5ReplicaFlowControlPause,
+ type_nsds5ReplicaFlowControlWindow);
+ }
+ conn_set_tot_update_cb(prp->conn, NULL);
if (cb_data.lock)
{
PR_DestroyLock(cb_data.lock);
@@ -619,6 +636,37 @@ void get_result (int rc, void *cb_data)
((callback_data*)cb_data)->rc = rc;
}
+/* Call must hold the connection lock */
+int
+repl5_tot_last_rcv_msgid(Repl_Connection *conn)
+{
+ struct callback_data *cb_data;
+
+ conn_get_tot_update_cb_nolock(conn, (void **) &cb_data);
+ if (cb_data == NULL) {
+ return -1;
+ } else {
+ return cb_data->last_message_id_received;
+ }
+}
+
+/* Increase the flowcontrol counter
+ * Call must hold the connection lock
+ */
+int
+repl5_tot_flowcontrol_detection(Repl_Connection *conn, int increment)
+{
+ struct callback_data *cb_data;
+
+ conn_get_tot_update_cb_nolock(conn, (void **) &cb_data);
+ if (cb_data == NULL) {
+ return -1;
+ } else {
+ cb_data->flowcontrol_detection += increment;
+ return cb_data->flowcontrol_detection;
+ }
+}
+
static
int send_entry (Slapi_Entry *e, void *cb_data)
{
diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c
index f31a476..bfcff03 100644
--- a/ldap/servers/plugins/replication/repl_globals.c
+++ b/ldap/servers/plugins/replication/repl_globals.c
@@ -131,6 +131,9 @@ const char *type_nsds5ReplicaSessionPauseTime = "nsds5ReplicaSessionPauseTime";
const char *type_nsds5ReplicaEnabled = "nsds5ReplicaEnabled";
const char *type_nsds5ReplicaStripAttrs = "nsds5ReplicaStripAttrs";
const char *type_nsds5ReplicaCleanRUVnotified = "nsds5ReplicaCleanRUVNotified";
+const char* type_nsds5ReplicaFlowControlWindow = "nsds5ReplicaFlowControlWindow";
+const char* type_nsds5ReplicaFlowControlPause = "nsds5ReplicaFlowControlPause";
+
/* windows sync specific attributes */
const char *type_nsds7WindowsReplicaArea = "nsds7WindowsReplicaSubtree";
commit bb565bd8e664a22aed754af092121d293d2fee5d
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Thu Apr 2 11:49:46 2015 -0700
Ticket #561 - disable writing unhashed#user#password to changelog
Backported:
. commit c4bd52e2211c043087765f74df6cf6cd41b8f234
Ticket #561 - disable writing unhashed#user#password to changelog
. commit da3be3fbf497775f608d1289f72cfe427850f950
Fix optimization issue introduced with fix for ticket #561,
. commit 1d4f3ca2e931e6d930056aeb683256965503c5e1
Fixing a compiler warning introduced by Ticket #561
. commit 84b8bfd7d18a0613920dce36f1d3775d75e45a3e
Fix for CVE-2014-8112
Description:
Introducing a config parameter nsslapd-unhashed-pw-switch to cn=config.
The parameter takes 3 values:
on - unhashed password is stored in the entry extension
and logged in the changelog.
nolog - unhashed password is stored in the entry extension
but not logged in the changelog.
off - unhashed password is not stored in the entry extension.
https://fedorahosted.org/389/ticket/561
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index ae522a3..0618d9b 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -322,7 +322,7 @@ static int _cl5Str2OperationType (const char *str);
static void _cl5WriteString (const char *str, char **buff);
static void _cl5ReadString (char **str, char **buff);
static void _cl5WriteMods (LDAPMod **mods, char **buff);
-static void _cl5WriteMod (LDAPMod *mod, char **buff);
+static int _cl5WriteMod (LDAPMod *mod, char **buff);
static int _cl5ReadMods (LDAPMod ***mods, char **buff);
static int _cl5ReadMod (Slapi_Mod *mod, char **buff);
static int _cl5GetModsSize (LDAPMod **mods);
@@ -2474,7 +2474,7 @@ static void _cl5WriteMods (LDAPMod **mods, char **buff)
{
PRInt32 i;
char *mod_start;
- PRInt32 count;
+ PRInt32 count = 0;
if (mods == NULL)
return;
@@ -2483,30 +2483,49 @@ static void _cl5WriteMods (LDAPMod **mods, char **buff)
mod_start = (*buff) + sizeof (count);
/* write mods*/
- for (i=0; mods[i]; i++)
- {
- _cl5WriteMod (mods[i], &mod_start);
+ for (i = 0; mods[i]; i++) {
+ if (0 <= _cl5WriteMod (mods[i], &mod_start)) {
+ count++;
+ }
}
- count = PR_htonl(i);
+ count = PR_htonl(count);
memcpy (*buff, &count, sizeof (count));
(*buff) = mod_start;
}
-static void _cl5WriteMod (LDAPMod *mod, char **buff)
+/*
+ * return values:
+ * positive: no need to encrypt && succeeded to write a mod
+ * 0: succeeded to encrypt && write a mod
+ * netative: failed to encrypt && no write to the changelog
+ */
+static int
+_cl5WriteMod (LDAPMod *mod, char **buff)
{
+ char *orig_pos;
char *pos;
PRInt32 count;
struct berval *bv;
struct berval *encbv;
struct berval *bv_to_use;
Slapi_Mod smod;
- int rc = 0;
+ int rc = -1;
+
+ if (NULL == mod) {
+ return rc;
+ }
+ if (SLAPD_UNHASHED_PW_NOLOG == slapi_config_get_unhashed_pw_switch()) {
+ if (0 == strcasecmp(mod->mod_type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD)) {
+ /* If nsslapd-unhashed-pw-switch == nolog, skip writing it to cl. */
+ return rc;
+ }
+ }
slapi_mod_init_byref(&smod, mod);
- pos = *buff;
+ orig_pos = pos = *buff;
/* write mod op */
*pos = (PRUint8)slapi_mod_get_operation (&smod);
pos ++;
@@ -2516,7 +2535,7 @@ static void _cl5WriteMod (LDAPMod *mod, char **buff)
/* write value count */
count = PR_htonl(slapi_mod_get_num_values(&smod));
memcpy (pos, &count, sizeof (count));
- pos += sizeof (PRInt32);
+ pos += sizeof (PRInt32);
bv = slapi_mod_get_first_value (&smod);
while (bv)
@@ -2536,6 +2555,8 @@ static void _cl5WriteMod (LDAPMod *mod, char **buff)
"_cl5WriteMod: encrypting \"%s: %s\" failed\n",
slapi_mod_get_type(&smod), bv->bv_val);
bv_to_use = NULL;
+ rc = -1;
+ break;
}
if (bv_to_use) {
_cl5WriteBerval (bv_to_use, &pos);
@@ -2544,9 +2565,14 @@ static void _cl5WriteMod (LDAPMod *mod, char **buff)
bv = slapi_mod_get_next_value (&smod);
}
- (*buff) = pos;
+ if (rc < 0) {
+ (*buff) = orig_pos;
+ } else {
+ (*buff) = pos;
+ }
slapi_mod_done (&smod);
+ return rc;
}
/* mods format:
diff --git a/ldap/servers/plugins/retrocl/retrocl_po.c b/ldap/servers/plugins/retrocl/retrocl_po.c
index c3d1c41..3fdf887 100644
--- a/ldap/servers/plugins/retrocl/retrocl_po.c
+++ b/ldap/servers/plugins/retrocl/retrocl_po.c
@@ -101,6 +101,12 @@ static lenstr *make_changes_string(LDAPMod **ldm, const char **includeattrs)
continue;
}
}
+ if (SLAPD_UNHASHED_PW_NOLOG == slapi_config_get_unhashed_pw_switch()) {
+ if (0 == strcasecmp(ldm[ i ]->mod_type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD)) {
+ /* If nsslapd-unhashed-pw-switch == nolog, skip writing it to cl. */
+ continue;
+ }
+ }
switch ( ldm[ i ]->mod_op & ~LDAP_MOD_BVALUES ) {
case LDAP_MOD_ADD:
addlenstr( l, "add: " );
diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c
index f52f766..37060df 100644
--- a/ldap/servers/slapd/add.c
+++ b/ldap/servers/slapd/add.c
@@ -447,7 +447,6 @@ static void op_shared_add (Slapi_PBlock *pb)
int err;
int internal_op, repl_op, legacy_op, lastmod;
char *pwdtype = NULL;
- Slapi_Value **unhashed_password_vals = NULL;
Slapi_Attr *attr = NULL;
Slapi_Entry *referral;
char errorbuf[BUFSIZ];
@@ -545,6 +544,7 @@ static void op_shared_add (Slapi_PBlock *pb)
{
Slapi_Value **present_values;
present_values= attr_get_present_values(attr);
+ Slapi_Value **unhashed_password_vals = NULL;
/* Set the backend in the pblock. The slapi_access_allowed function
* needs this set to work properly. */
@@ -576,11 +576,13 @@ static void op_shared_add (Slapi_PBlock *pb)
add_password_attrs(pb, operation, e);
slapi_entry_attr_replace_sv(e, SLAPI_USERPWD_ATTR, vals);
valuearray_free(&vals);
-
- /* Add the unhashed password pseudo-attribute to the entry */
- pwdtype = slapi_attr_syntax_normalize(PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
- slapi_entry_add_values_sv(e, pwdtype, unhashed_password_vals);
+ if (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch()) {
+ /* Add the unhashed password pseudo-attribute to the entry */
+ pwdtype = slapi_attr_syntax_normalize(PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
+ slapi_entry_add_values_sv(e, pwdtype, unhashed_password_vals);
+ }
}
+ valuearray_free(&unhashed_password_vals);
}
/* look for multiple backend local credentials or replication local credentials */
@@ -751,7 +753,6 @@ done:
slapi_ch_free((void **)&operation->o_params.p.p_add.parentuniqueid);
slapi_entry_free(e);
slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL);
- valuearray_free(&unhashed_password_vals);
slapi_ch_free((void**)&pwdtype);
slapi_ch_free_string(&proxydn);
slapi_ch_free_string(&proxystr);
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index 825dcee..dbb0fa8 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -121,7 +121,8 @@ typedef enum {
CONFIG_SPECIAL_ERRORLOGLEVEL, /* requires & with LDAP_DEBUG_ANY */
CONFIG_STRING_OR_EMPTY, /* use an empty string */
CONFIG_SPECIAL_ANON_ACCESS_SWITCH, /* maps strings to an enumeration */
- CONFIG_SPECIAL_VALIDATE_CERT_SWITCH /* maps strings to an enumeration */
+ CONFIG_SPECIAL_VALIDATE_CERT_SWITCH, /* maps strings to an enumeration */
+ CONFIG_SPECIAL_UNHASHED_PW_SWITCH /* unhashed pw: on/off/nolog */
} ConfigVarType;
static int config_set_onoff( const char *attrname, char *value,
@@ -269,6 +270,7 @@ int init_mempool_switch;
#define DEFAULT_SSLCLIENTAPTH "off"
#define DEFAULT_ALLOW_ANON_ACCESS "on"
#define DEFAULT_VALIDATE_CERT "warn"
+#define DEFAULT_UNHASHED_PW_SWITCH "on"
static int
isInt(ConfigVarType type)
@@ -1041,6 +1043,11 @@ static struct config_get_and_set {
NULL, 0,
(void**)&global_slapdFrontendConfig.ndn_cache_max_size,
CONFIG_INT, (ConfigGetFunc)config_get_ndn_cache_size},
+ {CONFIG_UNHASHED_PW_SWITCH_ATTRIBUTE, config_set_unhashed_pw_switch,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.unhashed_pw_switch,
+ CONFIG_SPECIAL_UNHASHED_PW_SWITCH,
+ (ConfigGetFunc)config_get_unhashed_pw_switch}
#ifdef MEMPOOL_EXPERIMENTAL
,{CONFIG_MEMPOOL_SWITCH_ATTRIBUTE, config_set_mempool_switch,
NULL, 0,
@@ -1459,6 +1466,7 @@ FrontendConfig_init () {
cfg->disk_grace_period = 60; /* 1 hour */
init_disk_logging_critical = cfg->disk_logging_critical = LDAP_OFF;
cfg->sasl_max_bufsize = SLAPD_DEFAULT_SASL_MAXBUFSIZE;
+ cfg->unhashed_pw_switch = SLAPD_UNHASHED_PW_ON;
init_listen_backlog_size = cfg->listen_backlog_size = DAEMON_LISTEN_SIZE;
init_ignore_time_skew = cfg->ignore_time_skew = LDAP_OFF;
@@ -6552,7 +6560,6 @@ config_get_allowed_to_delete_attrs(void)
return retVal;
}
-
int
config_set_allowed_to_delete_attrs( const char *attrname, char *value,
char *errorbuf, int apply )
@@ -6711,6 +6718,62 @@ config_initvalue_to_onoff(struct config_get_and_set *cgas, char *initvalbuf, siz
return retval;
}
+int
+config_set_unhashed_pw_switch(const char *attrname, char *value,
+ char *errorbuf, int apply)
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if (config_value_is_null(attrname, value, errorbuf, 0)) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ((strcasecmp(value, "on") != 0) && (strcasecmp(value, "off") != 0) &&
+ (strcasecmp(value, "nolog") != 0)) {
+ PR_snprintf(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid value \"%s\". Valid values are \"on\", "
+ "\"off\", or \"nolog\".", attrname, value);
+ retVal = LDAP_OPERATIONS_ERROR;
+ }
+
+ if (!apply) {
+ /* we can return now if we aren't applying the changes */
+ return retVal;
+ }
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ if (strcasecmp(value, "on") == 0 ) {
+ slapdFrontendConfig->unhashed_pw_switch = SLAPD_UNHASHED_PW_ON;
+ } else if (strcasecmp(value, "off") == 0 ) {
+ slapdFrontendConfig->unhashed_pw_switch = SLAPD_UNHASHED_PW_OFF;
+ } else if (strcasecmp(value, "nolog") == 0) {
+ slapdFrontendConfig->unhashed_pw_switch = SLAPD_UNHASHED_PW_NOLOG;
+ }
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ return retVal;
+}
+
+int
+slapi_config_get_unhashed_pw_switch()
+{
+ return config_get_unhashed_pw_switch();
+}
+
+int
+config_get_unhashed_pw_switch()
+{
+ int retVal = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->unhashed_pw_switch;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
/*
* This function is intended to be used from the dse code modify callback. It
* is "optimized" for that case because it takes a berval** of values, which is
@@ -6931,6 +6994,23 @@ config_set_value(
slapi_entry_attr_set_charptr(e, cgas->attr_name, sval);
break;
+ case CONFIG_SPECIAL_UNHASHED_PW_SWITCH:
+ if (!value) {
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "on");
+ break;
+ }
+
+ if (*((int *)value) == SLAPD_UNHASHED_PW_OFF) {
+ sval = "off";
+ } else if (*((int *)value) == SLAPD_UNHASHED_PW_NOLOG) {
+ sval = "nolog";
+ } else {
+ sval = "on";
+ }
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, sval);
+
+ break;
+
case CONFIG_SPECIAL_VALIDATE_CERT_SWITCH:
if (!value) {
slapi_entry_attr_set_charptr(e, cgas->attr_name, "off");
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
index 90c9f8c..c67ef14 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -894,13 +894,15 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
/*
* Finally, delete the unhashed userpassword
*/
- bval.bv_val = password;
- bval.bv_len = strlen(password);
- bv[0] = &bval;
- bv[1] = NULL;
- valuearray_init_bervalarray(bv, &va);
- slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
- valuearray_free(&va);
+ if (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch()) {
+ bval.bv_val = password;
+ bval.bv_len = strlen(password);
+ bv[0] = &bval;
+ bv[1] = NULL;
+ valuearray_init_bervalarray(bv, &va);
+ slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+ valuearray_free(&va);
+ }
} else {
/*
* Password is encoded, try and find a matching unhashed_password to delete
@@ -924,28 +926,31 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
bval.bv_len = strlen(unhashed_pwd);
bv[0] = &bval;
bv[1] = NULL;
-
/*
* Compare the clear text unhashed password, to the encoded password
* provided by the client.
*/
- unhashed_pwsp = pw_val2scheme( unhashed_pwd, NULL, 1 );
+ unhashed_pwsp = pw_val2scheme( (char *)unhashed_pwd, NULL, 1 );
if(strcmp(unhashed_pwsp->pws_name, "CLEAR") == 0){
- if((*(pwsp->pws_cmp))(unhashed_pwd , valpwd) == 0 ){
+ if((*(pwsp->pws_cmp))((char *)unhashed_pwd , valpwd) == 0 ){
/* match, add the delete mod for this particular unhashed userpassword */
- valuearray_init_bervalarray(bv, &va);
- slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
- valuearray_free(&va);
- free_pw_scheme( unhashed_pwsp );
+ if (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch()) {
+ valuearray_init_bervalarray(bv, &va);
+ slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+ valuearray_free(&va);
+ free_pw_scheme( unhashed_pwsp );
+ }
break;
}
} else {
/*
* We have a hashed unhashed_userpassword! We must delete it.
*/
- valuearray_init_bervalarray(bv, &va);
- slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
- valuearray_free(&va);
+ if (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch()) {
+ valuearray_init_bervalarray(bv, &va);
+ slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+ valuearray_free(&va);
+ }
}
free_pw_scheme( unhashed_pwsp );
}
@@ -958,13 +963,13 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
if (remove_unhashed_pw && !slapi_entry_attr_find(e, unhashed_pw_attr, &a)){
slapi_mods_add_mod_values(&smods, pw_mod->mod_op,unhashed_pw_attr, va);
}
- } else {
- /* add pseudo password attribute - only if it's value is clear text */
+ } else if (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch()) {
+ /* add pseudo password attribute */
valuearray_init_bervalarray_unhashed_only(pw_mod->mod_bvalues, &va);
- if(va){
+ if(va && va[0]){
slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
- valuearray_free(&va);
}
+ valuearray_free(&va);
}
/* Init new value array for hashed value */
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
index a7367a7..bef19d1 100644
--- a/ldap/servers/slapd/opshared.c
+++ b/ldap/servers/slapd/opshared.c
@@ -52,10 +52,7 @@
static void compute_limits (Slapi_PBlock *pb);
/* attributes that no clients are allowed to add or modify */
-/* PSEUDO_ATTR_UNHASHEDUSERPASSWORD used to be in protected_attrs_all.
- * Now it's moved to back-ldbm/id2entry.c to share it among repl masters.
- * (bz 182507)*/
-static char *protected_attrs_all [] = { NULL };
+static char *protected_attrs_all [] = { PSEUDO_ATTR_UNHASHEDUSERPASSWORD, NULL };
static char *pwpolicy_lock_attrs_all [] = { "passwordRetryCount",
"retryCountResetTime",
"accountUnlockTime",
@@ -70,30 +67,26 @@ int op_shared_is_allowed_attr (const char *attr_name, int replicated_op)
int i;
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
- /* check list of attributes that no client is allowed to specify */
- for (i = 0; protected_attrs_all[i]; i ++)
- {
- if (strcasecmp (attr_name, protected_attrs_all[i]) == 0)
- {
- /* this attribute is not allowed */
- return 0;
- }
- }
-
/* ONREPL - should allow backends to plugin here to specify
attributes that are not allowed */
- if (!replicated_op)
- {
- /*
- * check to see if attribute is marked as one clients can't modify
- */
+ if (!replicated_op) {
struct asyntaxinfo *asi;
int no_user_mod = 0;
+ /* check list of attributes that no client is allowed to specify */
+ for (i = 0; protected_attrs_all[i]; i ++) {
+ if (strcasecmp (attr_name, protected_attrs_all[i]) == 0) {
+ /* this attribute is not allowed */
+ return 0;
+ }
+ }
+ /*
+ * check to see if attribute is marked as one clients can't modify
+ */
asi = attr_syntax_get_by_name( attr_name, 0 );
if ( NULL != asi &&
- 0 != ( asi->asi_flags & SLAPI_ATTR_FLAG_NOUSERMOD ))
+ 0 != ( asi->asi_flags & SLAPI_ATTR_FLAG_NOUSERMOD ))
{
/* this attribute is not allowed */
no_user_mod = 1;
@@ -187,7 +180,7 @@ modify_update_last_modified_attr(Slapi_PBlock *pb, Slapi_Mods *smods)
/* anonymous bind */
bv.bv_val = "";
bv.bv_len = strlen(bv.bv_val);
- } else {
+ } else {
bv.bv_val = binddn;
bv.bv_len = strlen(bv.bv_val);
}
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index da9c925..c497c14 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -403,6 +403,7 @@ int config_set_malloc_mmap_threshold(const char *attrname, char *value, char *er
int config_set_ndn_cache_enabled(const char *attrname, char *value, char *errorbuf, int apply);
int config_set_ndn_cache_max_size(const char *attrname, char *value, char *errorbuf, int apply);
+int config_set_unhashed_pw_switch(const char *attrname, char *value, char *errorbuf, int apply);
#if !defined(_WIN32) && !defined(AIX)
@@ -572,6 +573,7 @@ int config_get_malloc_mmap_threshold();
int config_get_ndn_cache_count();
size_t config_get_ndn_cache_size();
int config_get_ndn_cache_enabled();
+int config_get_unhashed_pw_switch();
PLHashNumber hashNocaseString(const void *key);
PRIntn hashNocaseCompare(const void *v1, const void *v2);
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 70e8a51..c298033 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -306,9 +306,6 @@ typedef void (*VFPV)(); /* takes undefined arguments */
#define ATTR_NETSCAPEMDSUFFIX "netscapemdsuffix"
-/* Used to make unhashed passwords available to plugins. */
-#define PSEUDO_ATTR_UNHASHEDUSERPASSWORD "unhashed#user#password"
-
#define REFERRAL_REMOVE_CMD "remove"
/* Filenames for DSE storage */
@@ -339,6 +336,8 @@ typedef void (*VFPV)(); /* takes undefined arguments */
#define SLAPD_VALIDATE_CERT_ON 1
#define SLAPD_VALIDATE_CERT_WARN 2
+typedef int slapi_onoff_t;
+
struct subfilt {
char *sf_type;
char *sf_initial;
@@ -1891,6 +1890,7 @@ typedef struct _slapdEntryPoints {
#define CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-errorlog-logging-enabled"
#define CONFIG_AUDITLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-auditlog-logging-enabled"
#define CONFIG_AUDITLOG_LOGGING_HIDE_UNHASHED_PW "nsslapd-auditlog-logging-hide-unhashed-pw"
+#define CONFIG_UNHASHED_PW_SWITCH_ATTRIBUTE "nsslapd-unhashed-pw-switch"
#define CONFIG_ROOTDN_ATTRIBUTE "nsslapd-rootdn"
#define CONFIG_ROOTPW_ATTRIBUTE "nsslapd-rootpw"
#define CONFIG_ROOTPWSTORAGESCHEME_ATTRIBUTE "nsslapd-rootpwstoragescheme"
@@ -2277,7 +2277,7 @@ typedef struct _slapdFrontendConfig {
PRInt64 disk_threshold;
int disk_grace_period;
int disk_logging_critical;
-
+ slapi_onoff_t unhashed_pw_switch; /* switch to on/off/nolog unhashed pw */
int ignore_time_skew;
#if defined(LINUX)
int malloc_mxfast; /* mallopt M_MXFAST */
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 24d43e8..b170271 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -7061,6 +7061,14 @@ char **slapi_str2charray_ext( char *str, char *brkstr, int allow_dups );
#endif
#endif
+/* Used to make unhashed passwords available to plugins. */
+#define PSEUDO_ATTR_UNHASHEDUSERPASSWORD "unhashed#user#password"
+
+/* Unhashed password */
+#define SLAPD_UNHASHED_PW_OFF 0
+#define SLAPD_UNHASHED_PW_ON 1
+#define SLAPD_UNHASHED_PW_NOLOG 2
+
/**
* Set given "type: value" to the plugin default config entry
* (cn=plugin default config,cn=config) unless the same "type: value" pair
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index 18f0e94..9a4e339 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -816,6 +816,7 @@ int pw_rever_decode(char *cipher, char **plain, const char * attr_name);
/* config routines */
int slapi_config_get_readonly();
+int slapi_config_get_unhashed_pw_switch();
/*
* charray.c
diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c
index 7a753f8..8c0b7ee 100644
--- a/ldap/servers/slapd/util.c
+++ b/ldap/servers/slapd/util.c
@@ -325,13 +325,15 @@ int slapi_mods2entry (Slapi_Entry **e, const char *idn, LDAPMod **iattrs)
return rc;
}
-int slapi_entry2mods (const Slapi_Entry *e, char **dn, LDAPMod ***attrs)
+int
+slapi_entry2mods (const Slapi_Entry *e, char **dn, LDAPMod ***attrs)
{
Slapi_Mods smods;
Slapi_Attr *attr;
Slapi_Value **va;
char *type;
int rc;
+ int unhashed_pw_on = (SLAPD_UNHASHED_PW_ON == config_get_unhashed_pw_switch());
PR_ASSERT (e && attrs);
@@ -343,8 +345,11 @@ int slapi_entry2mods (const Slapi_Entry *e, char **dn, LDAPMod ***attrs)
while (rc == 0)
{
if ( NULL != ( va = attr_get_present_values( attr ))) {
- slapi_attr_get_type(attr, &type);
- slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD, type, va );
+ slapi_attr_get_type(attr, &type);
+ if (unhashed_pw_on || strcasecmp(type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD)) {
+ /* SLAPD_UNHASHED_PW_ON or type is not unhashed pw */
+ slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD, type, va );
+ }
}
rc = slapi_entry_next_attr(e, attr, &attr);
}
9 years
Branch '389-ds-base-1.3.3' - ldap/servers
by Ludwig Krispenz
ldap/servers/plugins/replication/repl5_agmtlist.c | 54 +++++++++++++++++++++-
1 file changed, 53 insertions(+), 1 deletion(-)
New commits:
commit 891d4cece7072e545ec6d651c06e4f923b4294cc
Author: Ludwig Krispenz <lkrispen(a)redhat.com>
Date: Tue Mar 31 10:15:08 2015 +0200
Ticket 48136 -v2v2 accept auxilliary objectclasse in replication agreements
Bug Description: the check for allowed modifications of an
replication agreement handles only the standard agreement
attributes, so extensions by adding another objectclass fails.
Fix Description: Extend the check and allow additions of auxiliary
objectclasses and if an extra obejectclass is present allow
adding of other attributes.
https://fedorahosted.org/389/ticket/48136
Reviewed by: MarkR, thanks
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
index 5b419c6..21823a4 100644
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
@@ -177,6 +177,57 @@ add_new_agreement(Slapi_Entry *e)
return rc;
}
+int
+id_extended_agreement(Repl_Agmt *agmt, LDAPMod** mods, Slapi_Entry *e)
+{
+ Slapi_Attr *sattr = NULL;
+ char *val = NULL;
+ int return_value = 0;
+ int i;
+
+ slapi_entry_attr_find(e, "objectclass", &sattr);
+ if (sattr) {
+ Slapi_Value *sval = NULL;
+ const char *val = NULL;
+ for (i = slapi_attr_first_value(sattr, &sval);
+ i >= 0; i = slapi_attr_next_value(sattr, i, &sval)) {
+ val = slapi_value_get_string(sval);
+ if ((0 == strcasecmp(val,"top")) ||
+ (0 == strcasecmp(val,"nsds5replicationAgreement"))) {
+ continue;
+ } else {
+ /* the entry has an additional objectclass, accept mods */
+ return 1;
+ }
+ }
+ }
+ /* This modification could remove an additional objectclass.
+ * In the entry we check this mod has already been applied,
+ * so check list of mods
+ */
+ for (i = 0; NULL != mods && NULL != mods[i]; i++) {
+ if (strcasecmp(mods[i]->mod_type, "objectclass")) continue;
+ if (mods[i]->mod_bvalues){
+ int j;
+ for (j = 0; mods[i]->mod_bvalues[j]; j++){
+ slapi_ch_free_string(&val);
+ val = slapi_berval_get_string_copy (mods[i]->mod_bvalues[j]);
+ if ((0 == strcasecmp(val,"top")) ||
+ (0 == strcasecmp(val,"nsds5replicationAgreement"))) {
+ continue;
+ } else {
+ /* an additional objectclass was modified */
+ return_value = 1;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ slapi_ch_free_string(&val);
+ return return_value;
+}
+
static int
agmtlist_add_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter,
int *returncode, char *returntext, void *arg)
@@ -583,7 +634,8 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
(void) agmt_set_WaitForAsyncResults(agmt, e);
}
}
- else if (0 == windows_handle_modify_agreement(agmt, mods[i]->mod_type, e))
+ else if ((0 == windows_handle_modify_agreement(agmt, mods[i]->mod_type, e)) &&
+ (0 == id_extended_agreement(agmt, mods, e)))
{
slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
"modification of %s attribute is not allowed\n", mods[i]->mod_type);
9 years
ldap/servers
by Ludwig Krispenz
ldap/servers/plugins/replication/repl5_agmtlist.c | 54 +++++++++++++++++++++-
1 file changed, 53 insertions(+), 1 deletion(-)
New commits:
commit fd816432a280ccfcc5d733a02daa486ba40fd27b
Author: Ludwig Krispenz <lkrispen(a)redhat.com>
Date: Tue Mar 31 10:15:08 2015 +0200
Ticket 48136 -v2v2 accept auxilliary objectclasse in replication agreements
Bug Description: the check for allowed modifications of an
replication agreement handles only the standard agreement
attributes, so extensions by adding another objectclass fails.
Fix Description: Extend the check and allow additions of auxiliary
objectclasses and if an extra obejectclass is present allow
adding of other attributes.
https://fedorahosted.org/389/ticket/48136
Reviewed by: MarkR, thanks
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
index 5b419c6..21823a4 100644
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
@@ -177,6 +177,57 @@ add_new_agreement(Slapi_Entry *e)
return rc;
}
+int
+id_extended_agreement(Repl_Agmt *agmt, LDAPMod** mods, Slapi_Entry *e)
+{
+ Slapi_Attr *sattr = NULL;
+ char *val = NULL;
+ int return_value = 0;
+ int i;
+
+ slapi_entry_attr_find(e, "objectclass", &sattr);
+ if (sattr) {
+ Slapi_Value *sval = NULL;
+ const char *val = NULL;
+ for (i = slapi_attr_first_value(sattr, &sval);
+ i >= 0; i = slapi_attr_next_value(sattr, i, &sval)) {
+ val = slapi_value_get_string(sval);
+ if ((0 == strcasecmp(val,"top")) ||
+ (0 == strcasecmp(val,"nsds5replicationAgreement"))) {
+ continue;
+ } else {
+ /* the entry has an additional objectclass, accept mods */
+ return 1;
+ }
+ }
+ }
+ /* This modification could remove an additional objectclass.
+ * In the entry we check this mod has already been applied,
+ * so check list of mods
+ */
+ for (i = 0; NULL != mods && NULL != mods[i]; i++) {
+ if (strcasecmp(mods[i]->mod_type, "objectclass")) continue;
+ if (mods[i]->mod_bvalues){
+ int j;
+ for (j = 0; mods[i]->mod_bvalues[j]; j++){
+ slapi_ch_free_string(&val);
+ val = slapi_berval_get_string_copy (mods[i]->mod_bvalues[j]);
+ if ((0 == strcasecmp(val,"top")) ||
+ (0 == strcasecmp(val,"nsds5replicationAgreement"))) {
+ continue;
+ } else {
+ /* an additional objectclass was modified */
+ return_value = 1;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ slapi_ch_free_string(&val);
+ return return_value;
+}
+
static int
agmtlist_add_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter,
int *returncode, char *returntext, void *arg)
@@ -583,7 +634,8 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
(void) agmt_set_WaitForAsyncResults(agmt, e);
}
}
- else if (0 == windows_handle_modify_agreement(agmt, mods[i]->mod_type, e))
+ else if ((0 == windows_handle_modify_agreement(agmt, mods[i]->mod_type, e)) &&
+ (0 == id_extended_agreement(agmt, mods, e)))
{
slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
"modification of %s attribute is not allowed\n", mods[i]->mod_type);
9 years