diff options
author | Nick Mathewson <nickm@torproject.org> | 2007-04-16 16:28:06 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2007-04-16 16:28:06 +0000 |
commit | 7fb7658a45d36e9a0b5f6f73fb907c3d0405da33 (patch) | |
tree | 9db5213b0c760ca332921e4d99909f3a05115372 /src/or | |
parent | 32c57918a0c672873050494cfa579d92cb042d3f (diff) | |
download | tor-7fb7658a45d36e9a0b5f6f73fb907c3d0405da33.tar.gz tor-7fb7658a45d36e9a0b5f6f73fb907c3d0405da33.zip |
r12401@catbus: nickm | 2007-04-16 12:28:01 -0400
Enforce checks for number of arguments to items in directory objects more uniformly.
svn:r9968
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/routerparse.c | 270 |
1 files changed, 122 insertions, 148 deletions
diff --git a/src/or/routerparse.c b/src/or/routerparse.c index d933c873a0..2722eae7dc 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -80,20 +80,13 @@ typedef struct directory_token_t { size_t object_size; /**< Bytes in object_body */ char *object_body; /**< Contents of object, base64-decoded. */ crypto_pk_env_t *key; /**< For public keys only. */ - const char *error; /**< For _ERR tokens only. */ + char *error; /**< For _ERR tokens only. */ } directory_token_t; /* ********************************************************************** */ /** We use a table of rules to decide how to parse each token type. */ -/** Rules for how many arguments a keyword can take. */ -typedef enum { - NO_ARGS, /**< No arguments, ever. */ - ARGS, /**< A list of arguments separated by spaces. */ - CONCAT_ARGS, /**< The rest of the line, treated as a single argument. */ -} arg_syntax; - /** Rules for whether the keyword needs an object. */ typedef enum { NO_OBJ, /**< No object, ever. */ @@ -104,38 +97,46 @@ typedef enum { /** DOCDOC */ typedef struct token_rule_t { - const char *t; directory_keyword v; arg_syntax s; obj_syntax os; + const char *t; directory_keyword v; + int min_args; int max_args; int concat_args; + obj_syntax os; int min_cnt; int max_cnt; } token_rule_t; /** DOCDOC */ -#define END_OF_TABLE { NULL, _NIL, NO_ARGS, NO_OBJ, 0, INT_MAX } +#define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX } #define T(s,t,a,o) { s, t, a, o, 0, INT_MAX } #define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX } #define T1(s,t,a,o) { s, t, a, o, 1, 1 } #define T01(s,t,a,o) { s, t, a, o, 0, 1 } +#define ARGS 0,INT_MAX,0 +#define NO_ARGS 0,0,0 +#define CONCAT_ARGS 1,1,1 +#define GE(n) n,INT_MAX,0 +#define EQ(n) n,n,0 + /** DOCDOC */ static token_rule_t routerdesc_token_table[] = { T0N("accept", K_ACCEPT, ARGS, NO_OBJ ), T0N("reject", K_REJECT, ARGS, NO_OBJ ), - T1( "router", K_ROUTER, ARGS, NO_OBJ ), + T1( "router", K_ROUTER, GE(5), NO_OBJ ), T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY ), T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY ), T1( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ), T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T01("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ), - T01("uptime", K_UPTIME, ARGS, NO_OBJ ), + T01("uptime", K_UPTIME, GE(1), NO_OBJ ), T01("family", K_FAMILY, ARGS, NO_OBJ ), T01("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ), - T01("hibernating", K_HIBERNATING, ARGS, NO_OBJ ), + T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ ), T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ), T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ), T01("eventdns", K_EVENTDNS, ARGS, NO_OBJ ), - T01("extra-info-digest", K_EXTRA_INFO_DIGEST, ARGS, NO_OBJ ), + T01("extra-info-digest", K_EXTRA_INFO_DIGEST, GE(1), NO_OBJ ), T01("caches-extra-info", K_CACHES_EXTRA_INFO, NO_ARGS, NO_OBJ ), - T1("bandwidth", K_BANDWIDTH, ARGS, NO_OBJ ), + T1( "bandwidth", K_BANDWIDTH, GE(3), NO_OBJ ), T01("platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ ), END_OF_TABLE @@ -147,13 +148,13 @@ static token_rule_t extrainfo_token_table[] = { T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ), T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ), - T1( "extra-info", K_EXTRA_INFO, ARGS, NO_OBJ ), + T1( "extra-info", K_EXTRA_INFO, GE(2), NO_OBJ ), END_OF_TABLE }; static token_rule_t rtrstatus_token_table[] = { - T1( "r", K_R, ARGS, NO_OBJ ), + T1( "r", K_R, GE(8), NO_OBJ ), T1( "s", K_S, ARGS, NO_OBJ ), T01("v", K_V, CONCAT_ARGS, NO_OBJ ), T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), @@ -164,20 +165,21 @@ static token_rule_t netstatus_token_table[] = { T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ), + /* XXXX should dir-signing-key really have ARGS? */ T1( "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, NEED_KEY ), T1( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ), T1( "network-status-version", K_NETWORK_STATUS_VERSION, - ARGS, NO_OBJ ), - T1( "dir-source", K_DIR_SOURCE, ARGS, NO_OBJ ), + GE(1), NO_OBJ ), + T1( "dir-source", K_DIR_SOURCE, GE(3), NO_OBJ ), T01("dir-options", K_DIR_OPTIONS, ARGS, NO_OBJ ), - T01("client-versions", K_CLIENT_VERSIONS, ARGS, NO_OBJ ), - T01("server-versions", K_SERVER_VERSIONS, ARGS, NO_OBJ ), + T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ), + T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ), END_OF_TABLE }; static token_rule_t dir_footer_token_table[] = { - T1( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ ), + T1( "directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ), END_OF_TABLE }; @@ -185,12 +187,12 @@ static token_rule_t dir_token_table[] = { /* don't enforce counts; this is obsolete. */ T( "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ ), T( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ ), - T( "recommended-software",K_RECOMMENDED_SOFTWARE,ARGS, NO_OBJ ), + T( "recommended-software",K_RECOMMENDED_SOFTWARE,CONCAT_ARGS, NO_OBJ ), T( "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS, NO_OBJ ), T( "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ ), T( "router-status", K_ROUTER_STATUS, ARGS, NO_OBJ ), - T1("published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), + T( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), T( "opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ), T( "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK ), @@ -642,10 +644,7 @@ check_directory_signature(const char *digest, char signed_digest[PK_BYTES]; crypto_pk_env_t *_pkey = NULL; - if (tok->n_args != 1) { - log_warn(LD_DIR, "Too many or too few arguments to directory-signature"); - return -1; - } + tor_assert(tok->n_args == 1); if (declared_key) { if (!check_authority || dir_signing_key_is_trusted(declared_key)) @@ -827,6 +826,7 @@ router_parse_entry_from_string(const char *s, const char *end, log_warn(LD_DIR,"Entry does not start with \"router\""); goto err; } + tor_assert(tok->n_args >= 5); router = tor_malloc_zero(sizeof(routerinfo_t)); router->routerlist_index = -1; @@ -835,70 +835,49 @@ router_parse_entry_from_string(const char *s, const char *end, router->cache_info.signed_descriptor_len = end-s; memcpy(router->cache_info.signed_descriptor_digest, digest, DIGEST_LEN); - if (tok->n_args >= 5) { - router->nickname = tor_strdup(tok->args[0]); - if (!is_legal_nickname(router->nickname)) { - log_warn(LD_DIR,"Router nickname is invalid"); - goto err; - } - router->address = tor_strdup(tok->args[1]); - if (!tor_inet_aton(router->address, &in)) { - log_warn(LD_DIR,"Router address is not an IP."); - goto err; - } - router->addr = ntohl(in.s_addr); - router->or_port = - (uint16_t) tor_parse_long(tok->args[2],10,0,65535,NULL,NULL); - router->dir_port = - (uint16_t) tor_parse_long(tok->args[4],10,0,65535,NULL,NULL); - } else { - log_warn(LD_DIR,"Wrong # of arguments to \"router\" (%d)",tok->n_args); + router->nickname = tor_strdup(tok->args[0]); + if (!is_legal_nickname(router->nickname)) { + log_warn(LD_DIR,"Router nickname is invalid"); goto err; } - - tok = find_first_by_keyword(tokens, K_BANDWIDTH); - if (!tok) { - log_warn(LD_DIR,"No bandwidth declared; failing."); + router->address = tor_strdup(tok->args[1]); + if (!tor_inet_aton(router->address, &in)) { + log_warn(LD_DIR,"Router address is not an IP."); goto err; - } else { - if (tok->n_args < 3) { - log_warn(LD_DIR, - "Not enough arguments to \"bandwidth\" in server descriptor."); - goto err; - } - router->bandwidthrate = - tor_parse_long(tok->args[0],10,0,INT_MAX,NULL,NULL); + } + router->addr = ntohl(in.s_addr); - if (!router->bandwidthrate) { - log_warn(LD_DIR, "bandwidthrate %s unreadable or 0. Failing.", - escaped(tok->args[0])); - goto err; - } + router->or_port = + (uint16_t) tor_parse_long(tok->args[2],10,0,65535,NULL,NULL); + router->dir_port = + (uint16_t) tor_parse_long(tok->args[4],10,0,65535,NULL,NULL); - router->bandwidthburst = - tor_parse_long(tok->args[1],10,0,INT_MAX,NULL,NULL); - router->bandwidthcapacity = - tor_parse_long(tok->args[2],10,0,INT_MAX,NULL,NULL); + tok = find_first_by_keyword(tokens, K_BANDWIDTH); + tor_assert(tok && tok->n_args >= 3); + router->bandwidthrate = + tor_parse_long(tok->args[0],10,0,INT_MAX,NULL,NULL); - /* XXX we don't error-check these values? -RD */ + if (!router->bandwidthrate) { + log_warn(LD_DIR, "bandwidthrate %s unreadable or 0. Failing.", + escaped(tok->args[0])); + goto err; } + router->bandwidthburst = + tor_parse_long(tok->args[1],10,0,INT_MAX,NULL,NULL); + router->bandwidthcapacity = + tor_parse_long(tok->args[2],10,0,INT_MAX,NULL,NULL); + /* XXX we don't error-check these values? -RD */ if ((tok = find_first_by_keyword(tokens, K_UPTIME))) { - if (tok->n_args != 1) { - log_warn(LD_DIR, "Unrecognized number of args on K_UPTIME; skipping."); - } else { - router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL); - } + tor_assert(tok->n_args >= 1); + router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL); } if ((tok = find_first_by_keyword(tokens, K_HIBERNATING))) { - if (tok->n_args < 1) { - log_warn(LD_DIR, "Too few args on 'hibernating' keyword. Skipping."); - } else { - router->is_hibernating - = (tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL) != 0); - } + tor_assert(tok->n_args >= 1); + router->is_hibernating + = (tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL) != 0); } tok = find_first_by_keyword(tokens, K_PUBLISHED); @@ -934,10 +913,7 @@ router_parse_entry_from_string(const char *s, const char *end, if ((tok = find_first_by_keyword(tokens, K_FINGERPRINT))) { /* If there's a fingerprint line, it must match the identity digest. */ char d[DIGEST_LEN]; - if (tok->n_args < 1) { - log_warn(LD_DIR, "Too few arguments to router fingerprint"); - goto err; - } + tor_assert(tok->n_args == 1); tor_strstrip(tok->args[0], " "); if (base16_decode(d, DIGEST_LEN, tok->args[0], strlen(tok->args[0]))) { log_warn(LD_DIR, "Couldn't decode router fingerprint %s", @@ -989,8 +965,8 @@ router_parse_entry_from_string(const char *s, const char *end, if ((tok = find_first_by_keyword(tokens, K_CACHES_EXTRA_INFO))) router->caches_extra_info = 1; - if ((tok = find_first_by_keyword(tokens, K_EXTRA_INFO_DIGEST)) && - tok->n_args) { + if ((tok = find_first_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) { + tor_assert(tok->n_args >= 1); if (strlen(tok->args[0]) == HEX_DIGEST_LEN) { base16_decode(router->extra_info_digest, DIGEST_LEN, tok->args[0], HEX_DIGEST_LEN); @@ -1094,11 +1070,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end, extrainfo->cache_info.signed_descriptor_body = tor_strndup(s, end-s); extrainfo->cache_info.signed_descriptor_len = end-s; memcpy(extrainfo->cache_info.signed_descriptor_digest, digest, DIGEST_LEN); - - if (tok->n_args < 2) { - log_warn(LD_DIR,"Insufficient arguments to \"extra-info\""); - goto err; - } + tor_assert(tok->n_args >= 2); if (!is_legal_nickname(tok->args[0])) { log_warn(LD_DIR,"Bad nickname %s on \"extra-info\"",escaped(tok->args[0])); goto err; @@ -1203,10 +1175,7 @@ routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens) } tok = find_first_by_keyword(tokens, K_R); tor_assert(tok); - if (tok->n_args < 8) { - log_warn(LD_DIR, - "Too few arguments to 'r' keywork in router status; skipping."); - } + tor_assert(tok->n_args >= 8); rs = tor_malloc_zero(sizeof(routerstatus_t)); if (!is_legal_nickname(tok->args[0])) { @@ -1272,7 +1241,8 @@ routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens) rs->is_bad_directory = 1; } } - if ((tok = find_first_by_keyword(tokens, K_V)) && tok->n_args) { + if ((tok = find_first_by_keyword(tokens, K_V))) { + tor_assert(tok->n_args == 1); rs->version_known = 1; if (strcmpstart(tok->args[0], "Tor ")) { rs->version_supports_begindir = 1; @@ -1352,10 +1322,7 @@ networkstatus_parse_from_string(const char *s) tok = find_first_by_keyword(tokens, K_DIR_SOURCE); tor_assert(tok); - if (tok->n_args < 3) { - log_warn(LD_DIR, "Too few arguments to dir-source keyword"); - goto err; - } + tor_assert(tok->n_args >= 3); ns->source_address = tok->args[0]; tok->args[0] = NULL; if (tor_inet_aton(tok->args[1], &in) == 0) { log_warn(LD_DIR, "Error parsing network-status source address %s", @@ -1372,10 +1339,7 @@ networkstatus_parse_from_string(const char *s) tok = find_first_by_keyword(tokens, K_FINGERPRINT); tor_assert(tok); - if (tok->n_args < 1) { - log_warn(LD_DIR, "Too few arguments to networkstatus fingerprint"); - goto err; - } + tor_assert(tok->n_args); if (base16_decode(ns->identity_digest, DIGEST_LEN, tok->args[0], strlen(tok->args[0]))) { log_warn(LD_DIR, "Couldn't decode networkstatus fingerprint %s", @@ -1383,7 +1347,8 @@ networkstatus_parse_from_string(const char *s) goto err; } - if ((tok = find_first_by_keyword(tokens, K_CONTACT)) && tok->n_args) { + if ((tok = find_first_by_keyword(tokens, K_CONTACT))) { + tor_assert(tok->n_args); ns->contact = tok->args[0]; tok->args[0] = NULL; } @@ -1417,8 +1382,7 @@ networkstatus_parse_from_string(const char *s) } if (ns->recommends_versions) { - if (!(tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS)) || - tok->n_args<1) { + if (!(tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS))) { log_warn(LD_DIR, "Missing client-versions"); } ns->client_versions = tok->args[0]; @@ -1684,6 +1648,7 @@ token_free(directory_token_t *tok) } tor_free(tok->object_type); tor_free(tok->object_body); + tor_free(tok->error); if (tok->key) crypto_free_pk_env(tok->key); tor_free(tok); @@ -1696,17 +1661,19 @@ static directory_token_t * get_next_token(const char **s, struct token_rule_t *table) { const char *next, *obstart; - int i, done, allocated, is_opt; + int i, j, done, allocated, is_opt; directory_token_t *tok; - arg_syntax a_syn; obj_syntax o_syn = NO_OBJ; + char ebuf[128]; + const char *kwd = ""; -#define RET_ERR(msg) \ - do { if (tok) token_free(tok); \ - tok = tor_malloc_zero(sizeof(directory_token_t));\ - tok->tp = _ERR; \ - tok->error = msg; \ - goto done_tokenizing; } while (0) +#define RET_ERR(msg) \ + do { \ + if (tok) token_free(tok); \ + tok = tor_malloc_zero(sizeof(directory_token_t)); \ + tok->tp = _ERR; \ + tok->error = tor_strdup(msg); \ + goto done_tokenizing; } while (0) tok = tor_malloc_zero(sizeof(directory_token_t)); tok->tp = _ERR; @@ -1718,7 +1685,7 @@ get_next_token(const char **s, struct token_rule_t *table) } next = find_whitespace(*s); if (!next) { - tok->error = "Unexpected EOF"; return tok; + tok->error = tor_strdup("Unexpected EOF"); return tok; } /* It's a keyword... but which one? */ is_opt = !strncmp("opt", *s, next-*s); @@ -1734,12 +1701,22 @@ get_next_token(const char **s, struct token_rule_t *table) for (i = 0; table[i].t ; ++i) { if (!strncmp(table[i].t, *s, next-*s)) { /* We've found the keyword. */ + kwd = table[i].t; tok->tp = table[i].v; - a_syn = table[i].s; o_syn = table[i].os; - if (a_syn == ARGS) { + if (table[i].concat_args) { + /* The keyword takes the line as a single argument */ + *s = eat_whitespace_no_nl(next); + next = strchr(*s, '\n'); + if (!next) + RET_ERR("Unexpected EOF"); + tok->args = tor_malloc(sizeof(char*)); + tok->args[0] = tor_strndup(*s,next-*s); + tok->n_args = 1; + *s = eat_whitespace_no_nl(next+1); + } else { /* This keyword takes multiple arguments. */ - i = 0; + j = 0; done = (*next == '\n'); allocated = 32; tok->args = tor_malloc(sizeof(char*)*32); @@ -1748,34 +1725,23 @@ get_next_token(const char **s, struct token_rule_t *table) next = find_whitespace(*s); if (*next == '\n') done = 1; - if (i == allocated) { + if (j == allocated) { allocated *= 2; tok->args = tor_realloc(tok->args,sizeof(char*)*allocated); } - tok->args[i++] = tor_strndup(*s,next-*s); + tok->args[j++] = tor_strndup(*s,next-*s); *s = eat_whitespace_no_nl(next+1); } - tok->n_args = i; - } else if (a_syn == CONCAT_ARGS) { - /* The keyword takes the line as a single argument */ - *s = eat_whitespace_no_nl(next); - next = strchr(*s, '\n'); - if (!next) - RET_ERR("Unexpected EOF"); - tok->args = tor_malloc(sizeof(char*)); - tok->args[0] = tor_strndup(*s,next-*s); - tok->n_args = 1; - *s = eat_whitespace_no_nl(next+1); - } else { - /* The keyword takes no arguments. */ - tor_assert(a_syn == NO_ARGS); - *s = eat_whitespace_no_nl(next); - if (**s != '\n') { - RET_ERR("Unexpected arguments"); - } - tok->n_args = 0; - *s = eat_whitespace_no_nl(*s+1); + tok->n_args = j; } + if (tok->n_args < table[i].min_args) { + tor_snprintf(ebuf, sizeof(ebuf), "Too few arguments to %s", kwd); + RET_ERR(ebuf); + } else if (tok->n_args > table[i].max_args) { + tor_snprintf(ebuf, sizeof(ebuf), "Too many arguments to %s", kwd); + RET_ERR(ebuf); + } + break; } } @@ -1832,18 +1798,26 @@ get_next_token(const char **s, struct token_rule_t *table) switch (o_syn) { case NO_OBJ: - if (tok->object_body) - RET_ERR("Unexpected object for keyword"); - if (tok->key) - RET_ERR("Unexpected public key for keyword"); + if (tok->object_body) { + tor_snprintf(ebuf, sizeof(ebuf), "Unexpected object for %s", kwd); + RET_ERR(ebuf); + } + if (tok->key) { + tor_snprintf(ebuf, sizeof(ebuf), "Unexpected public key for %s", kwd); + RET_ERR(ebuf); + } break; case NEED_OBJ: - if (!tok->object_body) - RET_ERR("Missing object for keyword"); + if (!tok->object_body) { + tor_snprintf(ebuf, sizeof(ebuf), "Missing object for %s", kwd); + RET_ERR(ebuf); + } break; case NEED_KEY: - if (!tok->key) - RET_ERR("Missing public key for keyword"); + if (!tok->key) { + tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd); + RET_ERR(ebuf); + } break; case OBJ_OK: break; |