#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/res_pjsip_cli.h"
+#include "asterisk/test.h"
+#include "asterisk/res_pjsip_presence_xml.h"
/*** MODULEINFO
<depend>pjproject</depend>
}
}
+AST_TEST_DEFINE(xml_sanitization_end_null)
+{
+ char sanitized[8];
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "xml_sanitization_end_null";
+ info->category = "/res/res_pjsip/";
+ info->summary = "Ensure XML sanitization works as expected with a long string";
+ info->description = "This test sanitizes a string which exceeds the output\n"
+ "buffer size. Once done the string is confirmed to be NULL terminated.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ ast_sip_sanitize_xml("aaaaaaaaaaaa", sanitized, sizeof(sanitized));
+ if (sanitized[7] != '\0') {
+ ast_test_status_update(test, "Sanitized XML string is not null-terminated when it should be\n");
+ return AST_TEST_FAIL;
+ }
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(xml_sanitization_exceeds_buffer)
+{
+ char sanitized[8];
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "xml_sanitization_exceeds_buffer";
+ info->category = "/res/res_pjsip/";
+ info->summary = "Ensure XML sanitization does not exceed buffer when output won't fit";
+ info->description = "This test sanitizes a string which before sanitization would\n"
+ "fit within the output buffer. After sanitization, however, the string would\n"
+ "exceed the buffer. Once done the string is confirmed to be NULL terminated.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ ast_sip_sanitize_xml("<><><>&", sanitized, sizeof(sanitized));
+ if (sanitized[7] != '\0') {
+ ast_test_status_update(test, "Sanitized XML string is not null-terminated when it should be\n");
+ return AST_TEST_FAIL;
+ }
+
+ return AST_TEST_PASS;
+}
+
/*!
* \internal
* \brief Reload configuration within a PJSIP thread
ast_res_pjsip_init_options_handling(0);
ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
+ AST_TEST_REGISTER(xml_sanitization_end_null);
+ AST_TEST_REGISTER(xml_sanitization_exceeds_buffer);
+
return AST_MODULE_LOAD_SUCCESS;
}
static int unload_module(void)
{
+ AST_TEST_UNREGISTER(xml_sanitization_end_null);
+ AST_TEST_UNREGISTER(xml_sanitization_exceeds_buffer);
+
/* The thread this is called from cannot call PJSIP/PJLIB functions,
* so we have to push the work to the threadpool to handle
*/
{
char *copy = ast_strdupa(input);
char *break_point;
+ size_t remaining = len - 1;
output[0] = '\0';
- while ((break_point = strpbrk(copy, "<>\"&'\n\r"))) {
+ while ((break_point = strpbrk(copy, "<>\"&'\n\r")) && remaining) {
char to_escape = *break_point;
*break_point = '\0';
- strncat(output, copy, len);
+ strncat(output, copy, remaining);
+
+ /* The strncat function will write remaining+1 if the string length is
+ * equal to or greater than the size provided to it. We take this into
+ * account by subtracting 1, which ensures that the NULL byte is written
+ * inside of the provided buffer.
+ */
+ remaining = len - strlen(output) - 1;
switch (to_escape) {
case '<':
- strncat(output, "<", len);
+ strncat(output, "<", remaining);
break;
case '>':
- strncat(output, ">", len);
+ strncat(output, ">", remaining);
break;
case '"':
- strncat(output, """, len);
+ strncat(output, """, remaining);
break;
case '&':
- strncat(output, "&", len);
+ strncat(output, "&", remaining);
break;
case '\'':
- strncat(output, "'", len);
+ strncat(output, "'", remaining);
break;
case '\r':
- strncat(output, " ", len);
+ strncat(output, " ", remaining);
break;
case '\n':
- strncat(output, " ", len);
+ strncat(output, " ", remaining);
break;
};
copy = break_point + 1;
+ remaining = len - strlen(output) - 1;
}
/* Be sure to copy everything after the final bracket */
- if (*copy) {
- strncat(output, copy, len);
+ if (*copy && remaining) {
+ strncat(output, copy, remaining);
}
}