From 004c23649e522492b1a0e1077a06423eee417fc4 Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@redhat.com>
Date: Fri, 24 Jan 2014 16:24:48 -0800
Subject: [PATCH] Ticket #47649 - Server hangs in cos_cache when adding a user
 entry

Bug description: cos_dn_defs_cb reads cosDefinition and sets up the cos
Definition part of cos cache.  In the function, when processing cosAttribute,
cosTargetTree and cosTemlpateDn are missing, it sets the parent dn of the
cos definition dn.  This parent setting is needed only when the 2 attributes
are completely missing from the cos definition.  But if the attributes are
located below cosAttribute (see the Example cos definition), in addition to
"cn=cosTemplates,ou=people,dc=example,dc=com", the parent of "cn=generate-
PostalCode,ou=People,dc=example,dc=com" is added to the cos cache as
cosTemplateDn.
  Example cos definition:
    dn: cn=generatePostalCode,ou=People,dc=example,dc=com
    description: generate postalCode attr based on location
    objectClass: top
    objectClass: ldapsubentry
    objectClass: cossuperdefinition
    objectClass: cosClassicDefinition
    cosAttribute: postalCode
    costemplatedn: cn=cosTemplates,ou=people,dc=example,dc=com
    cosSpecifier: l
    cn: generatePostalCode
The mistakenly added cosTemplatedDn makes adding an entry under ou=People notify
recreating the cos cache.  The notification needs to be outside of backend
transaction since it causes a deadlock with the cos_cache_wait_on_change thread
which cannot read the DB due to the transaction but holds the lock that the
notifier thread is waiting for.

Fix description: The parent of the cos definition dn is set to the cosTargetTree
and the cosTemlpateDn, only when the attributes are completely missing.
---
 ldap/servers/plugins/cos/cos_cache.c | 61 ++++++++++++++++++------------------
 1 file changed, 30 insertions(+), 31 deletions(-)

diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index 4a3a23a..0ba561e 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -727,7 +727,8 @@ struct dn_defs_info {
  * if a particular attempt to add a definition fails: info.ret gets set to
  * zero only if we succed to add a def.
 */
-static int 	cos_dn_defs_cb (Slapi_Entry* e, void *callback_data)
+static int 
+cos_dn_defs_cb (Slapi_Entry* e, void *callback_data)
 {
 	struct dn_defs_info *info;
 	cosAttrValue **pSneakyVal = 0;
@@ -877,31 +878,10 @@ static int 	cos_dn_defs_cb (Slapi_Entry* e, void *callback_data)
 					                      dnVals[valIndex]->bv_val);
 				}
 
-				if(!pCosTargetTree)
-				{
-					/* get the parent of the definition */
-					char *orig = slapi_dn_parent(pDn->val);
-					Slapi_DN *psdn = slapi_sdn_new_dn_byval(orig);
-					char *parent = (char *)slapi_sdn_get_dn(psdn);
-					if (!parent) {
-						parent = (char *)slapi_sdn_get_udn(psdn);
-						LDAPDebug(LDAP_DEBUG_ANY, 
-						  "cos_cache_build_definition_list: "
-						  "failed to normalize parent dn %s. "
-						  "Adding the pre normalized dn.\n", 
-						  parent, 0, 0);
-					}
-					cos_cache_add_attrval(&pCosTargetTree, parent);
-					if (!pCosTemplateDn) {
-						cos_cache_add_attrval(&pCosTemplateDn, parent);
-					}
-					slapi_sdn_free(&psdn);
-				}
-				
 				slapi_vattrspi_regattr((vattr_sp_handle *)vattr_handle,
 				                        dnVals[valIndex]->bv_val, NULL, NULL);
 			} /* if(attrType is cosAttribute) */
-										
+
 			/*
 			 * Add the attributetype to the appropriate
 			 * list.
@@ -913,6 +893,30 @@ static int 	cos_dn_defs_cb (Slapi_Entry* e, void *callback_data)
 		ber_bvecfree( dnVals );
 		dnVals = NULL;
 	} while(!slapi_entry_next_attr(e, dnAttr, &dnAttr));
+
+	if (pCosAttribute && (!pCosTargetTree || !pCosTemplateDn)) {
+		/* get the parent of the definition */
+		char *orig = slapi_dn_parent(pDn->val);
+		char *parent = slapi_create_dn_string("%s", orig);
+		if (!parent) {
+			parent = orig;
+			LDAPDebug(LDAP_DEBUG_ANY, 
+			          "cos_cache_build_definition_list: "
+			          "failed to normalize parent dn %s. "
+			          "Adding the pre normalized dn.\n", 
+			          parent, 0, 0);
+		}
+		if (!pCosTargetTree) {
+			cos_cache_add_attrval(&pCosTargetTree, parent);
+		}
+		if (!pCosTemplateDn) {
+			cos_cache_add_attrval(&pCosTemplateDn, parent);
+		}
+		if (parent != orig) {
+			slapi_ch_free_string(&parent);
+		}
+		slapi_ch_free_string(&orig);
+	}
 	
 	/*
 	determine the type of class of service scheme 
@@ -3582,14 +3586,9 @@ static int cos_cache_entry_is_cos_related( Slapi_Entry *e) {
 			{
 				pObj = (char*)slapi_value_get_string(val);
 
-				/*
-				 * objectclasses are ascii--maybe strcasecmp() is faster than
-				 * slapi_utf8casecmp()
-				*/
-				if(	!strcasecmp(pObj, "cosdefinition") ||
-					!strcasecmp(pObj, "cossuperdefinition") ||
-					!strcasecmp(pObj, "costemplate")
-					)
+				if(!strcasecmp(pObj, "cosdefinition") ||
+				   !strcasecmp(pObj, "cossuperdefinition") ||
+				   !strcasecmp(pObj, "costemplate"))
 				{
 					rc = 1;
 				}
-- 
1.8.1.4

