summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rw-r--r--encoding/apr_escape.c68
-rw-r--r--include/apr_escape.h25
-rw-r--r--test/testescape.c12
-rw-r--r--tools/gen_test_char.c10
5 files changed, 117 insertions, 1 deletions
diff --git a/CHANGES b/CHANGES
index b92c1228c..604f54e6e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
-*- coding: utf-8 -*-
Changes for APR 2.0.0
+ *) Add apr_escape_ldap() and apr_pescape_ldap(), escaping characters
+ as described by RFC4514 and RFC4515 respectively. [Graham Leggett]
+
*) Add apr_sockaddr_info_copy(), for making a deep copy of an
apr_sockaddr_t into a specified pool. [Yann Ylavic
<ylavic.dev gmail.com>]
diff --git a/encoding/apr_escape.c b/encoding/apr_escape.c
index 2bcfec418..33705c739 100644
--- a/encoding/apr_escape.c
+++ b/encoding/apr_escape.c
@@ -1179,3 +1179,71 @@ APR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str,
return NULL;
}
+
+APR_DECLARE(apr_status_t) apr_escape_ldap(char *escaped, const void *str,
+ apr_ssize_t slen, apr_size_t *len)
+{
+ apr_size_t size = 1;
+ int found = 0;
+ const unsigned char *s = (const unsigned char *) str;
+ unsigned char *d = (unsigned char *) escaped;
+ unsigned c;
+
+ if (s) {
+ if (d) {
+ while (((c = *s) && slen) || (slen > 0)) {
+ if (TEST_CHAR(c, T_ESCAPE_LDAP)) {
+ d = c2x(c, '\\', d);
+ size += 2;
+ found = 1;
+ }
+ else {
+ *d++ = c;
+ }
+ ++s;
+ size++;
+ slen--;
+ }
+ *d = '\0';
+ }
+ else {
+ while (((c = *s) && slen) || (slen > 0)) {
+ if (TEST_CHAR(c, T_ESCAPE_LDAP)) {
+ size += 2;
+ found = 1;
+ }
+ ++s;
+ size++;
+ slen--;
+ }
+ }
+ }
+
+ if (len) {
+ *len = size;
+ }
+ if (!found) {
+ return APR_NOTFOUND;
+ }
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(const char *) apr_pescape_ldap(apr_pool_t *p, const void *src, apr_ssize_t srclen)
+{
+ apr_size_t len;
+
+ switch (apr_escape_ldap(NULL, src, srclen, &len)) {
+ case APR_SUCCESS: {
+ char *encoded = apr_palloc(p, len);
+ apr_escape_ldap(encoded, src, srclen, NULL);
+ return encoded;
+ }
+ case APR_NOTFOUND: {
+ break;
+ }
+ }
+
+ return src;
+}
+
diff --git a/include/apr_escape.h b/include/apr_escape.h
index 17422b3a1..f1968be0c 100644
--- a/include/apr_escape.h
+++ b/include/apr_escape.h
@@ -366,6 +366,31 @@ APR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str,
APR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str,
int colon, apr_size_t *len);
+/**
+ * Apply LDAP escaping to binary data. Characters from RFC4514 and RFC4515
+ * are escaped with their hex equivalents.
+ * @param dest The destination buffer, can be NULL
+ * @param src The original buffer
+ * @param srclen The length of the original buffer
+ * @param len If present, returns the length of the string
+ * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL
+ */
+APR_DECLARE(apr_status_t) apr_escape_ldap(char *dest, const void *src,
+ apr_ssize_t srclen, apr_size_t *len);
+
+/**
+ * Apply LDAP escaping to binary data, and return the results from a
+ * pool. Characters from RFC4514 and RFC4515 are escaped with their hex
+ * equivalents.
+ * @param p Pool to allocate from
+ * @param src The original buffer
+ * @param slen The length of the original buffer
+ * @return A zero padded buffer allocated from the pool on success, or
+ * NULL if src was NULL.
+ */
+APR_DECLARE(const char *) apr_pescape_ldap(apr_pool_t *p, const void *src,
+ apr_ssize_t slen) __attribute__((nonnull(1)));
+
/** @} */
#ifdef __cplusplus
}
diff --git a/test/testescape.c b/test/testescape.c
index 323ff5618..8d537de0e 100644
--- a/test/testescape.c
+++ b/test/testescape.c
@@ -262,6 +262,18 @@ static void test_escape(abts_case *tc, void *data)
apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, (apr_size_t)4),
(len == 4));
+ src = "Parens R Us (for all your parenthetical needs) plus asterisk* \"+,;<>\\";
+ target = "Parens R Us \\28for all your parenthetical needs\\29 plus asterisk\\2a \\22\\2b\\2c\\3b\\3c\\3e\\5c";
+ dest = apr_pescape_ldap(pool, src, APR_ESCAPE_STRING);
+ ABTS_ASSERT(tc,
+ apr_psprintf(pool, "shell escaped (%s) does not match expected output (%s)",
+ dest, target),
+ (strcmp(dest, target) == 0));
+ apr_escape_ldap(NULL, src, APR_ESCAPE_STRING, &len);
+ ABTS_ASSERT(tc,
+ apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1),
+ (len == strlen(dest) + 1));
+
apr_pool_destroy(pool);
}
diff --git a/tools/gen_test_char.c b/tools/gen_test_char.c
index 811c802f2..156b33145 100644
--- a/tools/gen_test_char.c
+++ b/tools/gen_test_char.c
@@ -32,6 +32,7 @@
#define T_ESCAPE_ECHO (0x08)
#define T_ESCAPE_URLENCODED (0x10)
#define T_ESCAPE_XML (0x20)
+#define T_ESCAPE_LDAP (0x40)
int main(int argc, char *argv[])
{
@@ -46,6 +47,7 @@ int main(int argc, char *argv[])
"#define T_ESCAPE_ECHO (%u)\n"
"#define T_ESCAPE_URLENCODED (%u)\n"
"#define T_ESCAPE_XML (%u)\n"
+ "#define T_ESCAPE_LDAP (%u)\n"
"\n"
"static const unsigned char test_char_table[256] = {",
T_ESCAPE_SHELL_CMD,
@@ -53,7 +55,8 @@ int main(int argc, char *argv[])
T_OS_ESCAPE_PATH,
T_ESCAPE_ECHO,
T_ESCAPE_URLENCODED,
- T_ESCAPE_XML);
+ T_ESCAPE_XML,
+ T_ESCAPE_LDAP);
for (c = 0; c < 256; ++c) {
flags = 0;
@@ -106,6 +109,11 @@ int main(int argc, char *argv[])
flags |= T_ESCAPE_XML;
}
+ /* LDAP DN escaping (RFC4514) and LDAP filter escaping (RFC4515) */
+ if (!isprint(c) || strchr("\"+,;<>\\", c) || strchr("*()\\", c)) {
+ flags |= T_ESCAPE_LDAP;
+ }
+
printf("%u%c", flags, (c < 255) ? ',' : ' ');
}