mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-12 22:23:49 +01:00
r17499@catbus: nickm | 2008-01-07 13:39:46 -0500
Bugfix on fix for 557: Make values containing special characters work right with getconf, setconf, and saveconf. Document this in control-spec.txt svn:r13056
This commit is contained in:
parent
a63eb68fe1
commit
dd35fe59c4
@ -36,6 +36,9 @@ Changes in version 0.2.0.16-alpha - 2008-01-??
|
|||||||
|
|
||||||
o Minor features (controller):
|
o Minor features (controller):
|
||||||
- Get NS events working again. (Patch from tup)
|
- Get NS events working again. (Patch from tup)
|
||||||
|
- The GETCONF command now escapes and quotes configuration values
|
||||||
|
that don't otherwise fit into the torrc file.
|
||||||
|
- The SETCONF command now handles quoted values correctly.
|
||||||
|
|
||||||
o Minor features (other):
|
o Minor features (other):
|
||||||
- Add hidden services and DNSPorts to the list of things that make
|
- Add hidden services and DNSPorts to the list of things that make
|
||||||
@ -43,6 +46,7 @@ Changes in version 0.2.0.16-alpha - 2008-01-??
|
|||||||
no ports from a fatal error to a warning; we might change it
|
no ports from a fatal error to a warning; we might change it
|
||||||
back if this turns out to confuse anybody. (Fixes bug 579.)
|
back if this turns out to confuse anybody. (Fixes bug 579.)
|
||||||
|
|
||||||
|
|
||||||
Changes in version 0.2.0.15-alpha - 2007-12-25
|
Changes in version 0.2.0.15-alpha - 2007-12-25
|
||||||
o Major bugfixes:
|
o Major bugfixes:
|
||||||
- Fix several remotely triggerable asserts based on DirPort requests
|
- Fix several remotely triggerable asserts based on DirPort requests
|
||||||
|
@ -139,7 +139,8 @@ $Id$
|
|||||||
|
|
||||||
Change the value of one or more configuration variables. The syntax is:
|
Change the value of one or more configuration variables. The syntax is:
|
||||||
|
|
||||||
"SETCONF" 1*(SP keyword ["=" String]) CRLF
|
"SETCONF" 1*(SP keyword ["=" value]) CRLF
|
||||||
|
value = String / QuotedString
|
||||||
|
|
||||||
Tor behaves as though it had just read each of the key-value pairs
|
Tor behaves as though it had just read each of the key-value pairs
|
||||||
from its configuration file. Keywords with no corresponding values have
|
from its configuration file. Keywords with no corresponding values have
|
||||||
@ -184,6 +185,10 @@ $Id$
|
|||||||
empty string, Tor may reply with a reply line of the form:
|
empty string, Tor may reply with a reply line of the form:
|
||||||
250 keyword
|
250 keyword
|
||||||
|
|
||||||
|
Value may be a raw value or a quoted string. Tor will try to use
|
||||||
|
unquoted values except when the value could be misinterpreted through
|
||||||
|
not being quoted.
|
||||||
|
|
||||||
If some of the listed keywords can't be found, Tor replies with a
|
If some of the listed keywords can't be found, Tor replies with a
|
||||||
"552 unknown configuration keyword" message.
|
"552 unknown configuration keyword" message.
|
||||||
|
|
||||||
|
@ -627,7 +627,8 @@ static int parse_log_severity_range(const char *range, int *min_out,
|
|||||||
static int validate_data_directory(or_options_t *options);
|
static int validate_data_directory(or_options_t *options);
|
||||||
static int write_configuration_file(const char *fname, or_options_t *options);
|
static int write_configuration_file(const char *fname, or_options_t *options);
|
||||||
static config_line_t *get_assigned_option(config_format_t *fmt,
|
static config_line_t *get_assigned_option(config_format_t *fmt,
|
||||||
or_options_t *options, const char *key);
|
or_options_t *options, const char *key,
|
||||||
|
int escape_val);
|
||||||
static void config_init(config_format_t *fmt, void *options);
|
static void config_init(config_format_t *fmt, void *options);
|
||||||
static int or_state_validate(or_state_t *old_options, or_state_t *options,
|
static int or_state_validate(or_state_t *old_options, or_state_t *options,
|
||||||
int from_setconf, char **msg);
|
int from_setconf, char **msg);
|
||||||
@ -1686,7 +1687,33 @@ option_get_canonical_name(const char *key)
|
|||||||
config_line_t *
|
config_line_t *
|
||||||
option_get_assignment(or_options_t *options, const char *key)
|
option_get_assignment(or_options_t *options, const char *key)
|
||||||
{
|
{
|
||||||
return get_assigned_option(&options_format, options, key);
|
return get_assigned_option(&options_format, options, key, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return true iff value needs to be quoted and escaped to be used in
|
||||||
|
* a configuration file. */
|
||||||
|
static int
|
||||||
|
config_value_needs_escape(const char *value)
|
||||||
|
{
|
||||||
|
if (*value == '\"')
|
||||||
|
return 1;
|
||||||
|
while (*value) {
|
||||||
|
switch (*value)
|
||||||
|
{
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
case '#':
|
||||||
|
/* Note: quotes and backspaces need special handling when we are using
|
||||||
|
* quotes, not otherwise, so they don't trigger escaping on their
|
||||||
|
* own. */
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
if (!TOR_ISPRINT(*value))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
++value;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return a newly allocated deep copy of the lines in <b>inp</b>. */
|
/** Return a newly allocated deep copy of the lines in <b>inp</b>. */
|
||||||
@ -1707,10 +1734,12 @@ config_lines_dup(const config_line_t *inp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Return newly allocated line or lines corresponding to <b>key</b> in the
|
/** Return newly allocated line or lines corresponding to <b>key</b> in the
|
||||||
* configuration <b>options</b>. Return NULL if no such key exists. */
|
* configuration <b>options</b>. If <b>escape_val</b> is true and a
|
||||||
|
* value needs to be quoted before it's put in a config file, quote and
|
||||||
|
* escape that value. Return NULL if no such key exists. */
|
||||||
static config_line_t *
|
static config_line_t *
|
||||||
get_assigned_option(config_format_t *fmt, or_options_t *options,
|
get_assigned_option(config_format_t *fmt, or_options_t *options,
|
||||||
const char *key)
|
const char *key, int escape_val)
|
||||||
/* XXXX argument is options, but fmt is provided. Inconsistent. */
|
/* XXXX argument is options, but fmt is provided. Inconsistent. */
|
||||||
{
|
{
|
||||||
config_var_t *var;
|
config_var_t *var;
|
||||||
@ -1749,6 +1778,7 @@ get_assigned_option(config_format_t *fmt, or_options_t *options,
|
|||||||
tor_free(result->key);
|
tor_free(result->key);
|
||||||
tor_free(result);
|
tor_free(result);
|
||||||
}
|
}
|
||||||
|
escape_val = 0; /* Can't need escape. */
|
||||||
break;
|
break;
|
||||||
case CONFIG_TYPE_INTERVAL:
|
case CONFIG_TYPE_INTERVAL:
|
||||||
case CONFIG_TYPE_UINT:
|
case CONFIG_TYPE_UINT:
|
||||||
@ -1756,18 +1786,22 @@ get_assigned_option(config_format_t *fmt, or_options_t *options,
|
|||||||
* needs to be an int. Not, say, a uint16_t or char. */
|
* needs to be an int. Not, say, a uint16_t or char. */
|
||||||
tor_snprintf(buf, sizeof(buf), "%d", *(int*)value);
|
tor_snprintf(buf, sizeof(buf), "%d", *(int*)value);
|
||||||
result->value = tor_strdup(buf);
|
result->value = tor_strdup(buf);
|
||||||
|
escape_val = 0; /* Can't need escape. */
|
||||||
break;
|
break;
|
||||||
case CONFIG_TYPE_MEMUNIT:
|
case CONFIG_TYPE_MEMUNIT:
|
||||||
tor_snprintf(buf, sizeof(buf), U64_FORMAT,
|
tor_snprintf(buf, sizeof(buf), U64_FORMAT,
|
||||||
U64_PRINTF_ARG(*(uint64_t*)value));
|
U64_PRINTF_ARG(*(uint64_t*)value));
|
||||||
result->value = tor_strdup(buf);
|
result->value = tor_strdup(buf);
|
||||||
|
escape_val = 0; /* Can't need escape. */
|
||||||
break;
|
break;
|
||||||
case CONFIG_TYPE_DOUBLE:
|
case CONFIG_TYPE_DOUBLE:
|
||||||
tor_snprintf(buf, sizeof(buf), "%f", *(double*)value);
|
tor_snprintf(buf, sizeof(buf), "%f", *(double*)value);
|
||||||
result->value = tor_strdup(buf);
|
result->value = tor_strdup(buf);
|
||||||
|
escape_val = 0; /* Can't need escape. */
|
||||||
break;
|
break;
|
||||||
case CONFIG_TYPE_BOOL:
|
case CONFIG_TYPE_BOOL:
|
||||||
result->value = tor_strdup(*(int*)value ? "1" : "0");
|
result->value = tor_strdup(*(int*)value ? "1" : "0");
|
||||||
|
escape_val = 0; /* Can't need escape. */
|
||||||
break;
|
break;
|
||||||
case CONFIG_TYPE_CSV:
|
case CONFIG_TYPE_CSV:
|
||||||
if (*(smartlist_t**)value)
|
if (*(smartlist_t**)value)
|
||||||
@ -1793,7 +1827,8 @@ get_assigned_option(config_format_t *fmt, or_options_t *options,
|
|||||||
case CONFIG_TYPE_LINELIST_V:
|
case CONFIG_TYPE_LINELIST_V:
|
||||||
tor_free(result->key);
|
tor_free(result->key);
|
||||||
tor_free(result);
|
tor_free(result);
|
||||||
return config_lines_dup(*(const config_line_t**)value);
|
result = config_lines_dup(*(const config_line_t**)value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
tor_free(result->key);
|
tor_free(result->key);
|
||||||
tor_free(result);
|
tor_free(result);
|
||||||
@ -1802,6 +1837,17 @@ get_assigned_option(config_format_t *fmt, or_options_t *options,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (escape_val) {
|
||||||
|
config_line_t *line;
|
||||||
|
for (line = result; line; line = line->next) {
|
||||||
|
if (line->value && config_value_needs_escape(line->value)) {
|
||||||
|
char *newval = esc_for_log(line->value);
|
||||||
|
tor_free(line->value);
|
||||||
|
line->value = newval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2319,8 +2365,8 @@ option_is_same(config_format_t *fmt,
|
|||||||
CHECK(fmt, o1);
|
CHECK(fmt, o1);
|
||||||
CHECK(fmt, o2);
|
CHECK(fmt, o2);
|
||||||
|
|
||||||
c1 = get_assigned_option(fmt, o1, name);
|
c1 = get_assigned_option(fmt, o1, name, 0);
|
||||||
c2 = get_assigned_option(fmt, o2, name);
|
c2 = get_assigned_option(fmt, o2, name, 0);
|
||||||
r = config_lines_eq(c1, c2);
|
r = config_lines_eq(c1, c2);
|
||||||
config_free_lines(c1);
|
config_free_lines(c1);
|
||||||
config_free_lines(c2);
|
config_free_lines(c2);
|
||||||
@ -2341,7 +2387,7 @@ options_dup(config_format_t *fmt, or_options_t *old)
|
|||||||
continue;
|
continue;
|
||||||
if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE)
|
if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE)
|
||||||
continue;
|
continue;
|
||||||
line = get_assigned_option(fmt, old, fmt->vars[i].name);
|
line = get_assigned_option(fmt, old, fmt->vars[i].name, 0);
|
||||||
if (line) {
|
if (line) {
|
||||||
char *msg = NULL;
|
char *msg = NULL;
|
||||||
if (config_assign(fmt, newopts, line, 0, 0, &msg) < 0) {
|
if (config_assign(fmt, newopts, line, 0, 0, &msg) < 0) {
|
||||||
@ -2430,7 +2476,7 @@ config_dump(config_format_t *fmt, void *options, int minimal,
|
|||||||
comment_option = 1;
|
comment_option = 1;
|
||||||
|
|
||||||
desc = config_find_description(fmt, fmt->vars[i].name);
|
desc = config_find_description(fmt, fmt->vars[i].name);
|
||||||
line = assigned = get_assigned_option(fmt, options, fmt->vars[i].name);
|
line = assigned = get_assigned_option(fmt, options, fmt->vars[i].name, 1);
|
||||||
|
|
||||||
if (line && desc) {
|
if (line && desc) {
|
||||||
/* Only dump the description if there's something to describe. */
|
/* Only dump the description if there's something to describe. */
|
||||||
|
@ -364,6 +364,44 @@ read_escaped_data(const char *data, size_t len, char **out)
|
|||||||
return outp - *out;
|
return outp - *out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DOCDOC */
|
||||||
|
static const char *
|
||||||
|
extract_escaped_string(const char *start, size_t in_len_max,
|
||||||
|
char **out, size_t *out_len)
|
||||||
|
{
|
||||||
|
const char *cp, *end;
|
||||||
|
size_t len=0;
|
||||||
|
|
||||||
|
if (*start != '\"')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cp = start+1;
|
||||||
|
end = start+in_len_max;
|
||||||
|
|
||||||
|
/* Calculate length. */
|
||||||
|
while (1) {
|
||||||
|
if (cp >= end)
|
||||||
|
return NULL;
|
||||||
|
else if (*cp == '\\') {
|
||||||
|
if (++cp == end)
|
||||||
|
return NULL; /* Can't escape EOS. */
|
||||||
|
++cp;
|
||||||
|
++len;
|
||||||
|
} else if (*cp == '\"') {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
++cp;
|
||||||
|
++len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end = cp;
|
||||||
|
|
||||||
|
*out_len = end-start+1;
|
||||||
|
*out = tor_strndup(start, *out_len);
|
||||||
|
|
||||||
|
return end+1;
|
||||||
|
}
|
||||||
|
|
||||||
/** Given a pointer to a string starting at <b>start</b> containing
|
/** Given a pointer to a string starting at <b>start</b> containing
|
||||||
* <b>in_len_max</b> characters, decode a string beginning with one double
|
* <b>in_len_max</b> characters, decode a string beginning with one double
|
||||||
* quote, containing any number of non-quote characters or characters escaped
|
* quote, containing any number of non-quote characters or characters escaped
|
||||||
@ -372,6 +410,7 @@ read_escaped_data(const char *data, size_t len, char **out)
|
|||||||
* store its length in <b>out_len</b>. On success, return a pointer to the
|
* store its length in <b>out_len</b>. On success, return a pointer to the
|
||||||
* character immediately following the escaped string. On failure, return
|
* character immediately following the escaped string. On failure, return
|
||||||
* NULL. */
|
* NULL. */
|
||||||
|
/* XXXX020 fold into extract_escaped_string */
|
||||||
static const char *
|
static const char *
|
||||||
get_escaped_string(const char *start, size_t in_len_max,
|
get_escaped_string(const char *start, size_t in_len_max,
|
||||||
char **out, size_t *out_len)
|
char **out, size_t *out_len)
|
||||||
@ -659,8 +698,8 @@ control_setconf_helper(control_connection_t *conn, uint32_t len, char *body,
|
|||||||
val = tor_strndup(val_start, body-val_start);
|
val = tor_strndup(val_start, body-val_start);
|
||||||
val_len = strlen(val);
|
val_len = strlen(val);
|
||||||
} else {
|
} else {
|
||||||
body = (char*)get_escaped_string(body, (len - (body-start)),
|
body = (char*)extract_escaped_string(body, (len - (body-start)),
|
||||||
&val, &val_len);
|
&val, &val_len);
|
||||||
if (!body) {
|
if (!body) {
|
||||||
connection_write_str_to_buf("551 Couldn't parse string\r\n", conn);
|
connection_write_str_to_buf("551 Couldn't parse string\r\n", conn);
|
||||||
SMARTLIST_FOREACH(entries, char *, cp, tor_free(cp));
|
SMARTLIST_FOREACH(entries, char *, cp, tor_free(cp));
|
||||||
|
Loading…
Reference in New Issue
Block a user