Browse Source

Ticket 328 - make sure all internal search filters are properly escaped

Bug Description:  Not all internal search fitlers are properly escaped.

Fix Description:  Created a new sprintf type function, and a filter value escape function.

                  The sprintf function(slapi_filter_sprintf) varies from sprintf as you pass
                  a description argument before the value you want to escape/normalize:

                    ESC_NEXT_VAL          - escape the next argument
                    NORM_NEXT_VAL         - normalize the next argument
                    ESC_AND_NORM_NEXT_VAL - escape and normalize the next argument

                  In order to correctly normalize the value, the function also parses out the attribute
                  so we can get the syntax plugin normalization function.

                  As a side effect you must add an additional string format character for the description
                  arg(%s):

                         sprintf(buf,"cn=%s", value);

                         escaped_val = slapi_filter_sprintf("cn=%s%s", ESC_NEXT_VAL, value);

                  Also did some code cleanup.

https://fedorahosted.org/389/ticket/328

reviewed by: Noriko(Thanks!)
Mark Reynolds 13 years ago
parent
commit
3cf9a521fa

+ 4 - 13
ldap/servers/plugins/acl/acllas.c

@@ -2896,7 +2896,6 @@ acllas__eval_memberGroupDnAttr (char *attrName, Slapi_Entry *e,
 	** client is a member of.
 	*/
 	if (enumerate_groups) {
-		char			filter_str[BUFSIZ];
 		char			*attrs[3];
 		struct eval_info	info = {0};
 		char			*curMemberDn;
@@ -2934,23 +2933,15 @@ acllas__eval_memberGroupDnAttr (char *attrName, Slapi_Entry *e,
 		curMemberDn = n_clientdn;
 
 		while (!Done) {
-			char *filter_str_ptr = &filter_str[0];
-			char *new_filter_str = NULL;
-			int lenf = strlen(curMemberDn)<<1;
-
-			if (lenf > (BUFSIZ - 28)) { /* 28 for "(|(uniquemember=%s)(member=%s))" */
-				new_filter_str = slapi_ch_malloc(lenf + 28);
-				filter_str_ptr = new_filter_str;
-			}
+			char *filter_str_ptr;
 
 			/*
 			** Search the db for groups that the client is a member of.
 			** Once found cache it. cache only unique groups.
 			*/
 			tt = info.lu_idx;
-			sprintf (filter_str_ptr,"(|(uniquemember=%s)(member=%s))", 
-						curMemberDn, curMemberDn); 
-
+			filter_str_ptr = slapi_filter_sprintf("(|(uniquemember=%s%s)(member=%s%s))",
+					ESC_AND_NORM_NEXT_VAL, curMemberDn, ESC_AND_NORM_NEXT_VAL ,curMemberDn);
 			/* Use new search internal API */
 			{
 				Slapi_PBlock *aPb = slapi_pblock_new ();
@@ -2976,7 +2967,7 @@ acllas__eval_memberGroupDnAttr (char *attrName, Slapi_Entry *e,
 				slapi_pblock_destroy (aPb);
 			}
 
-			if (new_filter_str) slapi_ch_free((void **) &new_filter_str);
+			slapi_ch_free_string(&filter_str_ptr);
 
 			if (tt == info.lu_idx) {
 				slapi_log_error( SLAPI_LOG_ACL, plugin_name, "currDn:(%s) \n\tNO MEMBER ADDED\n", 

+ 18 - 6
ldap/servers/plugins/memberof/memberof.c

@@ -520,12 +520,14 @@ int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
 	Slapi_PBlock *search_pb = NULL;
 	Slapi_DN *base_sdn = NULL;
 	Slapi_Backend *be = NULL;
+	char *escaped_filter_val;
 	char *filter_str = NULL;
 	char *cookie = NULL;
 	int all_backends = memberof_config_get_all_backends();
 	int types_name_len = 0;
 	int num_types = 0;
 	int dn_len = slapi_sdn_get_ndn_len(sdn);
+	int free_it = 0;
 	int rc = 0;
 	int i = 0;
 
@@ -537,7 +539,15 @@ int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
 		types_name_len += strlen(types[num_types]);
 	}
 
-	/* Build the search filter. */
+	/* Escape the dn, and build the search filter. */
+	escaped_filter_val = slapi_escape_filter_value((char *)slapi_sdn_get_dn(sdn), dn_len);
+	if(escaped_filter_val){
+		dn_len = strlen(escaped_filter_val);
+		free_it = 1;
+	} else {
+		escaped_filter_val = (char *)slapi_sdn_get_dn(sdn);
+	}
+
 	if (num_types > 1)
 	{
 		int bytes_out = 0;
@@ -553,7 +563,7 @@ int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
 		for (i = 0; types[i]; i++)
 		{
 			bytes_out += snprintf(filter_str + bytes_out, filter_str_len - bytes_out,
-					"(%s=%s)", types[i], slapi_sdn_get_ndn(sdn));
+					"(%s=%s)", types[i], escaped_filter_val);
 		}
 
 		/* Add end of filter. */
@@ -561,10 +571,12 @@ int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
 	}
 	else if (num_types == 1)
 	{
-		filter_str =
-		        slapi_ch_smprintf("(%s=%s)", types[0], slapi_sdn_get_ndn(sdn));
+		filter_str = slapi_ch_smprintf("(%s=%s)", types[0], escaped_filter_val);
 	}
 
+	if(free_it)
+		slapi_ch_free_string(&escaped_filter_val);
+
 	if(filter_str == NULL){
 		return rc;
 	}
@@ -1131,12 +1143,12 @@ memberof_modop_one_replace_r(Slapi_PBlock *pb, MemberOfConfig *config,
 			Slapi_PBlock *search_pb = slapi_pblock_new();
 			Slapi_DN *base_sdn = 0;
 			Slapi_Backend *be = 0;
-			char *filter_str = 0;
+			char *filter_str;
 			char *cookie = NULL;
 			int n_entries = 0;
 			int all_backends = config->allBackends;
 
-			filter_str = slapi_ch_smprintf("(%s=%s)", config->memberof_attr, op_to);
+			filter_str = slapi_filter_sprintf("(%s=%s%s)", config->memberof_attr, ESC_NEXT_VAL, op_to);
 			be = slapi_get_first_backend(&cookie);
 			while(be){
 				/*

+ 1 - 4
ldap/servers/plugins/referint/referint.c

@@ -684,7 +684,6 @@ update_integrity(char **argv, Slapi_DN *origSDN,
     char *attrName = NULL;
     char *filter = NULL;
     char *attrs[2];
-    size_t len = slapi_sdn_get_ndn_len(origSDN);
     int search_result;
     int nval = 0;
     int i, j;
@@ -709,9 +708,7 @@ update_integrity(char **argv, Slapi_DN *origSDN,
         search_base = slapi_sdn_get_dn( sdn );
 
         for(i = 3; argv[i] != NULL; i++){
-            char buf[BUFSIZ];
-            filter = slapi_ch_smprintf("(%s=*%s)", argv[i],
-                                    escape_filter_value(origDN, len, buf));
+            filter = slapi_filter_sprintf("(%s=*%s%s)", argv[i], ESC_NEXT_VAL, origDN);
             if ( filter ) {
                 /* Need only the current attribute and its subtypes */
                 attrs[0] = argv[i];

+ 2 - 1
ldap/servers/plugins/replication/urp.c

@@ -1082,7 +1082,8 @@ urp_get_min_naming_conflict_entry ( Slapi_PBlock *pb, char *sessionid, CSN *opcs
 	slapi_log_error ( SLAPI_LOG_REPL, sessionid,
 		"Enter urp_get_min_naming_conflict_entry for %s\n", basedn);
 
-	filter = PR_smprintf("(%s=%s %s)", ATTR_NSDS5_REPLCONFLICT, REASON_ANNOTATE_DN, basedn);
+	filter = slapi_filter_sprintf("(%s=%s %s%s)", ATTR_NSDS5_REPLCONFLICT, REASON_ANNOTATE_DN,
+			ESC_NEXT_VAL, basedn);
 
 	/* server_ctrls will be freed when newpb is destroyed */
 	server_ctrls = (LDAPControl **)slapi_ch_calloc (2, sizeof (LDAPControl *));

+ 40 - 50
ldap/servers/plugins/replication/windows_protocol_util.c

@@ -2913,14 +2913,9 @@ find_entry_by_attr_value_remote(const char *attribute, const char *value, Slapi_
 	char *filter = NULL;
 	const char *searchbase = NULL;
 	Slapi_Entry *found_entry = NULL;
-	char *filter_escaped_value = NULL;
-	size_t vallen = 0;
 
-	vallen = value ? strlen(value) : 0;
-	filter_escaped_value = slapi_ch_calloc(sizeof(char), vallen*3+1);
 	/* should not have to escape attribute names */
-	filter = PR_smprintf("(%s=%s)",attribute,escape_filter_value(value, vallen, filter_escaped_value));
-	slapi_ch_free_string(&filter_escaped_value);
+	filter = slapi_filter_sprintf("(%s=%s%s)",attribute, ESC_NEXT_VAL, value);
 	searchbase = slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt));
 	cres = windows_search_entry(prp->conn, (char*)searchbase, filter, &found_entry);
 	if (cres)
@@ -2935,7 +2930,7 @@ find_entry_by_attr_value_remote(const char *attribute, const char *value, Slapi_
 	}
 	if (filter)
 	{
-		PR_smprintf_free(filter);
+		slapi_ch_free_string(&filter);
 		filter = NULL;
 	}
 	return retval;
@@ -3035,33 +3030,28 @@ find_entry_by_attr_value(const char *attribute, const char *value, Slapi_Entry *
 {
     Slapi_PBlock *pb = slapi_pblock_new();
     Slapi_Entry **entries = NULL, **ep = NULL;
-	Slapi_Entry *entry_found = NULL;
+    Slapi_Entry *entry_found = NULL;
+    LDAPControl **server_controls = NULL;
+    const char *subtree_dn = NULL;
+    char *subtree_dn_copy = NULL;
+    char **attrs = NULL;
     char *query = NULL;
-	int found_or_not = ENTRY_NOTFOUND;
-	int rval = 0;
-	const char *subtree_dn = NULL;
-	int not_unique = 0;
-	char *subtree_dn_copy = NULL;
-	int scope = LDAP_SCOPE_SUBTREE;
-	char **attrs = NULL;
-	LDAPControl **server_controls = NULL;
-	char *filter_escaped_value = NULL;
-	size_t vallen = 0;
+    int found_or_not = ENTRY_NOTFOUND;
+    int scope = LDAP_SCOPE_SUBTREE;
+    int not_unique = 0;
+    int rval = 0;
 
     if (pb == NULL)
         goto done;
 
-    vallen = value ? strlen(value) : 0;
-    filter_escaped_value = slapi_ch_calloc(sizeof(char), vallen*3+1);
     /* should not have to escape attribute names */
-    query = slapi_ch_smprintf("(%s=%s)", attribute, escape_filter_value(value, vallen, filter_escaped_value));
-    slapi_ch_free_string(&filter_escaped_value);
+    query = slapi_filter_sprintf("(%s=%s%s)", attribute, ESC_NEXT_VAL, value);
 
     if (query == NULL)
-		goto done;
+	    goto done;
 
-	subtree_dn = slapi_sdn_get_dn(windows_private_get_directory_subtree(ra));
-	subtree_dn_copy = slapi_ch_strdup(subtree_dn);
+    subtree_dn = slapi_sdn_get_dn(windows_private_get_directory_subtree(ra));
+    subtree_dn_copy = slapi_ch_strdup(subtree_dn);
 
     winsync_plugin_call_pre_ds_search_entry_cb(ra, NULL, &subtree_dn_copy, &scope, &query,
                                                &attrs, &server_controls);
@@ -3079,35 +3069,35 @@ find_entry_by_attr_value(const char *attribute, const char *value, Slapi_Entry *
 
     slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rval);
     if (rval != LDAP_SUCCESS)
-	{
-		goto done;
-	}
+    {
+        goto done;
+    }
 
     slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
     if ((entries == NULL) || (entries[0] == NULL))
-	{
-		goto done;
-	}
-	entry_found = entries[0];
-	for (ep = entries; *ep; ep++) {
-		if (not_unique)
-		{
-			found_or_not = ENTRY_NOT_UNIQUE;
-		}
-		not_unique = 1;
-	}
+    {
+        goto done;
+    }
+    entry_found = entries[0];
+    for (ep = entries; *ep; ep++) {
+        if (not_unique)
+        {
+            found_or_not = ENTRY_NOT_UNIQUE;
+        }
+        not_unique = 1;
+    }
 done:
-	if (entry_found && (found_or_not != ENTRY_NOT_UNIQUE))
-	{
-		found_or_not = 0;
-		*e = slapi_entry_dup(entry_found);
-	}
-	if (pb)
-	{
-		slapi_free_search_results_internal(pb);
-		slapi_pblock_destroy(pb);
-	}
-	return found_or_not;
+    if (entry_found && (found_or_not != ENTRY_NOT_UNIQUE))
+    {
+        found_or_not = 0;
+        *e = slapi_entry_dup(entry_found);
+    }
+    if (pb)
+    {
+        slapi_free_search_results_internal(pb);
+        slapi_pblock_destroy(pb);
+    }
+    return found_or_not;
 }
 
 static int

+ 29 - 29
ldap/servers/slapd/attr.c

@@ -574,36 +574,36 @@ slapi_attr_value_cmp( const Slapi_Attr *a, const struct berval *v1, const struct
 int
 slapi_attr_value_cmp_ext(const Slapi_Attr *a, Slapi_Value *v1, Slapi_Value *v2)
 {
-	int retVal;
-	const struct berval *bv2 = slapi_value_get_berval(v2);
-
-	if ( a->a_flags & SLAPI_ATTR_FLAG_CMP_BITBYBIT )
-	{
-		const struct berval *bv1 = slapi_value_get_berval(v1);
-		return slapi_attr_value_cmp(a, bv1, bv2);
-	}
-	else
-	{
-		Slapi_Attr a2;
-		struct ava ava;
-		Slapi_Value *cvals[2];
-		unsigned long v2_flags = v2->v_flags;
-
-		a2 = *a;
-		cvals[0] = v1;
-		cvals[1] = NULL;
-		a2.a_present_values.va = cvals; /* JCM - PUKE */
+        int retVal;
+        const struct berval *bv2 = slapi_value_get_berval(v2);
 
-		ava.ava_type = a->a_type;
-		ava.ava_value = *bv2;
-		if (v2_flags) {
-			ava.ava_private = &v2_flags;
-		} else {
-			ava.ava_private = NULL;
-		}
-		retVal = plugin_call_syntax_filter_ava(&a2, LDAP_FILTER_EQUALITY, &ava);
-	}
-	return retVal;
+        if ( a->a_flags & SLAPI_ATTR_FLAG_CMP_BITBYBIT )
+        {
+                const struct berval *bv1 = slapi_value_get_berval(v1);
+                return slapi_attr_value_cmp(a, bv1, bv2);
+        }
+        else
+        {
+                Slapi_Attr a2;
+                struct ava ava;
+                Slapi_Value *cvals[2];
+                unsigned long v2_flags = v2->v_flags;
+
+                a2 = *a;
+                cvals[0] = v1;
+                cvals[1] = NULL;
+                a2.a_present_values.va = cvals; /* JCM - PUKE */
+
+                ava.ava_type = a->a_type;
+                ava.ava_value = *bv2;
+                if (v2_flags) {
+                        ava.ava_private = &v2_flags;
+                } else {
+                        ava.ava_private = NULL;
+                }
+                retVal = plugin_call_syntax_filter_ava(&a2, LDAP_FILTER_EQUALITY, &ava);
+        }
+        return retVal;
 }
 
 /*

+ 28 - 23
ldap/servers/slapd/filter.c

@@ -124,11 +124,11 @@ get_filter( Connection *conn, BerElement *ber, int scope,
 }
 
 
-#define FILTER_EQ_FMT       "(%s=%s)"
-#define FILTER_GE_FMT       "(%s>=%s)"
-#define FILTER_LE_FMT       "(%s<=%s)"
-#define FILTER_APROX_FMT    "(%s~=%s)"
-#define FILTER_EXTENDED_FMT "(%s%s%s%s:=%s)"
+#define FILTER_EQ_FMT       "(%s=%s%s)"
+#define FILTER_GE_FMT       "(%s>=%s%s)"
+#define FILTER_LE_FMT       "(%s<=%s%s)"
+#define FILTER_APROX_FMT    "(%s~=%s%s)"
+#define FILTER_EXTENDED_FMT "(%s%s%s%s:=%s%s)"
 #define FILTER_EQ_LEN	4
 #define FILTER_GE_LEN	5
 #define FILTER_LE_LEN	5
@@ -140,16 +140,14 @@ get_filter( Connection *conn, BerElement *ber, int scope,
 static char *
 filter_escape_filter_value_extended(struct slapi_filter *f) 
 {
-    char ebuf[BUFSIZ], *ptr;
-    const char *estr;
+    char *ptr;
     
-    estr  = escape_filter_value( f->f_mr_value.bv_val, f->f_mr_value.bv_len, ebuf );
-	ptr = slapi_ch_smprintf(FILTER_EXTENDED_FMT,
+    ptr = slapi_filter_sprintf(FILTER_EXTENDED_FMT,
         f->f_mr_type ? f->f_mr_type : "",
         f->f_mr_dnAttrs ? ":dn" : "",
         f->f_mr_oid ? ":" : "",
         f->f_mr_oid ? f->f_mr_oid : "",
-        estr );
+        ESC_NEXT_VAL,  f->f_mr_value.bv_val);
     return ptr;
 }
 
@@ -158,12 +156,11 @@ filter_escape_filter_value_extended(struct slapi_filter *f)
 static char *
 filter_escape_filter_value(struct slapi_filter *f, const char *fmt, size_t len) 
 {
-    char ebuf[BUFSIZ], *ptr;
-    const char *estr;
+    char *ptr;
+
+    filter_compute_hash(f);
+    ptr = slapi_filter_sprintf(fmt, f->f_avtype, ESC_NEXT_VAL, f->f_avvalue.bv_val );
     
-	estr  = escape_filter_value( f->f_avvalue.bv_val, f->f_avvalue.bv_len, ebuf );
-	filter_compute_hash(f);
-    ptr = slapi_ch_smprintf(fmt, f->f_avtype, estr );
     return ptr;
 }
 
@@ -474,8 +471,7 @@ get_substring_filter(
 {
 	ber_tag_t	tag, rc;
 	ber_len_t	len = -1;
-	char		*val, *last, *type = NULL;
-	char		ebuf[BUFSIZ];
+	char		*val, *eval, *last, *type = NULL;
 
 	LDAPDebug( LDAP_DEBUG_FILTER, "=> get_substring_filter\n", 0, 0, 0 );
 
@@ -516,8 +512,11 @@ get_substring_filter(
 				return( LDAP_PROTOCOL_ERROR );
 			}
 			f->f_sub_initial = val;
-    	    /* jcm: Had to cast away a const */
-			val = (char*)escape_filter_value( val, -1, ebuf );
+			eval = (char*)slapi_escape_filter_value( val, -1);
+			if(eval){
+				slapi_ch_free_string(&val);
+				val = eval;
+			}
 			*fstr = slapi_ch_realloc( *fstr, strlen( *fstr ) +
 			    strlen( val ) + 1 );
 			strcat( *fstr, val );
@@ -526,8 +525,11 @@ get_substring_filter(
 		case LDAP_SUBSTRING_ANY:
 			LDAPDebug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
 			charray_add( &f->f_sub_any, val );
-    	    /* jcm: Had to cast away a const */
-			val = (char*)escape_filter_value( val, -1, ebuf );
+			eval = (char*)slapi_escape_filter_value( val, -1);
+			if(eval){
+				slapi_ch_free_string(&val);
+				val = eval;
+			}
 			*fstr = slapi_ch_realloc( *fstr, strlen( *fstr ) +
 			    strlen( val ) + 2 );
 			strcat( *fstr, "*" );
@@ -540,8 +542,11 @@ get_substring_filter(
 				return( LDAP_PROTOCOL_ERROR );
 			}
 			f->f_sub_final = val;
-    	    /* jcm: Had to cast away a const */
-			val = (char*)escape_filter_value( val, -1, ebuf );
+			eval = (char*)slapi_escape_filter_value( val, -1);
+			if(eval){
+				slapi_ch_free_string(&val);
+				val = eval;
+			}
 			*fstr = slapi_ch_realloc( *fstr, strlen( *fstr ) +
 			    strlen( val ) + 2 );
 			strcat( *fstr, "*" );

+ 74 - 71
ldap/servers/slapd/ldaputil.c

@@ -304,53 +304,56 @@ slapi_ldap_url_parse(const char *url, LDAPURLDesc **ludpp, int require_dn, int *
        replace all but the last colon with %3A
        Go to the 3rd '/' or to the end of the string (convert only the host:port part) */
     if (url) {
-	char *p = strstr(url, "://");
-	if (p) {
-	    int foundspace = 0;
-	    int coloncount = 0;
-	    char *lastcolon = NULL;
-	    p += 3;
-	    for (; *p && (*p != '/'); p++) {
-		if (*p == ' ') {
-		    foundspace = 1;
-		}
-		if (*p == ':') {
-		    coloncount++;
-		    lastcolon = p;
-		}
-	    }
-	    if (foundspace) {
-		char *src = NULL, *dest = NULL;
-		/* have to convert url */
-		/* len * 3 is way too much, but acceptable */
-		urlescaped = slapi_ch_calloc(strlen(url) * 3, sizeof(char));
-		dest = urlescaped;
-		/* copy the scheme */
-	        src = strstr(url, "://");
-		src += 3;
-		memcpy(dest, url, src-url);
-		dest += (src-url);
-		/* we have to convert all spaces to %20 - we have to convert
-		   all colons except the last one to %3A */
-		for (; *src; ++src) {
-		    if (src < p) {
-			if (*src == ' ') {
-			    memcpy(dest, "%20", 3);
-			    dest += 3;
-			} else if ((coloncount > 1) && (*src == ':') && (src != lastcolon)) {
-			    memcpy(dest, "%3A", 3);
-			    dest += 3;
-			} else {
-			    *dest++ = *src;
-			}
-		    } else {
-			*dest++ = *src;
-		    }
-		}
-		*dest = '\0';
-		url_to_use = urlescaped;
-	    }
-	}
+        char *p = strstr(url, "://");
+        if (p) {
+            int foundspace = 0;
+            int coloncount = 0;
+            char *lastcolon = NULL;
+
+            p += 3;
+            for (; *p && (*p != '/'); p++) {
+                if (*p == ' ') {
+                    foundspace = 1;
+                }
+                if (*p == ':') {
+                    coloncount++;
+                    lastcolon = p;
+                }
+            }
+            if (foundspace) {
+                char *src = NULL, *dest = NULL;
+
+                /* have to convert url, len * 3 is way too much, but acceptable */
+                urlescaped = slapi_ch_calloc(strlen(url) * 3, sizeof(char));
+                dest = urlescaped;
+                /* copy the scheme */
+                src = strstr(url, "://");
+                src += 3;
+                memcpy(dest, url, src-url);
+                dest += (src-url);
+                /*
+                 * we have to convert all spaces to %20 - we have to convert
+                 * all colons except the last one to %3A
+                 */
+                for (; *src; ++src) {
+                    if (src < p) {
+                        if (*src == ' ') {
+                            memcpy(dest, "%20", 3);
+                            dest += 3;
+                        } else if ((coloncount > 1) && (*src == ':') && (src != lastcolon)) {
+                            memcpy(dest, "%3A", 3);
+                            dest += 3;
+                        } else {
+                            *dest++ = *src;
+                        }
+                    } else {
+                        *dest++ = *src;
+                    }
+                }
+                *dest = '\0';
+                url_to_use = urlescaped;
+            }
+        }
     }
 #endif
 
@@ -388,30 +391,30 @@ slapi_ldap_url_parse(const char *url, LDAPURLDesc **ludpp, int require_dn, int *
 
 #if defined(USE_OPENLDAP)
     if (urlescaped && (*ludpp) && (*ludpp)->lud_host) {
-	/* have to unescape lud_host - can unescape in place */
-	char *p = strstr((*ludpp)->lud_host, "://");
-	if (p) {
-	    char *dest = NULL;
-	    p += 3;
-	    dest = p;
-	    /* up to the first '/', unescape the host */
-	    for (; *p && (*p != '/'); p++) {
-		if (!strncmp(p, "%20", 3)) {
-		    *dest++ = ' ';
-		    p += 2;
-		} else if (!strncmp(p, "%3A", 3)) {
-		    *dest++ = ':';
-		    p += 2;
-		} else {
-		    *dest++ = *p;
-		}
-	    }
-	    /* just copy the remainder of the host, if any */
-	    while (*p) {
-		*dest++ = *p++;
-	    }
-	    *dest = '\0';
-	}
+        /* have to unescape lud_host - can unescape in place */
+        char *p = strstr((*ludpp)->lud_host, "://");
+        if (p) {
+            char *dest = NULL;
+            p += 3;
+            dest = p;
+            /* up to the first '/', unescape the host */
+            for (; *p && (*p != '/'); p++) {
+                if (!strncmp(p, "%20", 3)) {
+                    *dest++ = ' ';
+                    p += 2;
+                } else if (!strncmp(p, "%3A", 3)) {
+                    *dest++ = ':';
+                    p += 2;
+                } else {
+                    *dest++ = *p;
+                }
+            }
+            /* just copy the remainder of the host, if any */
+            while (*p) {
+                *dest++ = *p++;
+            }
+            *dest = '\0';
+        }
     }
     slapi_ch_free_string(&urlescaped);
 #endif

+ 2 - 2
ldap/servers/slapd/libslapd.def

@@ -1097,8 +1097,8 @@ EXPORTS
 	slapi_mtn_get_dn			@1098
 	dl_add_index				@1099
 	dl_replace				@1100
-        send_referrals_from_entry               @1101
-	escape_filter_value			@1102
+	send_referrals_from_entry               @1101
+	slapi_escape_filter_value		@1102
 	slapd_pk11_destroyContext		@1103
 	secoid_destroyAlgorithmID		@1104
 	op_shared_is_allowed_attr		@1105

+ 5 - 3
ldap/servers/slapd/main.c

@@ -1929,7 +1929,8 @@ lookup_instance_name_by_suffix(char *suffix,
         goto done;
 
     if (isexact) {
-        query = slapi_ch_smprintf("(&(objectclass=nsmappingtree)(|(cn=\"%s\")(cn=%s)))", suffix, suffix);
+        query = slapi_filter_sprintf("(&(objectclass=nsmappingtree)(|(cn=\"%s%s\")(cn=%s%s)))",
+                ESC_NEXT_VAL, suffix, ESC_NEXT_VAL, suffix);
         if (query == NULL)
             goto done;
     
@@ -1951,7 +1952,8 @@ lookup_instance_name_by_suffix(char *suffix,
     } else {
         char *suffixp = suffix;
         while (NULL != suffixp && strlen(suffixp) > 0) {
-            query = slapi_ch_smprintf("(&(objectclass=nsmappingtree)(|(cn=*%s\")(cn=*%s)))", suffixp, suffixp);
+            query = slapi_filter_sprintf("(&(objectclass=nsmappingtree)(|(cn=*%s%s\")(cn=*%s%s)))",
+                    ESC_NEXT_VAL, suffixp, ESC_NEXT_VAL, suffixp);
             if (query == NULL)
                 goto done;
             /* Note: This DN is no need to be normalized. */
@@ -2036,7 +2038,7 @@ static struct slapdplugin *lookup_plugin_by_instance_name(const char *name)
     if (pb == NULL)
         return NULL;
 
-    query = slapi_ch_smprintf("(&(cn=%s)(objectclass=nsBackendInstance))", name);
+    query = slapi_filter_sprintf("(&(cn=%s%s)(objectclass=nsBackendInstance))", ESC_AND_NORM_NEXT_VAL, name);
     if (query == NULL) {
         slapi_pblock_destroy(pb);
         return NULL;

+ 7 - 7
ldap/servers/slapd/mapping_tree.c

@@ -908,9 +908,9 @@ static int
 mapping_tree_node_get_children(mapping_tree_node *target, int is_root)
 {
     Slapi_PBlock *pb;
-    char * filter = NULL;
-    int res;
     Slapi_Entry **entries = NULL;
+    char *filter = NULL;
+    int res;
     int x;
     int result = 0;
 
@@ -923,11 +923,11 @@ mapping_tree_node_get_children(mapping_tree_node *target, int is_root)
         filter = slapi_ch_smprintf("(&(objectclass=nsMappingTree)(!(%s=*)))",
                  MAPPING_TREE_PARENT_ATTRIBUTE);
     } else {
-        filter = slapi_ch_smprintf("(&(objectclass=nsMappingTree)(|(%s=\"%s\")(%s=%s)))",
-            MAPPING_TREE_PARENT_ATTRIBUTE, 
-            slapi_sdn_get_dn(target->mtn_subtree),
-            MAPPING_TREE_PARENT_ATTRIBUTE, 
-            slapi_sdn_get_dn(target->mtn_subtree));
+        const char *filter_value = slapi_sdn_get_dn(target->mtn_subtree);
+
+        filter = slapi_filter_sprintf("(&(objectclass=nsMappingTree)(|(%s=\"%s%s\")(%s=%s%s)))",
+            MAPPING_TREE_PARENT_ATTRIBUTE, ESC_NEXT_VAL, filter_value,
+            MAPPING_TREE_PARENT_ATTRIBUTE, ESC_NEXT_VAL, filter_value );
     }
 
     slapi_search_internal_set_pb(pb, MAPPING_TREE_BASE_DN, LDAP_SCOPE_ONELEVEL,

+ 1 - 1
ldap/servers/slapd/plugin.c

@@ -3024,7 +3024,7 @@ plugin_enabled(const char *plugin_name, void *identity)
 	char *filter = NULL;
 	int rc = 0;	/* disabled, by default */
 
-	filter = slapi_ch_smprintf("cn=%s", plugin_name);
+	filter = slapi_filter_sprintf("cn=%s%s", ESC_NEXT_VAL, plugin_name);
 	search_pb = slapi_pblock_new();
 	slapi_search_internal_set_pb(search_pb, PLUGIN_BASE_DN, LDAP_SCOPE_ONELEVEL,
 								 filter, NULL, 0, NULL, NULL, identity, 0);

+ 15 - 0
ldap/servers/slapd/slapi-plugin.h

@@ -3593,6 +3593,21 @@ void slapi_rand_array(void *randx, size_t len);
  */
 int slapi_rand();
 
+/**
+ * Escape special characters in a search filter value
+ *
+ * \param filter_str A ldap search filter value (cn=VALUE_TO_BE_ESCAPED)
+ * \param len length of the search filter value.  -1 indicates the string is null terminated
+ * \param buf the buffer to store the escaped filter value string
+ * \return the escaped filter value string
+ */
+char* slapi_escape_filter_value(char* filter_str, int len);
+
+#define ESC_NEXT_VAL "__ESC__NEXT__VAL__"
+#define NORM_NEXT_VAL "__NORM__NEXT__VAL__"
+#define ESC_AND_NORM_NEXT_VAL "__ESC__AND__NORM__NEXT__VAL__"
+
+char* slapi_filter_sprintf(const char *fmt, ...);
 
 /*
  * attribute routines

+ 0 - 1
ldap/servers/slapd/slapi-private.h

@@ -1143,7 +1143,6 @@ char* slapd_get_tmp_dir( void );
 #include <stdio.h> /* GGOODREPL - For BUFSIZ, below, gak */
 const char* escape_string (const char* str, char buf[BUFSIZ]);
 const char* escape_string_with_punctuation(const char* str, char buf[BUFSIZ]);
-const char* escape_filter_value(const char* str, int len, char buf[BUFSIZ]);
 void strcpy_unescape_value( char *d, const char *s );
 
 char *slapi_berval_get_string_copy(const struct berval *bval);

+ 274 - 4
ldap/servers/slapd/util.c

@@ -72,6 +72,10 @@
 #define _CSEP '/'
 #endif
 
+/* slapi_filter_sprintf macros */
+#define ATTRSIZE 256   /* size allowed for an attr name */
+#define FILTER_BUF 128 /* initial buffer size for attr value */
+#define BUF_INCR 16    /* the amount to increase the FILTER_BUF once it fills up */
 
 static int special_np(unsigned char c)
 {
@@ -95,6 +99,7 @@ static int special_np_and_punct(unsigned char c)
     return UTIL_ESCAPE_NONE;
 }
 
+#ifndef USE_OPENLDAP
 static int special_filter(unsigned char c)
 {
     /*
@@ -110,6 +115,27 @@ static int special_filter(unsigned char c)
             c == '\\' || 
             c == '"') ? UTIL_ESCAPE_HEX : UTIL_ESCAPE_NONE;
 }
+#endif
+
+/*
+ *  Used by filter_stuff_func to help extract an attribute so we know
+ *  how to normalize the value.
+ */
+static int
+special_attr_char(unsigned char c)
+{
+    return (c < 32 ||
+            c > 126 ||
+            c == '*' ||
+            c == '|' ||
+            c == '&' ||
+            c == '!' ||
+            c == '(' ||
+            c == ')' ||
+            c == '\\' ||
+            c == '=' ||
+            c == '"');
+}
 
 static const char*
 do_escape_string (
@@ -180,7 +206,7 @@ do_escape_string (
 	    *bufNext = '\0';
 	    return buf;
 	}
-    } 
+    }
     return str;
 }
 
@@ -206,10 +232,254 @@ escape_string_with_punctuation(const char* str, char buf[BUFSIZ])
   return do_escape_string(str,-1,buf,special_np_and_punct);
 }
 
-const char*
-escape_filter_value(const char* str, int len, char buf[BUFSIZ])
+#define ESCAPE_FILTER 1
+#define NORM_FILTER 2
+
+struct filter_ctx {
+  char *buf;
+  char attr[ATTRSIZE];
+  int attr_position;
+  int attr_found;
+  int buf_size;
+  int buf_len;
+  int next_arg_needs_esc_norm;
+  int skip_escape;
+};
+
+/*
+ *  This function is called by slapi_filter_sprintf to escape/normalize certain values
+ */
+static PRIntn
+filter_stuff_func(void *arg, const char *val, PRUint32 slen)
 {
-    return do_escape_string(str,len,buf,special_filter);
+    struct filter_ctx *ctx = (struct filter_ctx *)arg;
+    struct berval escaped_filter;
+    struct berval raw_filter;
+    char *buf = (char *)val;
+    int extra_space;
+    int filter_len = slen;
+    int free_buf = 0;
+
+    /* look at val - if val is one of our special keywords, and make a note of it for the next pass */
+    if (strcmp(val, ESC_NEXT_VAL) == 0){
+        ctx->next_arg_needs_esc_norm |= ESCAPE_FILTER;
+        return 0;
+    }
+    if (strcmp(val, NORM_NEXT_VAL) == 0){
+        ctx->next_arg_needs_esc_norm |= NORM_FILTER;
+        return 0;
+    }
+    if (strcmp(val, ESC_AND_NORM_NEXT_VAL) == 0){
+        ctx->next_arg_needs_esc_norm = NORM_FILTER | ESCAPE_FILTER;
+        return 0;
+    }
+    /*
+     *  Start collecting the attribute name so we can use the correct
+     *  syntax normalization func.
+     */
+    if(ctx->attr_found == 0 && ctx->attr_position < (ATTRSIZE - 1)){
+        if(ctx->attr[0] == '\0'){
+            if(strstr(val,"=")){
+                /* we have an attr we need to record */
+                if(!special_attr_char(val[0])){
+                    memcpy(ctx->attr, val, 1);
+                    ctx->attr_position++;
+                }
+            } else {
+                /*
+                 *  We have passed in an attribute as a arg - so we can just set the
+                 *  attr with val.  The next pass should be '=', otherwise we will
+                 *  reset it.
+                 */
+                memcpy(ctx->attr, val, slen);
+                ctx->attr_position = slen;
+            }
+        } else {
+            if(val[0] == '='){ /* hit the end of the attribute name */
+                ctx->attr_found = 1;
+            } else {
+                if(special_attr_char(val[0])){
+                    /* this is not an attribute, we should not be collecting this, reset everything */
+                    memset(ctx->attr, '\0', ATTRSIZE);
+                    ctx->attr_position = 0;
+                } else {
+                    memcpy(ctx->attr + ctx->attr_position, val, 1);
+                    ctx->attr_position++;
+                }
+            }
+        }
+    }
+
+    if (ctx->next_arg_needs_esc_norm && !ctx->skip_escape){
+        /*
+         *  Normalize the filter value first
+         */
+        if(ctx->next_arg_needs_esc_norm & NORM_FILTER){
+            char *norm_val = NULL;
+
+            if(ctx->attr_found){
+                slapi_attr_value_normalize(NULL, NULL, ctx->attr , buf, 1, &norm_val );
+                if(norm_val){
+                    buf = norm_val;
+                    filter_len = strlen(buf);
+                }
+            }
+        }
+        /*
+         *  Escape the filter value
+         */
+        if(ctx->next_arg_needs_esc_norm & ESCAPE_FILTER){
+#if defined (USE_OPENLDAP)
+            raw_filter.bv_val = (char *)buf;
+            raw_filter.bv_len = filter_len;
+            if(ldap_bv2escaped_filter_value(&raw_filter, &escaped_filter) != 0){
+                LDAPDebug(LDAP_DEBUG_TRACE, "slapi_filter_sprintf: failed to escape filter value(%s)\n",val,0,0);
+                ctx->next_arg_needs_esc_norm = 0;
+                return -1;
+            } else {
+                filter_len = escaped_filter.bv_len;
+                buf = escaped_filter.bv_val;
+            }
+#else
+            buf = slapi_ch_calloc(sizeof(char), filter_len*3 + 1);
+            free_buf = 1;
+            if(do_escape_string(val, filter_len, buf, special_filter) == NULL){
+                LDAPDebug(LDAP_DEBUG_TRACE, "slapi_filter_sprintf: failed to escape filter value(%s)\n",val,0,0);
+                ctx->next_arg_needs_esc_norm = 0;
+                slapi_ch_free_string(&buf);
+                return -1;
+            } else {
+                filter_len = strlen(buf);
+            }
+#endif
+        }
+
+        /*
+         *  Now add the new value to the buffer, and allocate more memory if needed
+         */
+        if (ctx->buf_size + filter_len >= ctx->buf_len){
+            /* increase buffer for this filter */
+            extra_space = (ctx->buf_len + filter_len + BUF_INCR);
+            slapi_ch_realloc(ctx->buf, sizeof(char) * extra_space);
+            ctx->buf_len = extra_space;
+        }
+
+        /* append the escaped value */
+        memcpy(ctx->buf + ctx->buf_size, buf, filter_len);
+        ctx->buf_size += filter_len;
+
+        /* done with the value, reset everything */
+        ctx->next_arg_needs_esc_norm = 0;
+        ctx->attr_found = 0;
+        ctx->attr_position = 0;
+        memset(ctx->attr, '\0', ATTRSIZE);
+        if(free_buf){
+            slapi_ch_free_string(&buf);
+        }
+
+        return filter_len;
+    } else { /* process arg as is */
+        /* check if we have enough room in our buffer */
+        if (ctx->buf_size + slen >= ctx->buf_len){
+            /* increase buffer for this filter */
+            extra_space = (ctx->buf_len + slen + BUF_INCR);
+            ctx->buf = slapi_ch_realloc((char *)ctx->buf, sizeof(char) * extra_space);
+            ctx->buf_len = extra_space;
+        }
+        memcpy(ctx->buf + ctx->buf_size, buf, slen);
+        ctx->buf_size += slen;
+
+        return slen;
+    }
+}
+
+/*
+ *  This is basically like slapi_ch_smprintf() except it can handle special
+ *  keywords that will cause the next value to be escaped and/or normalized.
+ *
+ *  ESC_NEXT_VAL - escape the next value
+ *  NORM_NEXT_VAL -  normalize the next value
+ *  ESC_AND_NORM_NEXT_VAL - escape and normalize the next value
+ *
+ *  Example:
+ *
+ *     slapi_filter_sprintf("cn=%s%s", ESC_NEXT_VAL, value);
+ *     slapi_filter_sprintf("(|(cn=%s%s)(sn=%s%s))", ESC_NEXT_VAL, value, NORM_NEXT_VAL, value);
+ *
+ *  Note: you need a string format specifier(%s) for each keyword
+ */
+char*
+slapi_filter_sprintf(const char *fmt, ...)
+{
+    struct filter_ctx ctx;
+    va_list args;
+    char *buf;
+    int rc;
+
+    buf = slapi_ch_calloc(sizeof(char), FILTER_BUF + 1);
+    ctx.buf = buf;
+    memset(ctx.attr,'\0', ATTRSIZE);
+    ctx.attr_position = 0;
+    ctx.attr_found = 0;
+    ctx.buf_len = FILTER_BUF;
+    ctx.buf_size = 0;
+    ctx.next_arg_needs_esc_norm = 0;
+    ctx.skip_escape = 0;
+
+    va_start(args, fmt);
+    rc = PR_vsxprintf(filter_stuff_func, &ctx, fmt, args);
+    if(rc == -1){
+        /* transformation failed, just return non-normalized/escaped string */
+        ctx.skip_escape = 1;
+        PR_vsxprintf(filter_stuff_func, &ctx, fmt, args);
+    }
+    va_end(args);
+
+    return buf;
+}
+
+/*
+ *  escape special characters in values used in search filters
+ *
+ *  caller must free the returned value
+ */
+char*
+slapi_escape_filter_value(char* filter_str, int len)
+{
+    struct berval *escaped_filter = NULL;
+    struct berval raw_filter;
+    int filter_len;
+
+    /*
+     *  Check the length for special cases
+     */
+    if(len == -1){
+        /* filter str is null terminated */
+        filter_len = strlen(filter_str);
+    } else if (len == 0){
+        /* return the filter as is */
+        return slapi_ch_strdup(filter_str);
+    } else {
+        /* the len is the length */
+        filter_len = len;
+    }
+#if defined (USE_OPENLDAP)
+    /*
+     *  Construct the berval and escape it
+     */
+    raw_filter.bv_val = filter_str;
+    raw_filter.bv_len = filter_len;
+    if(ldap_bv2escaped_filter_value(&raw_filter, escaped_filter) != 0){
+        LDAPDebug(LDAP_DEBUG_TRACE, "slapi_escape_filter_value: failed to escape filter value(%s)\n",filter_str,0,0);
+        return NULL;
+    } else {
+        return slapi_ch_strdup(escaped_filter->bv_val);
+    }
+#else
+    char *buf = slapi_ch_calloc(sizeof(char), filter_len*3+1);
+
+    return do_escape_string(filter_str, filter_len, buf, special_filter);
+#endif
 }
 
 /*