|
@@ -0,0 +1,132 @@
|
|
|
+/* Copyright (c) 2003, Roger Dingledine
|
|
|
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
|
|
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
|
|
|
+/* See LICENSE for licensing information */
|
|
|
+
|
|
|
+#include "lib/log/escape.h"
|
|
|
+#include "lib/log/util_bug.h"
|
|
|
+#include "lib/string/compat_ctype.h"
|
|
|
+#include "lib/string/printf.h"
|
|
|
+#include "lib/malloc/util_malloc.h"
|
|
|
+
|
|
|
+/** Allocate and return a new string representing the contents of <b>s</b>,
|
|
|
+ * surrounded by quotes and using standard C escapes.
|
|
|
+ *
|
|
|
+ * Generally, we use this for logging values that come in over the network to
|
|
|
+ * keep them from tricking users, and for sending certain values to the
|
|
|
+ * controller.
|
|
|
+ *
|
|
|
+ * We trust values from the resolver, OS, configuration file, and command line
|
|
|
+ * to not be maliciously ill-formed. We validate incoming routerdescs and
|
|
|
+ * SOCKS requests and addresses from BEGIN cells as they're parsed;
|
|
|
+ * afterwards, we trust them as non-malicious.
|
|
|
+ */
|
|
|
+char *
|
|
|
+esc_for_log(const char *s)
|
|
|
+{
|
|
|
+ const char *cp;
|
|
|
+ char *result, *outp;
|
|
|
+ size_t len = 3;
|
|
|
+ if (!s) {
|
|
|
+ return tor_strdup("(null)");
|
|
|
+ }
|
|
|
+
|
|
|
+ for (cp = s; *cp; ++cp) {
|
|
|
+ switch (*cp) {
|
|
|
+ case '\\':
|
|
|
+ case '\"':
|
|
|
+ case '\'':
|
|
|
+ case '\r':
|
|
|
+ case '\n':
|
|
|
+ case '\t':
|
|
|
+ len += 2;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127)
|
|
|
+ ++len;
|
|
|
+ else
|
|
|
+ len += 4;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ tor_assert(len <= SSIZE_MAX);
|
|
|
+
|
|
|
+ result = outp = tor_malloc(len);
|
|
|
+ *outp++ = '\"';
|
|
|
+ for (cp = s; *cp; ++cp) {
|
|
|
+ /* This assertion should always succeed, since we will write at least
|
|
|
+ * one char here, and two chars for closing quote and nul later */
|
|
|
+ tor_assert((outp-result) < (ssize_t)len-2);
|
|
|
+ switch (*cp) {
|
|
|
+ case '\\':
|
|
|
+ case '\"':
|
|
|
+ case '\'':
|
|
|
+ *outp++ = '\\';
|
|
|
+ *outp++ = *cp;
|
|
|
+ break;
|
|
|
+ case '\n':
|
|
|
+ *outp++ = '\\';
|
|
|
+ *outp++ = 'n';
|
|
|
+ break;
|
|
|
+ case '\t':
|
|
|
+ *outp++ = '\\';
|
|
|
+ *outp++ = 't';
|
|
|
+ break;
|
|
|
+ case '\r':
|
|
|
+ *outp++ = '\\';
|
|
|
+ *outp++ = 'r';
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) {
|
|
|
+ *outp++ = *cp;
|
|
|
+ } else {
|
|
|
+ tor_assert((outp-result) < (ssize_t)len-4);
|
|
|
+ tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp);
|
|
|
+ outp += 4;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ tor_assert((outp-result) <= (ssize_t)len-2);
|
|
|
+ *outp++ = '\"';
|
|
|
+ *outp++ = 0;
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+/** Similar to esc_for_log. Allocate and return a new string representing
|
|
|
+ * the first n characters in <b>chars</b>, surround by quotes and using
|
|
|
+ * standard C escapes. If a NUL character is encountered in <b>chars</b>,
|
|
|
+ * the resulting string will be terminated there.
|
|
|
+ */
|
|
|
+char *
|
|
|
+esc_for_log_len(const char *chars, size_t n)
|
|
|
+{
|
|
|
+ char *string = tor_strndup(chars, n);
|
|
|
+ char *string_escaped = esc_for_log(string);
|
|
|
+ tor_free(string);
|
|
|
+ return string_escaped;
|
|
|
+}
|
|
|
+
|
|
|
+/** Allocate and return a new string representing the contents of <b>s</b>,
|
|
|
+ * surrounded by quotes and using standard C escapes.
|
|
|
+ *
|
|
|
+ * THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main
|
|
|
+ * thread. Also, each call invalidates the last-returned value, so don't
|
|
|
+ * try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b));
|
|
|
+ */
|
|
|
+const char *
|
|
|
+escaped(const char *s)
|
|
|
+{
|
|
|
+ static char *escaped_val_ = NULL;
|
|
|
+ tor_free(escaped_val_);
|
|
|
+
|
|
|
+ if (s)
|
|
|
+ escaped_val_ = esc_for_log(s);
|
|
|
+ else
|
|
|
+ escaped_val_ = NULL;
|
|
|
+
|
|
|
+ return escaped_val_;
|
|
|
+}
|