Refactor find_first_by_keyword into one variant that can return NULL and one that can't.

This makes it easier for us to avoid errors where we we forgot to list a keyword as mandatory, and easier for Coverity to detect cases like this too.

svn:r17595
This commit is contained in:
Nick Mathewson 2008-12-11 19:40:58 +00:00
parent f3b52e331e
commit bb02f919f1

View File

@ -449,8 +449,13 @@ static int router_get_hash_impl(const char *s, char *digest,
char end_char); char end_char);
static void token_free(directory_token_t *tok); static void token_free(directory_token_t *tok);
static smartlist_t *find_all_exitpolicy(smartlist_t *s); static smartlist_t *find_all_exitpolicy(smartlist_t *s);
static directory_token_t *find_first_by_keyword(smartlist_t *s, static directory_token_t *_find_by_keyword(smartlist_t *s,
directory_keyword keyword); directory_keyword keyword,
const char *keyword_str);
#define find_by_keyword(s, keyword) _find_by_keyword((s), (keyword), #keyword)
static directory_token_t *find_opt_by_keyword(smartlist_t *s,
directory_keyword keyword);
#define TS_ANNOTATIONS_OK 1 #define TS_ANNOTATIONS_OK 1
#define TS_NOCHECK 2 #define TS_NOCHECK 2
#define TS_NO_NEW_ANNOTATIONS 4 #define TS_NO_NEW_ANNOTATIONS 4
@ -729,8 +734,7 @@ router_parse_directory(const char *str)
log_warn(LD_DIR, "Error tokenizing directory"); goto err; log_warn(LD_DIR, "Error tokenizing directory"); goto err;
} }
tok = find_first_by_keyword(tokens, K_PUBLISHED); tok = find_by_keyword(tokens, K_PUBLISHED);
tor_assert(tok);
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
if (parse_iso_time(tok->args[0], &published_on) < 0) { if (parse_iso_time(tok->args[0], &published_on) < 0) {
@ -790,13 +794,12 @@ router_parse_runningrouters(const char *str)
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_PUBLISHED); tok = find_by_keyword(tokens, K_PUBLISHED);
tor_assert(tok);
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
if (parse_iso_time(tok->args[0], &published_on) < 0) { if (parse_iso_time(tok->args[0], &published_on) < 0) {
goto err; goto err;
} }
if (!(tok = find_first_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) { if (!(tok = find_opt_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
log_warn(LD_DIR, "Missing signature on running-routers"); log_warn(LD_DIR, "Missing signature on running-routers");
goto err; goto err;
} }
@ -1182,7 +1185,7 @@ router_parse_entry_from_string(const char *s, const char *end,
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_ROUTER); tok = find_by_keyword(tokens, K_ROUTER);
tor_assert(tok->n_args >= 5); tor_assert(tok->n_args >= 5);
router = tor_malloc_zero(sizeof(routerinfo_t)); router = tor_malloc_zero(sizeof(routerinfo_t));
@ -1238,8 +1241,8 @@ router_parse_entry_from_string(const char *s, const char *end,
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_BANDWIDTH); tok = find_by_keyword(tokens, K_BANDWIDTH);
tor_assert(tok && tok->n_args >= 3); tor_assert(tok->n_args >= 3);
router->bandwidthrate = (int) router->bandwidthrate = (int)
tor_parse_long(tok->args[0],10,1,INT_MAX,&ok,NULL); tor_parse_long(tok->args[0],10,1,INT_MAX,&ok,NULL);
@ -1261,7 +1264,7 @@ router_parse_entry_from_string(const char *s, const char *end,
goto err; goto err;
} }
if ((tok = find_first_by_keyword(tokens, A_PURPOSE))) { if ((tok = find_opt_by_keyword(tokens, A_PURPOSE))) {
tor_assert(tok->n_args != 0); tor_assert(tok->n_args != 0);
router->purpose = router_purpose_from_string(tok->args[0]); router->purpose = router_purpose_from_string(tok->args[0]);
} else { } else {
@ -1270,7 +1273,7 @@ router_parse_entry_from_string(const char *s, const char *end,
router->cache_info.send_unencrypted = router->cache_info.send_unencrypted =
(router->purpose == ROUTER_PURPOSE_GENERAL) ? 1 : 0; (router->purpose == ROUTER_PURPOSE_GENERAL) ? 1 : 0;
if ((tok = find_first_by_keyword(tokens, K_UPTIME))) { if ((tok = find_opt_by_keyword(tokens, K_UPTIME))) {
tor_assert(tok->n_args >= 1); tor_assert(tok->n_args >= 1);
router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,&ok,NULL); router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,&ok,NULL);
if (!ok) { if (!ok) {
@ -1279,25 +1282,22 @@ router_parse_entry_from_string(const char *s, const char *end,
} }
} }
if ((tok = find_first_by_keyword(tokens, K_HIBERNATING))) { if ((tok = find_opt_by_keyword(tokens, K_HIBERNATING))) {
tor_assert(tok->n_args >= 1); tor_assert(tok->n_args >= 1);
router->is_hibernating router->is_hibernating
= (tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL) != 0); = (tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL) != 0);
} }
tok = find_first_by_keyword(tokens, K_PUBLISHED); tok = find_by_keyword(tokens, K_PUBLISHED);
tor_assert(tok);
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0) if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0)
goto err; goto err;
tok = find_first_by_keyword(tokens, K_ONION_KEY); tok = find_by_keyword(tokens, K_ONION_KEY);
tor_assert(tok);
router->onion_pkey = tok->key; router->onion_pkey = tok->key;
tok->key = NULL; /* Prevent free */ tok->key = NULL; /* Prevent free */
tok = find_first_by_keyword(tokens, K_SIGNING_KEY); tok = find_by_keyword(tokens, K_SIGNING_KEY);
tor_assert(tok);
router->identity_pkey = tok->key; router->identity_pkey = tok->key;
tok->key = NULL; /* Prevent free */ tok->key = NULL; /* Prevent free */
if (crypto_pk_get_digest(router->identity_pkey, if (crypto_pk_get_digest(router->identity_pkey,
@ -1305,7 +1305,7 @@ router_parse_entry_from_string(const char *s, const char *end,
log_warn(LD_DIR, "Couldn't calculate key digest"); goto err; log_warn(LD_DIR, "Couldn't calculate key digest"); goto err;
} }
if ((tok = find_first_by_keyword(tokens, K_FINGERPRINT))) { if ((tok = find_opt_by_keyword(tokens, K_FINGERPRINT))) {
/* If there's a fingerprint line, it must match the identity digest. */ /* If there's a fingerprint line, it must match the identity digest. */
char d[DIGEST_LEN]; char d[DIGEST_LEN];
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
@ -1322,15 +1322,15 @@ router_parse_entry_from_string(const char *s, const char *end,
} }
} }
if ((tok = find_first_by_keyword(tokens, K_PLATFORM))) { if ((tok = find_opt_by_keyword(tokens, K_PLATFORM))) {
router->platform = tor_strdup(tok->args[0]); router->platform = tor_strdup(tok->args[0]);
} }
if ((tok = find_first_by_keyword(tokens, K_CONTACT))) { if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) {
router->contact_info = tor_strdup(tok->args[0]); router->contact_info = tor_strdup(tok->args[0]);
} }
if ((tok = find_first_by_keyword(tokens, K_EVENTDNS))) { if ((tok = find_opt_by_keyword(tokens, K_EVENTDNS))) {
router->has_old_dnsworkers = tok->n_args && !strcmp(tok->args[0], "0"); router->has_old_dnsworkers = tok->n_args && !strcmp(tok->args[0], "0");
} else if (router->platform) { } else if (router->platform) {
if (! tor_version_as_new_as(router->platform, "0.1.2.2-alpha")) if (! tor_version_as_new_as(router->platform, "0.1.2.2-alpha"))
@ -1349,7 +1349,7 @@ router_parse_entry_from_string(const char *s, const char *end,
}); });
policy_expand_private(&router->exit_policy); policy_expand_private(&router->exit_policy);
if ((tok = find_first_by_keyword(tokens, K_FAMILY)) && tok->n_args) { if ((tok = find_opt_by_keyword(tokens, K_FAMILY)) && tok->n_args) {
int i; int i;
router->declared_family = smartlist_create(); router->declared_family = smartlist_create();
for (i=0;i<tok->n_args;++i) { for (i=0;i<tok->n_args;++i) {
@ -1362,13 +1362,13 @@ router_parse_entry_from_string(const char *s, const char *end,
} }
} }
if ((tok = find_first_by_keyword(tokens, K_CACHES_EXTRA_INFO))) if ((tok = find_opt_by_keyword(tokens, K_CACHES_EXTRA_INFO)))
router->caches_extra_info = 1; router->caches_extra_info = 1;
if ((tok = find_first_by_keyword(tokens, K_ALLOW_SINGLE_HOP_EXITS))) if ((tok = find_opt_by_keyword(tokens, K_ALLOW_SINGLE_HOP_EXITS)))
router->allow_single_hop_exits = 1; router->allow_single_hop_exits = 1;
if ((tok = find_first_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) { if ((tok = find_opt_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) {
tor_assert(tok->n_args >= 1); tor_assert(tok->n_args >= 1);
if (strlen(tok->args[0]) == HEX_DIGEST_LEN) { if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
base16_decode(router->cache_info.extra_info_digest, base16_decode(router->cache_info.extra_info_digest,
@ -1378,12 +1378,11 @@ router_parse_entry_from_string(const char *s, const char *end,
} }
} }
if ((tok = find_first_by_keyword(tokens, K_HIDDEN_SERVICE_DIR))) { if ((tok = find_opt_by_keyword(tokens, K_HIDDEN_SERVICE_DIR))) {
router->wants_to_be_hs_dir = 1; router->wants_to_be_hs_dir = 1;
} }
tok = find_first_by_keyword(tokens, K_ROUTER_SIGNATURE); tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE);
tor_assert(tok);
note_crypto_pk_op(VERIFY_RTR); note_crypto_pk_op(VERIFY_RTR);
#ifdef COUNT_DISTINCT_DIGESTS #ifdef COUNT_DISTINCT_DIGESTS
if (!verified_digests) if (!verified_digests)
@ -1494,8 +1493,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_PUBLISHED); tok = find_by_keyword(tokens, K_PUBLISHED);
tor_assert(tok);
if (parse_iso_time(tok->args[0], &extrainfo->cache_info.published_on)) { if (parse_iso_time(tok->args[0], &extrainfo->cache_info.published_on)) {
log_warn(LD_DIR,"Invalid published time %s on \"extra-info\"", log_warn(LD_DIR,"Invalid published time %s on \"extra-info\"",
escaped(tok->args[0])); escaped(tok->args[0]));
@ -1508,8 +1506,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
key = router->identity_pkey; key = router->identity_pkey;
} }
tok = find_first_by_keyword(tokens, K_ROUTER_SIGNATURE); tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE);
tor_assert(tok);
if (strcmp(tok->object_type, "SIGNATURE") || if (strcmp(tok->object_type, "SIGNATURE") ||
tok->object_size < 128 || tok->object_size > 512) { tok->object_size < 128 || tok->object_size > 512) {
log_warn(LD_DIR, "Bad object type or length on extra-info signature"); log_warn(LD_DIR, "Bad object type or length on extra-info signature");
@ -1597,20 +1594,20 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string)
cert = tor_malloc_zero(sizeof(authority_cert_t)); cert = tor_malloc_zero(sizeof(authority_cert_t));
memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN); memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
tok = find_first_by_keyword(tokens, K_DIR_SIGNING_KEY); tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
tor_assert(tok && tok->key); tor_assert(tok->key);
cert->signing_key = tok->key; cert->signing_key = tok->key;
tok->key = NULL; tok->key = NULL;
if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest)) if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest))
goto err; goto err;
tok = find_first_by_keyword(tokens, K_DIR_IDENTITY_KEY); tok = find_by_keyword(tokens, K_DIR_IDENTITY_KEY);
tor_assert(tok && tok->key); tor_assert(tok->key);
cert->identity_key = tok->key; cert->identity_key = tok->key;
tok->key = NULL; tok->key = NULL;
tok = find_first_by_keyword(tokens, K_FINGERPRINT); tok = find_by_keyword(tokens, K_FINGERPRINT);
tor_assert(tok && tok->n_args); tor_assert(tok->n_args > 0);
if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0], if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0],
strlen(tok->args[0]))) { strlen(tok->args[0]))) {
log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s", log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s",
@ -1628,7 +1625,7 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string)
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_DIR_ADDRESS); tok = find_opt_by_keyword(tokens, K_DIR_ADDRESS);
if (tok) { if (tok) {
tor_assert(tok->n_args != 0); tor_assert(tok->n_args != 0);
if (parse_addr_port(LOG_WARN, tok->args[0], NULL, &cert->addr, if (parse_addr_port(LOG_WARN, tok->args[0], NULL, &cert->addr,
@ -1638,13 +1635,11 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string)
} }
} }
tok = find_first_by_keyword(tokens, K_DIR_KEY_PUBLISHED); tok = find_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
tor_assert(tok);
if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) { if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) {
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_DIR_KEY_EXPIRES); tok = find_by_keyword(tokens, K_DIR_KEY_EXPIRES);
tor_assert(tok);
if (parse_iso_time(tok->args[0], &cert->expires) < 0) { if (parse_iso_time(tok->args[0], &cert->expires) < 0) {
goto err; goto err;
} }
@ -1763,8 +1758,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
log_warn(LD_DIR, "Impossibly short router status"); log_warn(LD_DIR, "Impossibly short router status");
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_R); tok = find_by_keyword(tokens, K_R);
tor_assert(tok);
tor_assert(tok->n_args >= 8); tor_assert(tok->n_args >= 8);
if (vote_rs) { if (vote_rs) {
rs = &vote_rs->status; rs = &vote_rs->status;
@ -1810,7 +1804,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->or_port =(uint16_t) tor_parse_long(tok->args[6],10,0,65535,NULL,NULL); rs->or_port =(uint16_t) tor_parse_long(tok->args[6],10,0,65535,NULL,NULL);
rs->dir_port = (uint16_t) tor_parse_long(tok->args[7],10,0,65535,NULL,NULL); rs->dir_port = (uint16_t) tor_parse_long(tok->args[7],10,0,65535,NULL,NULL);
tok = find_first_by_keyword(tokens, K_S); tok = find_opt_by_keyword(tokens, K_S);
if (tok && vote) { if (tok && vote) {
int i; int i;
vote_rs->flags = 0; vote_rs->flags = 0;
@ -1858,7 +1852,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
} }
} }
} }
if ((tok = find_first_by_keyword(tokens, K_V))) { if ((tok = find_opt_by_keyword(tokens, K_V))) {
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
rs->version_known = 1; rs->version_known = 1;
if (strcmpstart(tok->args[0], "Tor ")) { if (strcmpstart(tok->args[0], "Tor ")) {
@ -1881,7 +1875,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
} }
/* handle weighting/bandwidth info */ /* handle weighting/bandwidth info */
if ((tok = find_first_by_keyword(tokens, K_W))) { if ((tok = find_opt_by_keyword(tokens, K_W))) {
int i; int i;
for (i=0; i < tok->n_args; ++i) { for (i=0; i < tok->n_args; ++i) {
if (!strcmpstart(tok->args[i], "Bandwidth=")) { if (!strcmpstart(tok->args[i], "Bandwidth=")) {
@ -1898,7 +1892,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
} }
/* parse exit policy summaries */ /* parse exit policy summaries */
if ((tok = find_first_by_keyword(tokens, K_P))) { if ((tok = find_opt_by_keyword(tokens, K_P))) {
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
if (strcmpstart(tok->args[0], "accept ") && if (strcmpstart(tok->args[0], "accept ") &&
strcmpstart(tok->args[0], "reject ")) { strcmpstart(tok->args[0], "reject ")) {
@ -1985,16 +1979,15 @@ networkstatus_v2_parse_from_string(const char *s)
ns = tor_malloc_zero(sizeof(networkstatus_v2_t)); ns = tor_malloc_zero(sizeof(networkstatus_v2_t));
memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN); memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN);
tok = find_first_by_keyword(tokens, K_NETWORK_STATUS_VERSION); tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
tor_assert(tok && tok->n_args >= 1); tor_assert(tok->n_args >= 1);
if (strcmp(tok->args[0], "2")) { if (strcmp(tok->args[0], "2")) {
log_warn(LD_BUG, "Got a non-v2 networkstatus. Version was " log_warn(LD_BUG, "Got a non-v2 networkstatus. Version was "
"%s", escaped(tok->args[0])); "%s", escaped(tok->args[0]));
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_DIR_SOURCE); tok = find_by_keyword(tokens, K_DIR_SOURCE);
tor_assert(tok);
tor_assert(tok->n_args >= 3); tor_assert(tok->n_args >= 3);
ns->source_address = tor_strdup(tok->args[0]); ns->source_address = tor_strdup(tok->args[0]);
if (tor_inet_aton(tok->args[1], &in) == 0) { if (tor_inet_aton(tok->args[1], &in) == 0) {
@ -2010,8 +2003,7 @@ networkstatus_v2_parse_from_string(const char *s)
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_FINGERPRINT); tok = find_by_keyword(tokens, K_FINGERPRINT);
tor_assert(tok);
tor_assert(tok->n_args != 0); tor_assert(tok->n_args != 0);
if (base16_decode(ns->identity_digest, DIGEST_LEN, tok->args[0], if (base16_decode(ns->identity_digest, DIGEST_LEN, tok->args[0],
strlen(tok->args[0]))) { strlen(tok->args[0]))) {
@ -2020,13 +2012,13 @@ networkstatus_v2_parse_from_string(const char *s)
goto err; goto err;
} }
if ((tok = find_first_by_keyword(tokens, K_CONTACT))) { if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) {
tor_assert(tok->n_args != 0); tor_assert(tok->n_args != 0);
ns->contact = tor_strdup(tok->args[0]); ns->contact = tor_strdup(tok->args[0]);
} }
tok = find_first_by_keyword(tokens, K_DIR_SIGNING_KEY); tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
tor_assert(tok && tok->key); tor_assert(tok->key);
ns->signing_key = tok->key; ns->signing_key = tok->key;
tok->key = NULL; tok->key = NULL;
@ -2040,7 +2032,7 @@ networkstatus_v2_parse_from_string(const char *s)
goto err; goto err;
} }
if ((tok = find_first_by_keyword(tokens, K_DIR_OPTIONS))) { if ((tok = find_opt_by_keyword(tokens, K_DIR_OPTIONS))) {
for (i=0; i < tok->n_args; ++i) { for (i=0; i < tok->n_args; ++i) {
if (!strcmp(tok->args[i], "Names")) if (!strcmp(tok->args[i], "Names"))
ns->binds_names = 1; ns->binds_names = 1;
@ -2054,13 +2046,13 @@ networkstatus_v2_parse_from_string(const char *s)
} }
if (ns->recommends_versions) { if (ns->recommends_versions) {
if (!(tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS))) { if (!(tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
log_warn(LD_DIR, "Missing client-versions on versioning directory"); log_warn(LD_DIR, "Missing client-versions on versioning directory");
goto err; goto err;
} }
ns->client_versions = tor_strdup(tok->args[0]); ns->client_versions = tor_strdup(tok->args[0]);
if (!(tok = find_first_by_keyword(tokens, K_SERVER_VERSIONS)) || if (!(tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS)) ||
tok->n_args<1) { tok->n_args<1) {
log_warn(LD_DIR, "Missing server-versions on versioning directory"); log_warn(LD_DIR, "Missing server-versions on versioning directory");
goto err; goto err;
@ -2068,8 +2060,7 @@ networkstatus_v2_parse_from_string(const char *s)
ns->server_versions = tor_strdup(tok->args[0]); ns->server_versions = tor_strdup(tok->args[0]);
} }
tok = find_first_by_keyword(tokens, K_PUBLISHED); tok = find_by_keyword(tokens, K_PUBLISHED);
tor_assert(tok);
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
if (parse_iso_time(tok->args[0], &ns->published_on) < 0) { if (parse_iso_time(tok->args[0], &ns->published_on) < 0) {
goto err; goto err;
@ -2174,8 +2165,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_VOTE_STATUS); tok = find_by_keyword(tokens, K_VOTE_STATUS);
tor_assert(tok);
tor_assert(tok->n_args != 0); tor_assert(tok->n_args != 0);
if (!strcmp(tok->args[0], "vote")) { if (!strcmp(tok->args[0], "vote")) {
ns->type = NS_TYPE_VOTE; ns->type = NS_TYPE_VOTE;
@ -2194,12 +2184,12 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
} }
if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) { if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) {
tok = find_first_by_keyword(tokens, K_PUBLISHED); tok = find_by_keyword(tokens, K_PUBLISHED);
if (parse_iso_time(tok->args[0], &ns->published)) if (parse_iso_time(tok->args[0], &ns->published))
goto err; goto err;
ns->supported_methods = smartlist_create(); ns->supported_methods = smartlist_create();
tok = find_first_by_keyword(tokens, K_CONSENSUS_METHODS); tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHODS);
if (tok) { if (tok) {
for (i=0; i < tok->n_args; ++i) for (i=0; i < tok->n_args; ++i)
smartlist_add(ns->supported_methods, tor_strdup(tok->args[i])); smartlist_add(ns->supported_methods, tor_strdup(tok->args[i]));
@ -2207,7 +2197,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
smartlist_add(ns->supported_methods, tor_strdup("1")); smartlist_add(ns->supported_methods, tor_strdup("1"));
} }
} else { } else {
tok = find_first_by_keyword(tokens, K_CONSENSUS_METHOD); tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHOD);
if (tok) { if (tok) {
ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX, ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX,
&ok, NULL); &ok, NULL);
@ -2218,19 +2208,19 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
} }
} }
tok = find_first_by_keyword(tokens, K_VALID_AFTER); tok = find_by_keyword(tokens, K_VALID_AFTER);
if (parse_iso_time(tok->args[0], &ns->valid_after)) if (parse_iso_time(tok->args[0], &ns->valid_after))
goto err; goto err;
tok = find_first_by_keyword(tokens, K_FRESH_UNTIL); tok = find_by_keyword(tokens, K_FRESH_UNTIL);
if (parse_iso_time(tok->args[0], &ns->fresh_until)) if (parse_iso_time(tok->args[0], &ns->fresh_until))
goto err; goto err;
tok = find_first_by_keyword(tokens, K_VALID_UNTIL); tok = find_by_keyword(tokens, K_VALID_UNTIL);
if (parse_iso_time(tok->args[0], &ns->valid_until)) if (parse_iso_time(tok->args[0], &ns->valid_until))
goto err; goto err;
tok = find_first_by_keyword(tokens, K_VOTING_DELAY); tok = find_by_keyword(tokens, K_VOTING_DELAY);
tor_assert(tok->n_args >= 2); tor_assert(tok->n_args >= 2);
ns->vote_seconds = ns->vote_seconds =
(int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &ok, NULL); (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &ok, NULL);
@ -2257,14 +2247,14 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
goto err; goto err;
} }
if ((tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS))) { if ((tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
ns->client_versions = tor_strdup(tok->args[0]); ns->client_versions = tor_strdup(tok->args[0]);
} }
if ((tok = find_first_by_keyword(tokens, K_SERVER_VERSIONS))) { if ((tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS))) {
ns->server_versions = tor_strdup(tok->args[0]); ns->server_versions = tor_strdup(tok->args[0]);
} }
tok = find_first_by_keyword(tokens, K_KNOWN_FLAGS); tok = find_by_keyword(tokens, K_KNOWN_FLAGS);
ns->known_flags = smartlist_create(); ns->known_flags = smartlist_create();
inorder = 1; inorder = 1;
for (i = 0; i < tok->n_args; ++i) { for (i = 0; i < tok->n_args; ++i) {
@ -2357,7 +2347,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
} }
if (ns->type != NS_TYPE_CONSENSUS && if (ns->type != NS_TYPE_CONSENSUS &&
(tok = find_first_by_keyword(tokens, K_LEGACY_DIR_KEY))) { (tok = find_opt_by_keyword(tokens, K_LEGACY_DIR_KEY))) {
int bad = 1; int bad = 1;
if (strlen(tok->args[0]) == HEX_DIGEST_LEN) { if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0); networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0);
@ -2551,8 +2541,7 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_CONSENSUS_DIGEST); tok = find_by_keyword(tokens, K_CONSENSUS_DIGEST);
tor_assert(tok);
if (strlen(tok->args[0]) != HEX_DIGEST_LEN) { if (strlen(tok->args[0]) != HEX_DIGEST_LEN) {
log_warn(LD_DIR, "Wrong length on consensus-digest in detached " log_warn(LD_DIR, "Wrong length on consensus-digest in detached "
"networkstatus signatures"); "networkstatus signatures");
@ -2565,19 +2554,19 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_VALID_AFTER); tok = find_by_keyword(tokens, K_VALID_AFTER);
if (parse_iso_time(tok->args[0], &sigs->valid_after)) { if (parse_iso_time(tok->args[0], &sigs->valid_after)) {
log_warn(LD_DIR, "Bad valid-after in detached networkstatus signatures"); log_warn(LD_DIR, "Bad valid-after in detached networkstatus signatures");
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_FRESH_UNTIL); tok = find_by_keyword(tokens, K_FRESH_UNTIL);
if (parse_iso_time(tok->args[0], &sigs->fresh_until)) { if (parse_iso_time(tok->args[0], &sigs->fresh_until)) {
log_warn(LD_DIR, "Bad fresh-until in detached networkstatus signatures"); log_warn(LD_DIR, "Bad fresh-until in detached networkstatus signatures");
goto err; goto err;
} }
tok = find_first_by_keyword(tokens, K_VALID_UNTIL); tok = find_by_keyword(tokens, K_VALID_UNTIL);
if (parse_iso_time(tok->args[0], &sigs->valid_until)) { if (parse_iso_time(tok->args[0], &sigs->valid_until)) {
log_warn(LD_DIR, "Bad valid-until in detached networkstatus signatures"); log_warn(LD_DIR, "Bad valid-until in detached networkstatus signatures");
goto err; goto err;
@ -3165,12 +3154,28 @@ tokenize_string(memarea_t *area,
* NULL if no such keyword is found. * NULL if no such keyword is found.
*/ */
static directory_token_t * static directory_token_t *
find_first_by_keyword(smartlist_t *s, directory_keyword keyword) find_opt_by_keyword(smartlist_t *s, directory_keyword keyword)
{ {
SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == keyword) return t); SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == keyword) return t);
return NULL; return NULL;
} }
/** Find the first token in <b>s</b> whose keyword is <b>keyword</b>; fail
* with an assert if no such keyword is found.
*/
static directory_token_t *
_find_by_keyword(smartlist_t *s, directory_keyword keyword,
const char *keyword_as_string)
{
directory_token_t *tok = find_opt_by_keyword(s, keyword);
if (PREDICT_UNLIKELY(!tok)) {
log_err(LD_BUG, "Missing %s [%d] in directory object that should have "
"been validated. Internal error.", keyword_as_string, (int)keyword);
tor_assert(tok);
}
return tok;
}
/** Return a newly allocated smartlist of all accept or reject tokens in /** Return a newly allocated smartlist of all accept or reject tokens in
* <b>s</b>. * <b>s</b>.
*/ */
@ -3497,8 +3502,7 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
goto err; goto err;
} }
/* Parse base32-encoded descriptor ID. */ /* Parse base32-encoded descriptor ID. */
tok = find_first_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR); tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
tor_assert(tok);
tor_assert(tok == smartlist_get(tokens, 0)); tor_assert(tok == smartlist_get(tokens, 0));
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
if (strlen(tok->args[0]) != REND_DESC_ID_V2_LEN_BASE32 || if (strlen(tok->args[0]) != REND_DESC_ID_V2_LEN_BASE32 ||
@ -3513,8 +3517,7 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
goto err; goto err;
} }
/* Parse descriptor version. */ /* Parse descriptor version. */
tok = find_first_by_keyword(tokens, R_VERSION); tok = find_by_keyword(tokens, R_VERSION);
tor_assert(tok);
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
result->version = result->version =
(int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL); (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
@ -3528,13 +3531,11 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
goto err; goto err;
} }
/* Parse public key. */ /* Parse public key. */
tok = find_first_by_keyword(tokens, R_PERMANENT_KEY); tok = find_by_keyword(tokens, R_PERMANENT_KEY);
tor_assert(tok);
result->pk = tok->key; result->pk = tok->key;
tok->key = NULL; /* Prevent free */ tok->key = NULL; /* Prevent free */
/* Parse secret ID part. */ /* Parse secret ID part. */
tok = find_first_by_keyword(tokens, R_SECRET_ID_PART); tok = find_by_keyword(tokens, R_SECRET_ID_PART);
tor_assert(tok);
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 || if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) { strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
@ -3548,16 +3549,14 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
} }
/* Parse publication time -- up-to-date check is done when storing the /* Parse publication time -- up-to-date check is done when storing the
* descriptor. */ * descriptor. */
tok = find_first_by_keyword(tokens, R_PUBLICATION_TIME); tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
tor_assert(tok);
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
if (parse_iso_time(tok->args[0], &result->timestamp) < 0) { if (parse_iso_time(tok->args[0], &result->timestamp) < 0) {
log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]); log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
goto err; goto err;
} }
/* Parse protocol versions. */ /* Parse protocol versions. */
tok = find_first_by_keyword(tokens, R_PROTOCOL_VERSIONS); tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS);
tor_assert(tok);
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
versions = smartlist_create(); versions = smartlist_create();
smartlist_split_string(versions, tok->args[0], ",", smartlist_split_string(versions, tok->args[0], ",",
@ -3572,7 +3571,7 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
smartlist_free(versions); smartlist_free(versions);
/* Parse encrypted introduction points. Don't verify. */ /* Parse encrypted introduction points. Don't verify. */
tok = find_first_by_keyword(tokens, R_INTRODUCTION_POINTS); tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS);
if (tok) { if (tok) {
if (strcmp(tok->object_type, "MESSAGE")) { if (strcmp(tok->object_type, "MESSAGE")) {
log_warn(LD_DIR, "Bad object type: introduction points should be of " log_warn(LD_DIR, "Bad object type: introduction points should be of "
@ -3587,8 +3586,7 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
*intro_points_encrypted_size_out = 0; *intro_points_encrypted_size_out = 0;
} }
/* Parse and verify signature. */ /* Parse and verify signature. */
tok = find_first_by_keyword(tokens, R_SIGNATURE); tok = find_by_keyword(tokens, R_SIGNATURE);
tor_assert(tok);
note_crypto_pk_op(VERIFY_RTR); note_crypto_pk_op(VERIFY_RTR);
if (check_signature_token(desc_hash, tok, result->pk, 0, if (check_signature_token(desc_hash, tok, result->pk, 0,
"v2 rendezvous service descriptor") < 0) "v2 rendezvous service descriptor") < 0)
@ -3786,8 +3784,7 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed,
intro = tor_malloc_zero(sizeof(rend_intro_point_t)); intro = tor_malloc_zero(sizeof(rend_intro_point_t));
info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t)); info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
/* Parse identifier. */ /* Parse identifier. */
tok = find_first_by_keyword(tokens, R_IPO_IDENTIFIER); tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
tor_assert(tok);
if (base32_decode(info->identity_digest, DIGEST_LEN, if (base32_decode(info->identity_digest, DIGEST_LEN,
tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) { tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) {
log_warn(LD_REND, "Identity digest contains illegal characters: %s", log_warn(LD_REND, "Identity digest contains illegal characters: %s",
@ -3800,7 +3797,7 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed,
base16_encode(info->nickname + 1, sizeof(info->nickname) - 1, base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
info->identity_digest, DIGEST_LEN); info->identity_digest, DIGEST_LEN);
/* Parse IP address. */ /* Parse IP address. */
tok = find_first_by_keyword(tokens, R_IPO_IP_ADDRESS); tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
if (tor_addr_from_str(&info->addr, tok->args[0])<0) { if (tor_addr_from_str(&info->addr, tok->args[0])<0) {
log_warn(LD_REND, "Could not parse introduction point address."); log_warn(LD_REND, "Could not parse introduction point address.");
rend_intro_point_free(intro); rend_intro_point_free(intro);
@ -3813,7 +3810,7 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed,
} }
/* Parse onion port. */ /* Parse onion port. */
tok = find_first_by_keyword(tokens, R_IPO_ONION_PORT); tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535, info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
&num_ok,NULL); &num_ok,NULL);
if (!info->port || !num_ok) { if (!info->port || !num_ok) {
@ -3823,11 +3820,11 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed,
goto err; goto err;
} }
/* Parse onion key. */ /* Parse onion key. */
tok = find_first_by_keyword(tokens, R_IPO_ONION_KEY); tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
info->onion_key = tok->key; info->onion_key = tok->key;
tok->key = NULL; /* Prevent free */ tok->key = NULL; /* Prevent free */
/* Parse service key. */ /* Parse service key. */
tok = find_first_by_keyword(tokens, R_IPO_SERVICE_KEY); tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY);
intro->intro_key = tok->key; intro->intro_key = tok->key;
tok->key = NULL; /* Prevent free */ tok->key = NULL; /* Prevent free */
/* Add extend info to list of introduction points. */ /* Add extend info to list of introduction points. */
@ -3897,8 +3894,7 @@ rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
goto err; goto err;
} }
/* Parse client name. */ /* Parse client name. */
tok = find_first_by_keyword(tokens, C_CLIENT_NAME); tok = find_by_keyword(tokens, C_CLIENT_NAME);
tor_assert(tok);
tor_assert(tok == smartlist_get(tokens, 0)); tor_assert(tok == smartlist_get(tokens, 0));
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
@ -3920,15 +3916,14 @@ rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
parsed_entry->client_name = tor_strdup(tok->args[0]); parsed_entry->client_name = tor_strdup(tok->args[0]);
strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry); strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
/* Parse client key. */ /* Parse client key. */
tok = find_first_by_keyword(tokens, C_CLIENT_KEY); tok = find_opt_by_keyword(tokens, C_CLIENT_KEY);
if (tok) { if (tok) {
parsed_entry->client_key = tok->key; parsed_entry->client_key = tok->key;
tok->key = NULL; /* Prevent free */ tok->key = NULL; /* Prevent free */
} }
/* Parse descriptor cookie. */ /* Parse descriptor cookie. */
tok = find_first_by_keyword(tokens, C_DESCRIPTOR_COOKIE); tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
tor_assert(tok);
tor_assert(tok->n_args == 1); tor_assert(tok->n_args == 1);
if (strlen(tok->args[0]) != REND_DESC_COOKIE_LEN_BASE64 + 2) { if (strlen(tok->args[0]) != REND_DESC_COOKIE_LEN_BASE64 + 2) {
log_warn(LD_REND, "Descriptor cookie has illegal length: %s", log_warn(LD_REND, "Descriptor cookie has illegal length: %s",