From 3e9b558af99f4033885be773548a0850992971c6 Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Wed, 14 Apr 2010 19:28:47 +0000
Subject: [PATCH] ITS#5340 fixes

---
 CHANGES                    |  1 +
 servers/slapd/proto-slap.h |  4 ++++
 servers/slapd/result.c     | 44 ++++++++++++++++++++++++++++++++++++++
 servers/slapd/slap.h       |  1 +
 4 files changed, 50 insertions(+)

diff --git a/CHANGES b/CHANGES
index a3a3aceda2..49f3d52149 100644
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,7 @@ OpenLDAP 2.4.21 Release (2009/12/20)
 	Fixed liblutil for negative microsecond offsets (ITS#6405)
 	Fixed slapd global settings to work without restart (ITS#6428)
 	Fixed slapd looping with SSL/TLS connections (ITS#6412)
+	Fixed slapd REP_ENTRY flag handling (ITS#5340)
 	Fixed slapd syncrepl freeing tasks from queue (ITS#6413)
 	Fixed slapd syncrepl parsing of tls defaults (ITS#6419)
 	Fixed slapd syncrepl uninitialized variables (ITS#6425)
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index b3d7767ee9..8bf3580084 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -1512,6 +1512,10 @@ LDAP_SLAPD_F (int) get_alias_dn LDAP_P((
 /*
  * result.c
  */
+LDAP_SLAPD_F (void) rs_replace_entry LDAP_P(( Operation *op,
+	SlapReply *rs, slap_overinst *on, Entry *e ));
+LDAP_SLAPD_F (int) rs_ensure_entry_modifiable LDAP_P(( Operation *op,
+	SlapReply *rs, slap_overinst *on ));
 LDAP_SLAPD_F (void) slap_send_ldap_result LDAP_P(( Operation *op, SlapReply *rs ));
 LDAP_SLAPD_F (void) send_ldap_sasl LDAP_P(( Operation *op, SlapReply *rs ));
 LDAP_SLAPD_F (void) send_ldap_disconnect LDAP_P(( Operation *op, SlapReply *rs ));
diff --git a/servers/slapd/result.c b/servers/slapd/result.c
index e74f7dbf35..38152e0194 100644
--- a/servers/slapd/result.c
+++ b/servers/slapd/result.c
@@ -132,6 +132,50 @@ slap_req2res( ber_tag_t tag )
 	return tag;
 }
 
+#ifdef RS_ASSERT
+#elif 0 && defined LDAP_DEVEL /* FIXME: this should not crash. ITS#5340. */
+#define RS_ASSERT assert
+#else
+#define RS_ASSERT(cond) ((void) 0)
+#endif
+
+/* Set rs->sr_entry after obyeing and clearing sr_flags & REP_ENTRY_MASK. */
+void
+rs_replace_entry( Operation *op, SlapReply *rs, slap_overinst *on, Entry *e )
+{
+	slap_mask_t e_flags = rs->sr_flags & REP_ENTRY_MUSTFLUSH;
+
+	if ( e_flags && rs->sr_entry != NULL ) {
+		RS_ASSERT( e_flags != REP_ENTRY_MUSTFLUSH );
+		if ( !(e_flags & REP_ENTRY_MUSTRELEASE) ) {
+			entry_free( rs->sr_entry );
+		} else if ( on != NULL ) {
+			overlay_entry_release_ov( op, rs->sr_entry, 0, on );
+		} else {
+			be_entry_release_rw( op, rs->sr_entry, 0 );
+		}
+	}
+	rs->sr_flags &= ~REP_ENTRY_MASK;
+	rs->sr_entry = e;
+}
+
+/*
+ * Ensure rs->sr_entry is modifiable, by duplicating it if necessary.
+ * Obey sr_flags.  Set REP_ENTRY_<MODIFIABLE, and MUSTBEFREED if duplicated>.
+ * Return nonzero if rs->sr_entry was replaced.
+ */
+int
+rs_ensure_entry_modifiable( Operation *op, SlapReply *rs, slap_overinst *on )
+{
+	if ( rs->sr_flags & REP_ENTRY_MODIFIABLE ) {
+		RS_ASSERT((rs->sr_flags & REP_ENTRY_MUSTFLUSH)==REP_ENTRY_MUSTBEFREED);
+		return 0;
+	}
+	rs_replace_entry( op, rs, on, entry_dup( rs->sr_entry ));
+	rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
+	return 1;
+}
+
 static long send_ldap_ber(
 	Operation *op,
 	BerElement *ber )
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index 2eb949d8c6..56e1768170 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -2090,6 +2090,7 @@ struct SlapReply {
 #define REP_ENTRY_MUSTBEFREED	0x0002U
 #define REP_ENTRY_MUSTRELEASE	0x0004U
 #define	REP_ENTRY_MASK		(REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED|REP_ENTRY_MUSTRELEASE)
+#define	REP_ENTRY_MUSTFLUSH	(REP_ENTRY_MUSTBEFREED|REP_ENTRY_MUSTRELEASE)
 
 #define REP_MATCHED_MUSTBEFREED	0x0010U
 #define	REP_MATCHED_MASK	(REP_MATCHED_MUSTBEFREED)
-- 
GitLab