1
0
Эх сурвалжийг харах

slapi_ldap_url_parse must handle multiple host:port in url

mozldap supports a non-standard URL extension which allows multiple host:port
combinations - openldap does not support this - fake out openldap by
converting spaces to %20 and all but the last colon to %3A before calling
ldap_url_parse, then unescape ludp->lud_host before returning
Rich Megginson 15 жил өмнө
parent
commit
312afcd8a0

+ 94 - 5
ldap/servers/slapd/ldaputil.c

@@ -141,27 +141,87 @@ slapi_ldap_url_parse(const char *url, LDAPURLDesc **ludpp, int require_dn, int *
     PR_ASSERT(url);
     PR_ASSERT(ludpp);
     int rc;
+    const char *url_to_use = url;
+#if defined(USE_OPENLDAP)
+    char *urlescaped = NULL;
+#endif
 
     if (secure) {
         *secure = 0;
     }
+#if defined(USE_OPENLDAP)
+    /* openldap does not support the non-standard multi host:port URLs supported
+       by mozldap - so we have to fake out openldap - replace all spaces with %20 -
+       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;
+	    }
+	}
+    }
+#endif
+
 #if defined(HAVE_LDAP_URL_PARSE_NO_DEFAULTS)
-    rc = ldap_url_parse_no_defaults(url, ludpp, require_dn);
+    rc = ldap_url_parse_no_defaults(url_to_use, ludpp, require_dn);
     if (!rc && *ludpp && secure) {
         *secure = (*ludpp)->lud_options & LDAP_URL_OPT_SECURE;
     }
 #else /* openldap */
 #if defined(HAVE_LDAP_URL_PARSE_EXT) && defined(LDAP_PVT_URL_PARSE_NONE) && defined(LDAP_PVT_URL_PARSE_NOEMPTY_DN)
-    rc = ldap_url_parse_ext(url, ludpp, require_dn ? LDAP_PVT_URL_PARSE_NONE : LDAP_PVT_URL_PARSE_NOEMPTY_DN);
+    rc = ldap_url_parse_ext(url_to_use, ludpp, require_dn ? LDAP_PVT_URL_PARSE_NONE : LDAP_PVT_URL_PARSE_NOEMPTY_DN);
 #else
-    rc = ldap_url_parse(url, ludpp);
+    rc = ldap_url_parse(url_to_use, ludpp);
     if ((rc || !*ludpp) && !require_dn) { /* failed - see if failure was due to missing dn */
-        size_t len = strlen(url);
+        size_t len = strlen(url_to_use);
         /* assume the url is just scheme://host:port[/] - add the empty string
            as the DN (adding a trailing / first if needed) and try to parse
            again
         */
-        char *urlcopy = slapi_ch_smprintf("%s%s%s", url, (url[len-1] == '/' ? "" : "/"), "");
+        char *urlcopy = slapi_ch_smprintf("%s%s%s", url_to_use, (url_to_use[len-1] == '/' ? "" : "/"), "");
         if (*ludpp) {
             ldap_free_urldesc(*ludpp); /* free the old one, if any */
         }
@@ -177,6 +237,35 @@ slapi_ldap_url_parse(const char *url, LDAPURLDesc **ludpp, int require_dn, int *
     }
 #endif /* openldap */
 
+#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';
+	}
+    }
+    slapi_ch_free_string(&urlescaped);
+#endif
     return rc;
 }