diff options
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | encoding/apr_escape.c | 68 | ||||
-rw-r--r-- | include/apr_escape.h | 25 | ||||
-rw-r--r-- | test/testescape.c | 12 | ||||
-rw-r--r-- | tools/gen_test_char.c | 10 |
5 files changed, 117 insertions, 1 deletions
@@ -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) ? ',' : ' '); } |