summaryrefslogtreecommitdiff
path: root/channels/sip/reqresp_parser.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2012-01-19 23:31:17 +0000
committerRichard Mudgett <rmudgett@digium.com>2012-01-19 23:31:17 +0000
commitae32acfa3efecc59e37219ef6d39d6564354f3a3 (patch)
tree0bf853b90f1bc9ebdc91ee36447dc46aa45d2110 /channels/sip/reqresp_parser.c
parentadd6efc20cec066e753879a552f01a5e2a6058fa (diff)
Misc minor fixes in reqresp_parser.c and chan_sip.c.
* Fix corner cases in get_calleridname() parsing and ensure that the output buffer is nul terminated. * Make get_calleridname() truncate the name it parses if the given buffer is too small rather than abandoning the parse and not returning anything for the name. Adjusted get_calleridname_test() unit test to handle the truncation change. * Fix get_in_brackets_test() unit test to check the results of get_in_brackets() correctly. * Fix parse_name_andor_addr() to not return the address of a local buffer. This function is currently not used. * Fix potential NULL pointer dereference in sip_sendtext(). * No need to memset(calleridname) in check_user_full() or tmp_name in get_name_and_number() because get_calleridname() ensures that it is nul terminated. * Reply with an accurate response if get_msg_text() fails in receive_message(). This is academic in v1.8 because get_msg_text() can never fail. ........ Merged revisions 351618 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 351646 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@351667 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels/sip/reqresp_parser.c')
-rw-r--r--channels/sip/reqresp_parser.c200
1 files changed, 117 insertions, 83 deletions
diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c
index d135e0073..b646f7bbb 100644
--- a/channels/sip/reqresp_parser.c
+++ b/channels/sip/reqresp_parser.c
@@ -685,63 +685,77 @@ const char *get_calleridname(const char *input, char *output, size_t outputsize)
char *orig_output = output;
const char *orig_input = input;
+ if (!output || !outputsize) {
+ /* Bad output parameters. Should never happen. */
+ return input;
+ }
+
/* clear any empty characters in the beginning */
input = ast_skip_blanks(input);
- /* no data at all or no storage room? */
- if (!input || *input == '<' || !outputsize || !output) {
- return orig_input;
- }
-
/* make sure the output buffer is initilized */
*orig_output = '\0';
/* make room for '\0' at the end of the output buffer */
- outputsize--;
+ --outputsize;
+
+ /* no data at all or no display name? */
+ if (!input || *input == '<') {
+ return input;
+ }
/* quoted-string rules */
if (input[0] == '"') {
input++; /* skip the first " */
- for (;((outputsize > 0) && *input); input++) {
+ for (; *input; ++input) {
if (*input == '"') { /* end of quoted-string */
break;
} else if (*input == 0x5c) { /* quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) */
- input++;
- if (!*input || (unsigned char)*input > 0x7f || *input == 0xa || *input == 0xd) {
+ ++input;
+ if (!*input) {
+ break;
+ }
+ if ((unsigned char) *input > 0x7f || *input == 0xa || *input == 0xd) {
continue; /* not a valid quoted-pair, so skip it */
}
- } else if (((*input != 0x9) && ((unsigned char) *input < 0x20)) ||
- (*input == 0x7f)) {
+ } else if ((*input != 0x9 && (unsigned char) *input < 0x20)
+ || *input == 0x7f) {
continue; /* skip this invalid character. */
}
- *output++ = *input;
- outputsize--;
+ if (0 < outputsize) {
+ /* We still have room for the output display-name. */
+ *output++ = *input;
+ --outputsize;
+ }
}
/* if this is successful, input should be at the ending quote */
- if (!input || *input != '"') {
+ if (*input != '"') {
ast_log(LOG_WARNING, "No ending quote for display-name was found\n");
*orig_output = '\0';
return orig_input;
}
/* make sure input is past the last quote */
- input++;
+ ++input;
- /* terminate outbuf */
+ /* terminate output */
*output = '\0';
} else { /* either an addr-spec or tokenLWS-combo */
- for (;((outputsize > 0) && *input); input++) {
+ for (; *input; ++input) {
/* token or WSP (without LWS) */
if ((*input >= '0' && *input <= '9') || (*input >= 'A' && *input <= 'Z')
|| (*input >= 'a' && *input <= 'z') || *input == '-' || *input == '.'
|| *input == '!' || *input == '%' || *input == '*' || *input == '_'
|| *input == '+' || *input == '`' || *input == '\'' || *input == '~'
|| *input == 0x9 || *input == ' ') {
- *output++ = *input;
- outputsize -= 1;
+ if (0 < outputsize) {
+ /* We still have room for the output display-name. */
+ *output++ = *input;
+ --outputsize;
+ }
} else if (*input == '<') { /* end of tokenLWS-combo */
/* we could assert that the previous char is LWS, but we don't care */
break;
@@ -759,10 +773,10 @@ const char *get_calleridname(const char *input, char *output, size_t outputsize)
return orig_input;
}
- /* set NULL while trimming trailing whitespace */
+ /* terminate output while trimming any trailing whitespace */
do {
*output-- = '\0';
- } while (*output == 0x9 || *output == ' '); /* we won't go past orig_output as first was a non-space */
+ } while (orig_output <= output && (*output == 0x9 || *output == ' '));
}
return input;
@@ -771,11 +785,12 @@ const char *get_calleridname(const char *input, char *output, size_t outputsize)
AST_TEST_DEFINE(get_calleridname_test)
{
int res = AST_TEST_PASS;
- const char *in1 = "\" quoted-text internal \\\" quote \"<stuff>";
+ const char *in1 = " \" quoted-text internal \\\" quote \"<stuff>";
const char *in2 = " token text with no quotes <stuff>";
const char *overflow1 = " \"quoted-text overflow 1234567890123456789012345678901234567890\" <stuff>";
+ const char *overflow2 = " non-quoted text overflow 1234567890123456789012345678901234567890 <stuff>";
const char *noendquote = " \"quoted-text no end <stuff>";
- const char *addrspec = " \"sip:blah@blah <stuff>";
+ const char *addrspec = " sip:blah@blah";
const char *no_quotes_no_brackets = "blah@blah";
const char *after_dname;
char dname[40];
@@ -810,11 +825,19 @@ AST_TEST_DEFINE(get_calleridname_test)
/* quoted-text buffer overflow */
after_dname = get_calleridname(overflow1, dname, sizeof(dname));
ast_test_status_update(test, "overflow display-name1: %s\nafter: %s\n", dname, after_dname);
- if (*dname != '\0' && after_dname != overflow1) {
+ if (strcmp(dname, "quoted-text overflow 123456789012345678")) {
ast_test_status_update(test, "overflow display-name1 test failed\n");
res = AST_TEST_FAIL;
}
+ /* non-quoted-text buffer overflow */
+ after_dname = get_calleridname(overflow2, dname, sizeof(dname));
+ ast_test_status_update(test, "overflow display-name2: %s\nafter: %s\n", dname, after_dname);
+ if (strcmp(dname, "non-quoted text overflow 12345678901234")) {
+ ast_test_status_update(test, "overflow display-name2 test failed\n");
+ res = AST_TEST_FAIL;
+ }
+
/* quoted-text buffer with no terminating end quote */
after_dname = get_calleridname(noendquote, dname, sizeof(dname));
ast_test_status_update(test, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname);
@@ -825,7 +848,7 @@ AST_TEST_DEFINE(get_calleridname_test)
/* addr-spec rather than display-name. */
after_dname = get_calleridname(addrspec, dname, sizeof(dname));
- ast_test_status_update(test, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname);
+ ast_test_status_update(test, "addr-spec display-name1: %s\nafter: %s\n", dname, after_dname);
if (*dname != '\0' && after_dname != addrspec) {
ast_test_status_update(test, "detection of addr-spec failed\n");
res = AST_TEST_FAIL;
@@ -839,14 +862,13 @@ AST_TEST_DEFINE(get_calleridname_test)
res = AST_TEST_FAIL;
}
-
return res;
}
int get_name_and_number(const char *hdr, char **name, char **number)
{
char header[256];
- char tmp_name[50] = { 0, };
+ char tmp_name[50];
char *tmp_number = NULL;
char *hostport = NULL;
char *dummy = NULL;
@@ -1069,14 +1091,14 @@ char *get_in_brackets(char *tmp)
AST_TEST_DEFINE(get_in_brackets_test)
{
int res = AST_TEST_PASS;
- char *in_brackets = "<sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
+ char in_brackets[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
char no_name[] = "<sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
char quoted_string[] = "\"I'm a quote stri><ng\" <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
char missing_end_quote[] = "\"I'm a quote string <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
char name_no_quotes[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
char no_end_bracket[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
char no_name_no_brackets[] = "sip:name@host";
- char missing_start_bracket[] = "name not in quotes sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
+ char missing_start_bracket[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
char *uri = NULL;
switch (cmd) {
@@ -1093,57 +1115,49 @@ AST_TEST_DEFINE(get_in_brackets_test)
}
/* Test 1, simple get in brackets */
- if (!(uri = get_in_brackets(no_name)) || !(strcmp(uri, in_brackets))) {
-
- ast_test_status_update(test, "Test 1, simple get in brackets failed.\n");
+ if (!(uri = get_in_brackets(no_name)) || strcmp(uri, in_brackets)) {
+ ast_test_status_update(test, "Test 1, simple get in brackets failed. %s\n", uri);
res = AST_TEST_FAIL;
}
/* Test 2, starts with quoted string */
- if (!(uri = get_in_brackets(quoted_string)) || !(strcmp(uri, in_brackets))) {
-
- ast_test_status_update(test, "Test 2, get in brackets with quoted string in front failed.\n");
+ if (!(uri = get_in_brackets(quoted_string)) || strcmp(uri, in_brackets)) {
+ ast_test_status_update(test, "Test 2, get in brackets with quoted string in front failed. %s\n", uri);
res = AST_TEST_FAIL;
}
/* Test 3, missing end quote */
- if (!(uri = get_in_brackets(missing_end_quote)) || !(strcmp(uri, in_brackets))) {
-
- ast_test_status_update(test, "Test 3, missing end quote failed.\n");
+ if (!(uri = get_in_brackets(missing_end_quote)) || !strcmp(uri, in_brackets)) {
+ ast_test_status_update(test, "Test 3, missing end quote failed. %s\n", uri);
res = AST_TEST_FAIL;
}
/* Test 4, starts with a name not in quotes */
- if (!(uri = get_in_brackets(name_no_quotes)) || !(strcmp(uri, in_brackets))) {
-
- ast_test_status_update(test, "Test 4, passing name not in quotes failed.\n");
+ if (!(uri = get_in_brackets(name_no_quotes)) || strcmp(uri, in_brackets)) {
+ ast_test_status_update(test, "Test 4, passing name not in quotes failed. %s\n", uri);
res = AST_TEST_FAIL;
}
/* Test 5, no end bracket, should just return everything after the first '<' */
- if (!(uri = get_in_brackets(no_end_bracket)) || !(strcmp(uri, in_brackets))) {
-
- ast_test_status_update(test, "Test 5, no end bracket failed.\n");
+ if (!(uri = get_in_brackets(no_end_bracket)) || !strcmp(uri, in_brackets)) {
+ ast_test_status_update(test, "Test 5, no end bracket failed. %s\n", uri);
res = AST_TEST_FAIL;
}
/* Test 6, NULL input */
if ((uri = get_in_brackets(NULL))) {
-
ast_test_status_update(test, "Test 6, NULL input failed.\n");
res = AST_TEST_FAIL;
}
/* Test 7, no name, and no brackets. */
- if (!(uri = get_in_brackets(no_name_no_brackets)) || (strcmp(uri, "sip:name@host"))) {
-
+ if (!(uri = get_in_brackets(no_name_no_brackets)) || strcmp(uri, "sip:name@host")) {
ast_test_status_update(test, "Test 7 failed. %s\n", uri);
res = AST_TEST_FAIL;
}
/* Test 8, no start bracket, but with ending bracket. */
- if (!(uri = get_in_brackets(missing_start_bracket)) || !(strcmp(uri, in_brackets))) {
-
+ if (!(uri = get_in_brackets(missing_start_bracket)) || strcmp(uri, in_brackets)) {
ast_test_status_update(test, "Test 8 failed. %s\n", uri);
res = AST_TEST_FAIL;
}
@@ -1158,20 +1172,42 @@ int parse_name_andor_addr(char *uri, const char *scheme, char **name,
char **residue)
{
char buf[1024];
- char **residue2=residue;
+ char **residue2 = residue;
+ char *orig_uri = uri;
int ret;
+
+ buf[0] = '\0';
if (name) {
- get_calleridname(uri,buf,sizeof(buf));
- *name = buf;
+ uri = (char *) get_calleridname(uri, buf, sizeof(buf));
}
- ret = get_in_brackets_full(uri,&uri,residue);
- if (ret == 0) { /* uri is in brackets so do not treat unknown trailing uri parameters as potential messageheader parameters */
- *residue = *residue + 1; /* step over the first semicolon so as per parse uri residue */
+ ret = get_in_brackets_full(uri, &uri, residue);
+ if (ret == 0) {
+ /*
+ * The uri is in brackets so do not treat unknown trailing uri
+ * parameters as potential message header parameters.
+ */
+ if (residue && **residue) {
+ /* step over the first semicolon as per parse_uri_full residue */
+ *residue = *residue + 1;
+ }
residue2 = NULL;
}
- return parse_uri_full(uri, scheme, user, pass, hostport, params, headers,
- residue2);
+ if (name) {
+ if (buf[0]) {
+ /*
+ * There is always room at orig_uri for the display-name because
+ * at least one character has always been removed. A '"' or '<'
+ * has been removed.
+ */
+ strcpy(orig_uri, buf);
+ *name = orig_uri;
+ } else {
+ *name = "";
+ }
+ }
+
+ return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2);
}
AST_TEST_DEFINE(parse_name_andor_addr_test)
@@ -1313,7 +1349,7 @@ AST_TEST_DEFINE(parse_name_andor_addr_test)
name = user = pass = hostport = headers = residue = NULL;
params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
params.lr = 0;
- ast_copy_string(uri,testdataptr->uri,sizeof(uri));
+ ast_copy_string(uri,testdataptr->uri,sizeof(uri));
if (parse_name_andor_addr(uri, "sip:,sips:",
testdataptr->nameptr,
testdataptr->userptr,
@@ -1330,17 +1366,17 @@ AST_TEST_DEFINE(parse_name_andor_addr_test)
((testdataptr->residueptr) && strcmp(testdataptr->residue, residue)) ||
((testdataptr->paramsptr) && strcmp(testdataptr->params.transport,params.transport)) ||
((testdataptr->paramsptr) && strcmp(testdataptr->params.user,params.user))
- ) {
- ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
- res = AST_TEST_FAIL;
+ ) {
+ ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
+ res = AST_TEST_FAIL;
}
}
-
return res;
}
-int get_comma(char *in, char **out) {
+int get_comma(char *in, char **out)
+{
char *c;
char *parse = in;
if (out) {
@@ -1376,35 +1412,35 @@ int get_comma(char *in, char **out) {
return 1;
}
-int parse_contact_header(char *contactheader, struct contactliststruct *contactlist) {
+int parse_contact_header(char *contactheader, struct contactliststruct *contactlist)
+{
int res;
int last;
char *comma;
char *residue;
char *param;
char *value;
- struct contact *contact=NULL;
+ struct contact *split_contact = NULL;
if (*contactheader == '*') {
return 1;
}
- contact = malloc(sizeof(*contact));
-
- AST_LIST_HEAD_SET_NOLOCK(contactlist, contact);
- while ((last = get_comma(contactheader,&comma)) != -1) {
+ split_contact = ast_calloc(1, sizeof(*split_contact));
+ AST_LIST_HEAD_SET_NOLOCK(contactlist, split_contact);
+ while ((last = get_comma(contactheader, &comma)) != -1) {
res = parse_name_andor_addr(contactheader, "sip:,sips:",
- &contact->name, &contact->user,
- &contact->pass, &contact->hostport,
- &contact->params, &contact->headers,
- &residue);
+ &split_contact->name, &split_contact->user,
+ &split_contact->pass, &split_contact->hostport,
+ &split_contact->params, &split_contact->headers,
+ &residue);
if (res == -1) {
return res;
}
/* parse contact params */
- contact->expires = contact->q = "";
+ split_contact->expires = split_contact->q = "";
while ((value = strchr(residue,'='))) {
*value++ = '\0';
@@ -1417,20 +1453,19 @@ int parse_contact_header(char *contactheader, struct contactliststruct *contactl
}
if (!strcmp(param,"expires")) {
- contact->expires = value;
+ split_contact->expires = value;
} else if (!strcmp(param,"q")) {
- contact->q = value;
+ split_contact->q = value;
}
}
- if(last) {
+ if (last) {
return 0;
}
contactheader = comma;
- contact = malloc(sizeof(*contact));
- AST_LIST_INSERT_TAIL(contactlist, contact, list);
-
+ split_contact = ast_calloc(1, sizeof(*split_contact));
+ AST_LIST_INSERT_TAIL(contactlist, split_contact, list);
}
return last;
}
@@ -1563,16 +1598,15 @@ AST_TEST_DEFINE(parse_contact_header_test)
strcmp(tdcontactptr->params.transport, contactptr->params.transport) ||
strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) ||
(tdcontactptr->params.lr != contactptr->params.lr)
- ) {
+ ) {
ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
res = AST_TEST_FAIL;
break;
}
- contactptr = AST_LIST_NEXT(contactptr,list);
+ contactptr = AST_LIST_NEXT(contactptr,list);
}
}
-
}
return res;