Hello,
most probably, ldap_quote_dn in exim 4.14 does *not*, what RFC 1485
recommends as DN string representation.
The ABNF encourages a sedecimal (hex) encoding for whole Attribute keys or
values. This sacrifices flexibility (you always have to quote whole keys or
values) for the sake of robustness (even against URL encoding :-)).
Have a look at the patch below with introduces a "new" eldap_quote_dn() and
eliminates the special DN encoding part in eldap_quote().
Please let me know, if I am right with this approach.
Here are some string tests with this encoding:
./exim -be '${quote_ldap_dn: marian}'
%23206D617269616E
./exim -be '${quote_ldap_dn:marian}'
marian
./exim -be '${quote_ldap_dn:marian010}'
marian010
./exim -be '${quote_ldap_dn:marian010,5}'
%236D617269616E3031302C35
--- src/lookups/ldap-ph.c Wed Mar 26 17:01:00 2003
+++ src/lookups/ldap.c Fri Mar 28 14:36:49 2003
@@ -1124,30 +1124,23 @@
, + " \ < > ;
- must be quoted by backslashing. Leading and trailing spaces must be
- escaped, as must a leading #. Then the string must be URL-quoted. This type
+ must be quoted to a hexstring leaded by a hash-sign.
+ See RFC 1485 for details.
+ Then the string must be URL-quoted. This type
of quoting is implemented by ${quote_ldap_dn:....}.
+ The hash-sign must be hexified and preceded by %.
-For URL quoting, the only characters that need not be quoted are the
-alphamerics and
-
- ! $ ' ( ) * + - . _
-
-All the others must be hexified and preceded by %. This includes the
-backslashes used for LDAP quoting.
-
-For a DN that is given in the USER parameter for authentication, we need the
-same initial quoting as (2) but in this case, the result must NOT be
-URL-escaped, because it isn't a URL. The way this is handled is by
-de-URL-quoting the text when processing the USER parameter in
-control_ldap_search() above. That means that the same quote operator can be
-used. This has the additional advantage that spaces in the DN won't cause
-parsing problems. For example:
+For a DN that is given in the USER parameter for authentication, we
+need the same initial quoting as (2) but in this case, the result (the
+hash sign) must NOT be URL-escaped, because it isn't a URL. The way
+this is handled is by de-URL-quoting the text when processing the USER
+parameter in control_ldap_search() above. That means that the same
+quote operator can be used. This has the additional advantage that
+spaces in the DN won't cause parsing problems. For example:
USER=cn=${quote_ldap_dn:$1},%20dc=example,%20dc=com
-should be safe if there are spaces in $1.
-
+NOTE: RFC 1485 allows for the relative safe hex string encoding only for *whole* strings. There is no characterwise quoting (except raw hexification of each character and manual prefixing with the hash sign).
Arguments:
s the string to be quoted
@@ -1173,9 +1166,41 @@
quote_ldap_dn, respectively. */
#define LDAP_QUOTE "*()\\"
-#define LDAP_DN_QUOTE ",+\"\\<>;"
-
+uschar *
+eldap_quote_dn(uschar *s)
+{
+ uschar *quoted;
+ uschar *t;
+ uschar len=0;
+ t=s;
+ int keep_unquoted=1;
+ while (*t)
+ {
+ len++;
+ if (keep_unquoted && !isalnum(*t)) keep_unquoted=0;
+ t++;
+ }
+ if (keep_unquoted)
+ {
+ quoted=store_get(len+1);
+ strcpy(quoted,s);
+ return quoted;
+ }
+ t = quoted = store_get(2*len+4); /* 3 for the hash and 1 for NUL */
+ if (!quoted) return NULL;
+ if (!len) {
+ *t='\0';
+ return quoted;
+ }
+ sprintf(t,"%%%02X",'#'); t+=3; /* escape the hash sign for URL encoding */
+ while (*s)
+ {
+ sprintf(t,"%02X",*s++);
+ t+=2;
+ }
+ return quoted;
+}
uschar *
eldap_quote(uschar *s, uschar *opt)
@@ -1183,7 +1208,6 @@
register int c;
int count = 0;
int len;
-BOOL dn = FALSE;
uschar *t = s;
uschar *quoted;
@@ -1192,7 +1216,7 @@
if (opt != NULL)
{
if (Ustrcmp(opt, "dn") != 0) return NULL; /* No others recognized */
- dn = TRUE;
+ return eldap_quote_dn(s);
}
/* Compute how much extra store we need for the string. This doesn't have to be
@@ -1217,8 +1241,6 @@
/* Handle plain quote_ldap */
-if (!dn)
- {
while ((c = *s++) != 0)
{
if (!isalnum(c))
@@ -1238,57 +1260,6 @@
}
*t++ = c; /* unquoted character */
}
- }
-
-/* Handle quote_ldap_dn */
-
-else
- {
- uschar *ss = s + len;
-
- /* Find the last char before any trailing spaces */
-
- while (ss > s && ss[-1] == ' ') ss--;
-
- /* Quote leading spaces and sharps */
-
- for (; s < ss; s++)
- {
- if (*s != ' ' && *s != '#') break;
- sprintf(CS t, "%%5C%%%02X", *s);
- t += 6;
- }
-
- /* Handle the rest of the string, up to the trailing spaces */
-
- while (s < ss)
- {
- c = *s++;
- if (!isalnum(c))
- {
- if (Ustrchr(LDAP_DN_QUOTE, c) != NULL)
- {
- Ustrncpy(t, "%5C", 3); /* insert \ where needed */
- t += 3; /* fall through to check URL */
- }
- if (Ustrchr(URL_NONQUOTE, c) == NULL) /* e.g. ] => %5D */
- {
- sprintf(CS t, "%%%02X", c);
- t += 3;
- continue;
- }
- }
- *t++ = c; /* unquoted character, or non-URL quoted after %5C */
- }
-
- /* Handle the trailing spaces */
-
- while (*ss++ != 0)
- {
- Ustrncpy(t, "%5C%20", 6);
- t += 6;
- }
- }
/* Terminate the new string and return */
--
Mit freundlichen Gruessen / Yours sincerely
Marian Eichholz
Postmaster
freenet.de AG Vorsitzender des Aufsichtsrates: Prof. Dr. Helmut Thoma
Deelbögenkamp 4c Vorstand: Eckhard Spoerr (Vors.), Axel Krieger
22297 Hamburg Amtsgericht Hamburg, HRB 74048