aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/util.c67
-rw-r--r--src/common/util.h4
-rw-r--r--src/test/test_util.c50
3 files changed, 121 insertions, 0 deletions
diff --git a/src/common/util.c b/src/common/util.c
index 93e2ba8e1..b2f12bfb6 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -865,6 +865,36 @@ tor_digest_is_zero(const char *digest)
return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN);
}
+/** Return true if <b>string</b> is a valid '<key>=<value>' string.
+ * <value> is optional, to indicate the empty string. */
+int
+string_is_key_value(const char *string)
+{
+ /* position of equal sign in string */
+ char *equal_sign_pos = NULL;
+
+ tor_assert(string);
+
+ if (strlen(string) < 2) { /* "x=a" is shortest args string */
+ log_warn(LD_GENERAL, "'%s' is too short to be a k=v value.", string);
+ return 0;
+ }
+
+ equal_sign_pos = strchr(string, '=');
+ if (!equal_sign_pos) {
+ log_warn(LD_GENERAL, "'%s' is not a k=v value.", string);
+ return 0;
+ }
+
+ /* validate that the '=' is not in the beginning of the string. */
+ if (equal_sign_pos == string) {
+ log_warn(LD_GENERAL, "'%s' is not a valid k=v value.", string);
+ return 0;
+ }
+
+ return 1;
+}
+
/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */
int
tor_digest256_is_zero(const char *digest)
@@ -1249,6 +1279,43 @@ wrap_string(smartlist_t *out, const char *string, size_t width,
}
}
+/** Escape every character of <b>string</b> that belongs to the set of
+ * characters <b>set</b>. Use <b>escape_char</b> as the character to
+ * use for escaping. */
+char *
+tor_escape_str_for_socks_arg(const char *string)
+{
+ char *new_string = NULL;
+ char *new_cp = NULL;
+ size_t length, new_length;
+ static const char *chars_to_escape = ";\\";
+
+ tor_assert(string);
+
+ length = strlen(string);
+
+ if (!length)
+ return NULL;
+ /* (new_length > SIZE_MAX) => ((length * 2) + 1 > SIZE_MAX) =>
+ (length*2 > SIZE_MAX - 1) => (length > (SIZE_MAX - 1)/2) */
+ if (length > (SIZE_MAX - 1)/2) /* check for overflow */
+ return NULL;
+
+ /* this should be enough even if all characters must be escaped */
+ new_length = (length * 2) + 1;
+
+ new_string = new_cp = tor_malloc_zero(new_length);
+
+ while (*string) {
+ if (strchr(chars_to_escape, *string))
+ *new_cp++ = '\\';
+
+ *new_cp++ = *string++;
+ }
+
+ return new_string;
+}
+
/* =====
* Time
* ===== */
diff --git a/src/common/util.h b/src/common/util.h
index 911b1b5a3..e3cd72118 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -209,12 +209,16 @@ const char *find_whitespace_eos(const char *s, const char *eos);
const char *find_str_at_start_of_line(const char *haystack,
const char *needle);
int string_is_C_identifier(const char *string);
+int string_is_key_value(const char *string);
int tor_mem_is_zero(const char *mem, size_t len);
int tor_digest_is_zero(const char *digest);
int tor_digest256_is_zero(const char *digest);
char *esc_for_log(const char *string) ATTR_MALLOC;
const char *escaped(const char *string);
+
+char *tor_escape_str_for_socks_arg(const char *string);
+
struct smartlist_t;
void wrap_string(struct smartlist_t *out, const char *string, size_t width,
const char *prefix0, const char *prefixRest);
diff --git a/src/test/test_util.c b/src/test/test_util.c
index bed33fac2..b41f23571 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -795,6 +795,54 @@ test_util_expand_filename(void)
}
#endif
+/** Test tor_escape_str_for_socks_arg(). */
+static void
+test_util_escape_string_socks(void)
+{
+ char *escaped_string = NULL;
+
+ /** Simple backslash escape. */
+ escaped_string = tor_escape_str_for_socks_arg("This is a backslash: \\");
+ test_assert(escaped_string);
+ test_streq(escaped_string, "This is a backslash: \\\\");
+ tor_free(escaped_string);
+
+ /** Simple semicolon escape. */
+ escaped_string = tor_escape_str_for_socks_arg("First rule: Do not use ;");
+ test_assert(escaped_string);
+ test_streq(escaped_string, "First rule: Do not use \\;");
+ tor_free(escaped_string);
+
+ /** Ilegal: Empty string. */
+ escaped_string = tor_escape_str_for_socks_arg("");
+ test_assert(!escaped_string);
+
+ /** Escape all characters. */
+ escaped_string = tor_escape_str_for_socks_arg(";\\;\\");
+ test_assert(escaped_string);
+ test_streq(escaped_string, "\\;\\\\\\;\\\\");
+ tor_free(escaped_string);
+
+ done:
+ tor_free(escaped_string);
+}
+
+static void
+test_util_string_is_key_value(void *ptr)
+{
+ (void)ptr;
+ test_assert(string_is_key_value("key=value"));
+ test_assert(string_is_key_value("k=v"));
+ test_assert(string_is_key_value("key="));
+ test_assert(!string_is_key_value("=value"));
+ test_assert(!string_is_key_value("="));
+
+ /* ??? */
+ /* test_assert(!string_is_key_value("===")); */
+ done:
+ ;
+}
+
/** Test basic string functionality. */
static void
test_util_strmisc(void)
@@ -3271,6 +3319,8 @@ struct testcase_t util_tests[] = {
#ifndef _WIN32
UTIL_LEGACY(expand_filename),
#endif
+ UTIL_LEGACY(escape_string_socks),
+ UTIL_LEGACY(string_is_key_value),
UTIL_LEGACY(strmisc),
UTIL_LEGACY(pow2),
UTIL_LEGACY(gzip),