mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-30 23:53:32 +01:00
Support code for resettable options, and option sets. Still needs validate-and-then-replace logic
svn:r2679
This commit is contained in:
parent
d9e0f3f9bc
commit
1b49198081
183
src/or/config.c
183
src/or/config.c
@ -23,6 +23,11 @@ typedef enum config_type_t {
|
|||||||
CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and optional
|
CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and optional
|
||||||
* whitespace. */
|
* whitespace. */
|
||||||
CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */
|
CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */
|
||||||
|
CONFIG_TYPE_LINELIST_S, /**< Uninterpreted, context-sensitive config lines,
|
||||||
|
* mixed with other keywords. */
|
||||||
|
CONFIG_TYPE_LINELIST_V, /**< Catch-all "virtual" option to summarize
|
||||||
|
* context-sensitive config lines when fetching.
|
||||||
|
*/
|
||||||
CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
|
CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
|
||||||
} config_type_t;
|
} config_type_t;
|
||||||
|
|
||||||
@ -106,14 +111,16 @@ static config_var_t config_vars[] = {
|
|||||||
VAR("Group", STRING, Group, NULL),
|
VAR("Group", STRING, Group, NULL),
|
||||||
VAR("HashedControlPassword",STRING, HashedControlPassword, NULL),
|
VAR("HashedControlPassword",STRING, HashedControlPassword, NULL),
|
||||||
VAR("HttpProxy", STRING, HttpProxy, NULL),
|
VAR("HttpProxy", STRING, HttpProxy, NULL),
|
||||||
VAR("HiddenServiceDir", LINELIST, RendConfigLines, NULL),
|
VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL),
|
||||||
VAR("HiddenServicePort", LINELIST, RendConfigLines, NULL),
|
VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL),
|
||||||
VAR("HiddenServiceNodes", LINELIST, RendConfigLines, NULL),
|
VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL),
|
||||||
VAR("HiddenServiceExcludeNodes", LINELIST, RendConfigLines,NULL),
|
VAR("HiddenServiceNodes", LINELIST_S, RendConfigLines, NULL),
|
||||||
|
VAR("HiddenServiceExcludeNodes", LINELIST_S, RendConfigLines, NULL),
|
||||||
VAR("IgnoreVersion", BOOL, IgnoreVersion, "0"),
|
VAR("IgnoreVersion", BOOL, IgnoreVersion, "0"),
|
||||||
VAR("KeepalivePeriod", UINT, KeepalivePeriod, "300"),
|
VAR("KeepalivePeriod", UINT, KeepalivePeriod, "300"),
|
||||||
VAR("LogLevel", LINELIST, LogOptions, NULL),
|
VAR("LogOptions", LINELIST_V, LogOptions, NULL),
|
||||||
VAR("LogFile", LINELIST, LogOptions, NULL),
|
VAR("LogLevel", LINELIST_S, LogOptions, NULL),
|
||||||
|
VAR("LogFile", LINELIST_S, LogOptions, NULL),
|
||||||
OBSOLETE("LinkPadding"),
|
OBSOLETE("LinkPadding"),
|
||||||
VAR("MaxConn", UINT, MaxConn, "1024"),
|
VAR("MaxConn", UINT, MaxConn, "1024"),
|
||||||
VAR("MaxOnionsPending", UINT, MaxOnionsPending, "100"),
|
VAR("MaxOnionsPending", UINT, MaxOnionsPending, "100"),
|
||||||
@ -137,7 +144,7 @@ static config_var_t config_vars[] = {
|
|||||||
VAR("SocksPort", UINT, SocksPort, "9050"),
|
VAR("SocksPort", UINT, SocksPort, "9050"),
|
||||||
VAR("SocksBindAddress", LINELIST, SocksBindAddress, NULL),
|
VAR("SocksBindAddress", LINELIST, SocksBindAddress, NULL),
|
||||||
VAR("SocksPolicy", LINELIST, SocksPolicy, NULL),
|
VAR("SocksPolicy", LINELIST, SocksPolicy, NULL),
|
||||||
VAR("SysLog", LINELIST, LogOptions, NULL),
|
VAR("SysLog", LINELIST_S, LogOptions, NULL),
|
||||||
OBSOLETE("TrafficShaping"),
|
OBSOLETE("TrafficShaping"),
|
||||||
VAR("User", STRING, User, NULL),
|
VAR("User", STRING, User, NULL),
|
||||||
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
|
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
|
||||||
@ -151,13 +158,16 @@ static config_var_t config_vars[] = {
|
|||||||
static struct config_line_t *config_get_commandlines(int argc, char **argv);
|
static struct config_line_t *config_get_commandlines(int argc, char **argv);
|
||||||
static int config_get_lines(FILE *f, struct config_line_t **result);
|
static int config_get_lines(FILE *f, struct config_line_t **result);
|
||||||
static void config_free_lines(struct config_line_t *front);
|
static void config_free_lines(struct config_line_t *front);
|
||||||
static int config_assign_line(or_options_t *options, struct config_line_t *c);
|
static int config_assign_line(or_options_t *options, struct config_line_t *c,
|
||||||
static int config_assign(or_options_t *options, struct config_line_t *list);
|
int reset);
|
||||||
|
static int config_assign(or_options_t *options, struct config_line_t *list,
|
||||||
|
int reset);
|
||||||
static int parse_dir_server_line(const char *line);
|
static int parse_dir_server_line(const char *line);
|
||||||
static int parse_redirect_line(or_options_t *options,
|
static int parse_redirect_line(or_options_t *options,
|
||||||
struct config_line_t *line);
|
struct config_line_t *line);
|
||||||
static const char *expand_abbrev(const char *option, int commandline_only);
|
static const char *expand_abbrev(const char *option, int commandline_only);
|
||||||
static config_var_t *config_find_option(const char *key);
|
static config_var_t *config_find_option(const char *key);
|
||||||
|
static void reset_option(or_options_t *options, config_var_t *var);
|
||||||
|
|
||||||
/** If <b>option</b> is an official abbreviation for a longer option,
|
/** If <b>option</b> is an official abbreviation for a longer option,
|
||||||
* return the longer option. Otherwise return <b>option</b>.
|
* return the longer option. Otherwise return <b>option</b>.
|
||||||
@ -216,7 +226,7 @@ config_get_commandlines(int argc, char **argv)
|
|||||||
|
|
||||||
/** Helper: allocate a new configuration option mapping 'key' to 'val',
|
/** Helper: allocate a new configuration option mapping 'key' to 'val',
|
||||||
* prepend it to 'front', and return the newly allocated config_line_t */
|
* prepend it to 'front', and return the newly allocated config_line_t */
|
||||||
static struct config_line_t *
|
struct config_line_t *
|
||||||
config_line_prepend(struct config_line_t *front,
|
config_line_prepend(struct config_line_t *front,
|
||||||
const char *key,
|
const char *key,
|
||||||
const char *val)
|
const char *val)
|
||||||
@ -298,9 +308,13 @@ static config_var_t *config_find_option(const char *key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** If <b>c</b> is a syntactically valid configuration line, update
|
/** If <b>c</b> is a syntactically valid configuration line, update
|
||||||
* <b>options</b> with its value and return 0. Otherwise return -1. */
|
* <b>options</b> with its value and return 0. Otherwise return -1.
|
||||||
|
*
|
||||||
|
* If 'reset' is set, and we get a line containing no value, restore the
|
||||||
|
* option to its default value.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
config_assign_line(or_options_t *options, struct config_line_t *c)
|
config_assign_line(or_options_t *options, struct config_line_t *c, int reset)
|
||||||
{
|
{
|
||||||
int i, ok;
|
int i, ok;
|
||||||
config_var_t *var;
|
config_var_t *var;
|
||||||
@ -311,13 +325,17 @@ config_assign_line(or_options_t *options, struct config_line_t *c)
|
|||||||
log_fn(LOG_WARN, "Unknown option '%s'. Failing.", c->key);
|
log_fn(LOG_WARN, "Unknown option '%s'. Failing.", c->key);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put keyword into canonical case. */
|
/* Put keyword into canonical case. */
|
||||||
if (strcmp(var->name, c->key)) {
|
if (strcmp(var->name, c->key)) {
|
||||||
tor_free(c->key);
|
tor_free(c->key);
|
||||||
c->key = tor_strdup(var->name);
|
c->key = tor_strdup(var->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reset && !strlen(c->value)) {
|
||||||
|
reset_option(options, var);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
lvalue = ((char*)options) + var->var_offset;
|
lvalue = ((char*)options) + var->var_offset;
|
||||||
switch(var->type) {
|
switch(var->type) {
|
||||||
|
|
||||||
@ -357,22 +375,43 @@ config_assign_line(or_options_t *options, struct config_line_t *c)
|
|||||||
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONFIG_TYPE_LINELIST:
|
|
||||||
/* Note: this reverses the order that the lines appear in. That's
|
case CONFIG_TYPE_LINELIST:
|
||||||
* just fine, since we build up the list of lines reversed in the
|
case CONFIG_TYPE_LINELIST_S:
|
||||||
* first place. */
|
/* Note: this reverses the order that the lines appear in. That's
|
||||||
*(struct config_line_t**)lvalue =
|
* just fine, since we build up the list of lines reversed in the
|
||||||
config_line_prepend(*(struct config_line_t**)lvalue, c->key, c->value);
|
* first place. */
|
||||||
break;
|
*(struct config_line_t**)lvalue =
|
||||||
|
config_line_prepend(*(struct config_line_t**)lvalue, c->key, c->value);
|
||||||
|
break;
|
||||||
|
|
||||||
case CONFIG_TYPE_OBSOLETE:
|
case CONFIG_TYPE_OBSOLETE:
|
||||||
log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
|
log_fn(LOG_WARN, "Skipping obsolete configuration option '%s'", c->key);
|
||||||
break;
|
break;
|
||||||
|
case CONFIG_TYPE_LINELIST_V:
|
||||||
|
log_fn(LOG_WARN, "Can't provide value for virtual option '%s'", c->key);
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
tor_assert(0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** restore the option named <b>key</b> in options to its default value. */
|
||||||
|
static void
|
||||||
|
config_reset_line(or_options_t *options, const char *key)
|
||||||
|
{
|
||||||
|
config_var_t *var;
|
||||||
|
|
||||||
|
var = config_find_option(key);
|
||||||
|
if (!var)
|
||||||
|
return; /* give error on next pass. */
|
||||||
|
|
||||||
|
reset_option(options, var);
|
||||||
|
}
|
||||||
|
|
||||||
/** Return a canonicalized list of the options assigned for key.
|
/** Return a canonicalized list of the options assigned for key.
|
||||||
*/
|
*/
|
||||||
struct config_line_t *
|
struct config_line_t *
|
||||||
@ -387,10 +426,14 @@ config_get_assigned_option(or_options_t *options, const char *key)
|
|||||||
if (!var) {
|
if (!var) {
|
||||||
log_fn(LOG_WARN, "Unknown option '%s'. Failing.", key);
|
log_fn(LOG_WARN, "Unknown option '%s'. Failing.", key);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
} else if (var->type == CONFIG_TYPE_LINELIST_S) {
|
||||||
|
log_fn(LOG_WARN, "Can't return context-sensitive '%s' on its own", key);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
value = ((char*)options) + var->var_offset;
|
value = ((char*)options) + var->var_offset;
|
||||||
|
|
||||||
if (var->type == CONFIG_TYPE_LINELIST) {
|
if (var->type == CONFIG_TYPE_LINELIST ||
|
||||||
|
var->type == CONFIG_TYPE_LINELIST_V) {
|
||||||
/* Linelist requires special handling: we just copy and return it. */
|
/* Linelist requires special handling: we just copy and return it. */
|
||||||
const struct config_line_t *next_in = value;
|
const struct config_line_t *next_in = value;
|
||||||
struct config_line_t **next_out = &result;
|
struct config_line_t **next_out = &result;
|
||||||
@ -442,18 +485,36 @@ config_get_assigned_option(or_options_t *options, const char *key)
|
|||||||
/** Iterate through the linked list of requested options <b>list</b>.
|
/** Iterate through the linked list of requested options <b>list</b>.
|
||||||
* For each item, convert as appropriate and assign to <b>options</b>.
|
* For each item, convert as appropriate and assign to <b>options</b>.
|
||||||
* If an item is unrecognized, return -1 immediately,
|
* If an item is unrecognized, return -1 immediately,
|
||||||
* else return 0 for success. */
|
* else return 0 for success.
|
||||||
|
*
|
||||||
|
* If <b>reset</b>, then interpret empty lines as meaning "restore to
|
||||||
|
* default value", and interpret LINELIST* options as replacing (not
|
||||||
|
* extending) their previous values.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
config_assign(or_options_t *options, struct config_line_t *list)
|
config_assign(or_options_t *options, struct config_line_t *list, int reset)
|
||||||
{
|
{
|
||||||
while (list) {
|
struct config_line_t *p;
|
||||||
const char *full = expand_abbrev(list->key, 0);
|
|
||||||
if (strcmp(full,list->key)) {
|
|
||||||
tor_free(list->key);
|
|
||||||
list->key = tor_strdup(full);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config_assign_line(options, list))
|
/* pass 1: normalize keys */
|
||||||
|
for (p = list; p; p = p->next) {
|
||||||
|
const char *full = expand_abbrev(p->key, 0);
|
||||||
|
if (strcmp(full,p->key)) {
|
||||||
|
tor_free(p->key);
|
||||||
|
p->key = tor_strdup(full);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pass 2: if we're reading from a resetting souurce, clear all mentioned
|
||||||
|
* linelists. */
|
||||||
|
if (reset) {
|
||||||
|
for (p = list; p; p = p->next)
|
||||||
|
config_reset_line(options, p->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pass 3: assign. */
|
||||||
|
while (list) {
|
||||||
|
if (config_assign_line(options, list, reset))
|
||||||
return -1;
|
return -1;
|
||||||
list = list->next;
|
list = list->next;
|
||||||
}
|
}
|
||||||
@ -604,6 +665,7 @@ free_options(or_options_t *options)
|
|||||||
tor_free(*(char **)lvalue);
|
tor_free(*(char **)lvalue);
|
||||||
break;
|
break;
|
||||||
case CONFIG_TYPE_LINELIST:
|
case CONFIG_TYPE_LINELIST:
|
||||||
|
case CONFIG_TYPE_LINELIST_V:
|
||||||
config_free_lines(*(struct config_line_t**)lvalue);
|
config_free_lines(*(struct config_line_t**)lvalue);
|
||||||
*(struct config_line_t**)lvalue = NULL;
|
*(struct config_line_t**)lvalue = NULL;
|
||||||
break;
|
break;
|
||||||
@ -614,6 +676,9 @@ free_options(or_options_t *options)
|
|||||||
*(smartlist_t**)lvalue = NULL;
|
*(smartlist_t**)lvalue = NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CONFIG_TYPE_LINELIST_S:
|
||||||
|
/* will be freed by corresponding LINELIST_V. */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* XXX this last part is an exception. can we make it not needed? */
|
/* XXX this last part is an exception. can we make it not needed? */
|
||||||
@ -625,13 +690,59 @@ free_options(or_options_t *options)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Replace the option indexed by <b>var</b> in <b>options</b> with its
|
||||||
|
* default value. */
|
||||||
|
static void
|
||||||
|
reset_option(or_options_t *options, config_var_t *var)
|
||||||
|
{
|
||||||
|
struct config_line_t *c;
|
||||||
|
void *lvalue;
|
||||||
|
|
||||||
|
lvalue = ((char*)options) + var->var_offset;
|
||||||
|
switch (var->type) {
|
||||||
|
case CONFIG_TYPE_STRING:
|
||||||
|
tor_free(*(char**)lvalue);
|
||||||
|
break;
|
||||||
|
case CONFIG_TYPE_DOUBLE:
|
||||||
|
*(double*)lvalue = 0.0;
|
||||||
|
break;
|
||||||
|
case CONFIG_TYPE_UINT:
|
||||||
|
case CONFIG_TYPE_BOOL:
|
||||||
|
*(int*)lvalue = 0;
|
||||||
|
break;
|
||||||
|
case CONFIG_TYPE_CSV:
|
||||||
|
if (*(smartlist_t**)lvalue) {
|
||||||
|
SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp));
|
||||||
|
smartlist_free(*(smartlist_t **)lvalue);
|
||||||
|
*(smartlist_t **)lvalue = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONFIG_TYPE_LINELIST:
|
||||||
|
case CONFIG_TYPE_LINELIST_S:
|
||||||
|
config_free_lines(*(struct config_line_t **)lvalue);
|
||||||
|
*(struct config_line_t **)lvalue = NULL;
|
||||||
|
break;
|
||||||
|
case CONFIG_TYPE_LINELIST_V:
|
||||||
|
/* handled by linelist_s. */
|
||||||
|
break;
|
||||||
|
case CONFIG_TYPE_OBSOLETE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (var->initvalue) {
|
||||||
|
c = tor_malloc(sizeof(struct config_line_t));
|
||||||
|
c->key = tor_strdup(var->name);
|
||||||
|
c->value = tor_strdup(var->initvalue);
|
||||||
|
config_assign_line(options,c,0);
|
||||||
|
config_free_lines(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Set <b>options</b> to hold reasonable defaults for most options.
|
/** Set <b>options</b> to hold reasonable defaults for most options.
|
||||||
* Each option defaults to zero. */
|
* Each option defaults to zero. */
|
||||||
static void
|
static void
|
||||||
init_options(or_options_t *options)
|
init_options(or_options_t *options)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct config_line_t *c;
|
|
||||||
config_var_t *var;
|
config_var_t *var;
|
||||||
|
|
||||||
memset(options,0,sizeof(or_options_t));
|
memset(options,0,sizeof(or_options_t));
|
||||||
@ -639,11 +750,7 @@ init_options(or_options_t *options)
|
|||||||
var = &config_vars[i];
|
var = &config_vars[i];
|
||||||
if(!var->initvalue)
|
if(!var->initvalue)
|
||||||
continue; /* defaults to NULL or 0 */
|
continue; /* defaults to NULL or 0 */
|
||||||
c = tor_malloc(sizeof(struct config_line_t));
|
reset_option(options, var);
|
||||||
c->key = tor_strdup(var->name);
|
|
||||||
c->value = tor_strdup(var->initvalue);
|
|
||||||
config_assign_line(options,c);
|
|
||||||
config_free_lines(c);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,7 +1155,7 @@ getconfig(int argc, char **argv, or_options_t *options)
|
|||||||
tor_free(fname);
|
tor_free(fname);
|
||||||
if (config_get_lines(cf, &cl)<0)
|
if (config_get_lines(cf, &cl)<0)
|
||||||
return -1;
|
return -1;
|
||||||
if (config_assign(options,cl) < 0)
|
if (config_assign(options,cl, 0) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
config_free_lines(cl);
|
config_free_lines(cl);
|
||||||
fclose(cf);
|
fclose(cf);
|
||||||
@ -1056,7 +1163,7 @@ getconfig(int argc, char **argv, or_options_t *options)
|
|||||||
|
|
||||||
/* go through command-line variables too */
|
/* go through command-line variables too */
|
||||||
cl = config_get_commandlines(argc,argv);
|
cl = config_get_commandlines(argc,argv);
|
||||||
if (config_assign(options,cl) < 0)
|
if (config_assign(options,cl,0) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
config_free_lines(cl);
|
config_free_lines(cl);
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ static void send_control_error(connection_t *conn, uint16_t error,
|
|||||||
const char *message);
|
const char *message);
|
||||||
static void send_control_event(uint16_t event, uint16_t len, const char *body);
|
static void send_control_event(uint16_t event, uint16_t len, const char *body);
|
||||||
static int handle_control_setconf(connection_t *conn, uint16_t len,
|
static int handle_control_setconf(connection_t *conn, uint16_t len,
|
||||||
const char *body);
|
char *body);
|
||||||
static int handle_control_getconf(connection_t *conn, uint16_t len,
|
static int handle_control_getconf(connection_t *conn, uint16_t len,
|
||||||
const char *body);
|
const char *body);
|
||||||
static int handle_control_setevents(connection_t *conn, uint16_t len,
|
static int handle_control_setevents(connection_t *conn, uint16_t len,
|
||||||
@ -139,58 +139,81 @@ send_control_event(uint16_t event, uint16_t len, const char *body)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
handle_control_setconf(connection_t *conn, uint16_t len,
|
handle_control_setconf(connection_t *conn, uint16_t len,
|
||||||
const char *body)
|
char *body)
|
||||||
{
|
{
|
||||||
|
char *k, *v;
|
||||||
|
struct config_line_t *lines = NULL;
|
||||||
|
|
||||||
|
/* XXXX009 move this logic into config.c someplace. */
|
||||||
|
|
||||||
|
do {
|
||||||
|
body = parse_line_from_str(body, &k, &v);
|
||||||
|
if (!body) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (k && v)
|
||||||
|
lines = config_line_prepend(lines, k, v);
|
||||||
|
} while (*body);
|
||||||
|
|
||||||
/* XXXX009 NM */
|
/* XXXX009 NM */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
send_control_error(conn, ERR_UNSPECIFIED, "Couldn't parse configuration");
|
||||||
|
/* config_free_lines(lines); */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_control_getconf(connection_t *conn, uint16_t body_len,
|
static int
|
||||||
|
handle_control_getconf(connection_t *conn, uint16_t body_len,
|
||||||
const char *body)
|
const char *body)
|
||||||
{
|
{
|
||||||
smartlist_t *answer_elements = NULL;
|
smartlist_t *questions = NULL;
|
||||||
|
smartlist_t *answers = NULL;
|
||||||
char *msg = NULL;
|
char *msg = NULL;
|
||||||
size_t msg_len;
|
size_t msg_len;
|
||||||
|
|
||||||
if (body[body_len-1] != '\0') {
|
questions = smartlist_create();
|
||||||
send_control_error(conn, ERR_UNSPECIFIED,
|
smartlist_split_string(questions, body, "\n",
|
||||||
"getconf message body not nul-terminated.");
|
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||||
return 0;
|
answers = smartlist_create();
|
||||||
}
|
SMARTLIST_FOREACH(questions, const char *, q,
|
||||||
/* Now we can be sure that body will end in a nul-terminated string. */
|
{
|
||||||
|
struct config_line_t *answer = config_get_assigned_option(&options,q);
|
||||||
answer_elements = smartlist_create();
|
|
||||||
while (body_len) {
|
|
||||||
size_t question_len = strlen(body);
|
|
||||||
struct config_line_t *answer = config_get_assigned_option(&options,body);
|
|
||||||
if (!answer) {
|
if (!answer) {
|
||||||
send_control_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body);
|
send_control_error(conn, ERR_UNRECOGNIZED_CONFIG_KEY, body);
|
||||||
goto done;
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
while (answer) {
|
while (answer) {
|
||||||
struct config_line_t *next;
|
struct config_line_t *next;
|
||||||
smartlist_add(answer_elements, answer->key);
|
size_t alen = strlen(answer->key)+strlen(answer->value)+2;
|
||||||
smartlist_add(answer_elements, answer->value);
|
char *astr = tor_malloc(alen);
|
||||||
|
tor_snprintf(astr, alen, "%s %s\n", answer->key, answer->value);
|
||||||
|
smartlist_add(answers, astr);
|
||||||
|
|
||||||
next = answer->next;
|
next = answer->next;
|
||||||
|
tor_free(answer->key);
|
||||||
|
tor_free(answer->value);
|
||||||
tor_free(answer);
|
tor_free(answer);
|
||||||
answer = next;
|
answer = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body += question_len+1;
|
});
|
||||||
body_len -= question_len+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = smartlist_join_strings2(answer_elements, "\0", 1, 0, &msg_len);
|
msg = smartlist_join_strings(answers, "", 0, &msg_len);
|
||||||
send_control_message(conn, CONTROL_CMD_CONFVALUE,
|
send_control_message(conn, CONTROL_CMD_CONFVALUE,
|
||||||
(uint16_t)msg_len, msg);
|
(uint16_t)msg_len, msg);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
SMARTLIST_FOREACH(answer_elements, char *, cp, tor_free(cp));
|
if (answers) SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp));
|
||||||
smartlist_free(answer_elements);
|
if (questions) SMARTLIST_FOREACH(questions, char *, cp, tor_free(cp));
|
||||||
|
smartlist_free(answers);
|
||||||
|
smartlist_free(questions);
|
||||||
tor_free(msg);
|
tor_free(msg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_control_setevents(connection_t *conn, uint16_t len,
|
static int handle_control_setevents(connection_t *conn, uint16_t len,
|
||||||
const char *body)
|
const char *body)
|
||||||
{
|
{
|
||||||
@ -218,6 +241,7 @@ static int handle_control_setevents(connection_t *conn, uint16_t len,
|
|||||||
send_control_done(conn);
|
send_control_done(conn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_control_authenticate(connection_t *conn, uint16_t len,
|
static int handle_control_authenticate(connection_t *conn, uint16_t len,
|
||||||
const char *body)
|
const char *body)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user