summaryrefslogtreecommitdiff
path: root/main/utils.c
diff options
context:
space:
mode:
authorKevin Harwell <kharwell@digium.com>2015-06-08 09:44:04 -0500
committerKevin Harwell <kharwell@digium.com>2015-06-08 09:44:04 -0500
commit53c1126090733d8d4e6ee06e2ef92dc98bb0f374 (patch)
treef9597ec0362307ee798469749c1d9d2aeff53e22 /main/utils.c
parent8785d0ccbfa1959d1ba6be8769e9d5356f3fef32 (diff)
AMI: Escape string values.
So this issue is a bit complicated. Since it is possible to pass values to AMI that contain a '\r\n' (or other similar sequences) these values need to be escaped. One way to solve this is to escape the values and then pass the escaped values to the AMI variable parameter string building function. However, this puts the onus on the pre-build function to escape all string values. This potentially requires a fair amount of changes along with a lot of string allocations/freeing for all values. Surely there is a way to push this complexity down a level into the string building function itself? This of course is possible, but ends up requiring a way to distinguish between strings that need to be escaped and those that don't. The best way to handle this is by introducing a new format specifier in the format string. For instance a %s (no escape) and %S (escape). However, that is a bit weird and unexpected. So faced with those possibilities this patch implements a limited version of the first option. Instead of attempting to escape all string values this patch only escapes those values that make sense. This approach limits the number of changes and doesn't suffer from the odd format specifier problem. ASTERISK-24934 #close Reported by: warren smith Change-Id: Ib55a5b84fe0481b0f2caaaab68c566f392c0aac0
Diffstat (limited to 'main/utils.c')
-rw-r--r--main/utils.c108
1 files changed, 108 insertions, 0 deletions
diff --git a/main/utils.c b/main/utils.c
index b1b7ac9af..3bf2c5176 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1618,6 +1618,114 @@ char *ast_unescape_c(char *src)
return ret;
}
+/*
+ * Standard escape sequences - Note, '\0' is not included as a valid character
+ * to escape, but instead is used here as a NULL terminator for the string.
+ */
+char escape_sequences[] = {
+ '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\'', '\"', '\?', '\0'
+};
+
+/*
+ * Standard escape sequences output map (has to maintain matching order with
+ * escape_sequences). '\0' is included here as a NULL terminator for the string.
+ */
+static char escape_sequences_map[] = {
+ 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"', '?', '\0'
+};
+
+char* ast_escape(char *dest, const char *s, size_t num, const char *to_escape)
+{
+ char *p;
+
+ if (!dest || ast_strlen_zero(s)) {
+ return dest;
+ }
+
+ if (ast_strlen_zero(to_escape)) {
+ ast_copy_string(dest, s, num);
+ return dest;
+ }
+
+ for (p = dest; *s && num--; ++s, ++p) {
+ /* If in the list of characters to escape then escape it */
+ if (strchr(to_escape, *s)) {
+ /*
+ * See if the character to escape is part of the standard escape
+ * sequences. If so we'll have to use its mapped counterpart
+ * otherwise just use the current character.
+ */
+ char *c = strchr(escape_sequences, *s);
+ *p++ = '\\';
+ *p = c ? escape_sequences_map[c - escape_sequences] : *s;
+ } else {
+ *p = *s;
+ }
+ }
+
+ *p = '\0';
+ return dest;
+}
+
+char* ast_escape_c(char *dest, const char *s, size_t num)
+{
+ /*
+ * Note - This is an optimized version of ast_escape. When looking only
+ * for escape_sequences a couple of checks used in the generic case can
+ * be left out thus making it slightly more efficient.
+ */
+ char *p;
+
+ if (!dest || ast_strlen_zero(s)) {
+ return dest;
+ }
+
+ for (p = dest; *s && num--; ++s, ++p) {
+ /*
+ * See if the character to escape is part of the standard escape
+ * sequences. If so use its mapped counterpart.
+ */
+ char *c = strchr(escape_sequences, *s);
+ if (c) {
+ *p++ = '\\';
+ *p = escape_sequences_map[c - escape_sequences];
+ } else {
+ *p = *s;
+ }
+ }
+
+ *p = '\0';
+ return dest;
+}
+
+static char *escape_alloc(const char *s, size_t *size)
+{
+ if (!s || !(*size = strlen(s))) {
+ return NULL;
+ }
+
+ /*
+ * The result string needs to be twice the size of the given
+ * string just in case every character in it needs to be escaped.
+ */
+ *size = *size * 2 + 1;
+ return ast_calloc(sizeof(char), *size);
+}
+
+char *ast_escape_alloc(const char *s, const char *to_escape)
+{
+ size_t size = 0;
+ char *dest = escape_alloc(s, &size);
+ return ast_escape(dest, s, size, to_escape);
+}
+
+char *ast_escape_c_alloc(const char *s)
+{
+ size_t size = 0;
+ char *dest = escape_alloc(s, &size);
+ return ast_escape_c(dest, s, size);
+}
+
int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
{
int result;