From: Jonathan Rose Date: Thu, 9 Jun 2011 14:06:42 +0000 (+0000) Subject: Adds ast_escape_encoded utility to properly handle escaping of quoted field before... X-Git-Tag: 1.8.5-rc1~11^2~47 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5f46b994f47c8a1d1bc99682810ce7e1dafe306c;p=thirdparty%2Fasterisk.git Adds ast_escape_encoded utility to properly handle escaping of quoted field before uri. This commit backports a feature in trunk affecting initreqprep so that display name won't be encoded improperly. Also includes unit tests for the ast_escape_quoted function. This patch gives 1.8 a much improved outlook in countries which don't use standard ASCII characters. (closes issue ASTERISK-16949) Reported by: Örn Arnarson Review: https://reviewboard.asterisk.org/r/1235/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@322585 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 457b088d4d..ad8997e8bf 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -11537,7 +11537,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho ast_string_field_set(p, fromname, n); if (sip_cfg.pedanticsipchecking) { - ast_uri_encode(n, tmp_n, sizeof(tmp_n), 0); + ast_escape_quoted(n, tmp_n, sizeof(tmp_n)); n = tmp_n; ast_uri_encode(l, tmp_l, sizeof(tmp_l), 0); l = tmp_l; diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 7b75db808f..ed71441e5c 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -273,6 +273,19 @@ char *ast_uri_encode(const char *string, char *outbuf, int buflen, int do_specia */ void ast_uri_decode(char *s); +/*! + * \brief Escape characters found in a quoted string. + * + * \note This function escapes quoted characters based on the 'qdtext' set of + * allowed characters from RFC 3261 section 25.1. + * + * \param string string to be escaped + * \param outbuf resulting escaped string + * \param buflen size of output buffer + * \return a pointer to the escaped string + */ +char *ast_escape_quoted(const char *string, char *outbuf, int buflen); + static force_inline void ast_slinear_saturated_add(short *input, short *value) { int res; diff --git a/main/utils.c b/main/utils.c index bd6805b16d..0872876f5b 100644 --- a/main/utils.c +++ b/main/utils.c @@ -415,6 +415,37 @@ char *ast_uri_encode(const char *string, char *outbuf, int buflen, int do_specia return outbuf; } +/*! \brief escapes characters specified for quoted portions of sip messages */ +char *ast_escape_quoted(const char *string, char *outbuf, int buflen) +{ + const char *ptr = string; + char *out = outbuf; + char *allow = "\t\v !"; /* allow LWS (minus \r and \n) and "!" */ + + while (*ptr && out - outbuf < buflen - 1) { + if (!(strchr(allow, *ptr)) + && !(*ptr >= '#' && *ptr <= '[') /* %x23 - %x5b */ + && !(*ptr >= ']' && *ptr <= '~') /* %x5d - %x7e */ + && !((unsigned char) *ptr > 0x7f)) { /* UTF8-nonascii */ + + if (out - outbuf >= buflen - 2) { + break; + } + out += sprintf(out, "\\%c", (unsigned char) *ptr); + } else { + *out = *ptr; + out++; + } + ptr++; + } + + if (buflen) { + *out = '\0'; + } + + return outbuf; +} + /*! \brief ast_uri_decode: Decode SIP URI, URN, URL (overwrite the string) */ void ast_uri_decode(char *s) { diff --git a/tests/test_utils.c b/tests/test_utils.c index b7a368a7d0..a4852f6b34 100644 --- a/tests/test_utils.c +++ b/tests/test_utils.c @@ -102,6 +102,54 @@ AST_TEST_DEFINE(uri_encode_decode_test) return res; } +AST_TEST_DEFINE(quoted_escape_test) +{ + int res = AST_TEST_PASS; + const char *in = "a\"bcdefg\"hijkl\\mnopqrs tuv\twxyz"; + char out[256] = { 0 }; + char small[4] = { 0 }; + int i; + + static struct { + char *buf; + const size_t buflen; + + const char *output; + } tests[] = { + {0, sizeof(out), + "a\\\"bcdefg\\\"hijkl\\\\mnopqrs tuv\twxyz"}, + {0, sizeof(small), + "a\\\""}, + }; + + tests[0].buf = out; + tests[1].buf = small; + + switch (cmd) { + case TEST_INIT: + info->name = "quoted_escape_test"; + info->category = "/main/utils/"; + info->summary = "escape a quoted string"; + info->description = "Escape a string to be quoted and check the result."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + for (i = 0; i < ARRAY_LEN(tests); i++) { + ast_escape_quoted(in, tests[i].buf, tests[i].buflen); + if (strcmp(tests[i].output, tests[i].buf)) { + ast_test_status_update(test, "ESCAPED DOES NOT MATCH EXPECTED, FAIL\n"); + ast_test_status_update(test, "original: %s\n", in); + ast_test_status_update(test, "expected: %s\n", tests[i].output); + ast_test_status_update(test, "result: %s\n", tests[i].buf); + res = AST_TEST_FAIL; + } + } + + return res; +} + AST_TEST_DEFINE(md5_test) { static const struct { @@ -348,6 +396,7 @@ AST_TEST_DEFINE(agi_loaded_test) static int unload_module(void) { AST_TEST_UNREGISTER(uri_encode_decode_test); + AST_TEST_UNREGISTER(quoted_escape_test); AST_TEST_UNREGISTER(md5_test); AST_TEST_UNREGISTER(sha1_test); AST_TEST_UNREGISTER(base64_test); @@ -360,6 +409,7 @@ static int unload_module(void) static int load_module(void) { AST_TEST_REGISTER(uri_encode_decode_test); + AST_TEST_REGISTER(quoted_escape_test); AST_TEST_REGISTER(md5_test); AST_TEST_REGISTER(sha1_test); AST_TEST_REGISTER(base64_test);