[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r10192: Cleanup, lock-down, and refactor bits of routerparse.c: use (in tor/trunk: . src/or)
- To: or-cvs@xxxxxxxxxxxxx
- Subject: [or-cvs] r10192: Cleanup, lock-down, and refactor bits of routerparse.c: use (in tor/trunk: . src/or)
- From: nickm@xxxxxxxx
- Date: Mon, 14 May 2007 18:51:06 -0400 (EDT)
- Delivered-to: archiver@seul.org
- Delivered-to: or-cvs-outgoing@seul.org
- Delivered-to: or-cvs@seul.org
- Delivery-date: Mon, 14 May 2007 18:51:15 -0400
- Reply-to: or-dev@xxxxxxxxxxxxx
- Sender: owner-or-cvs@xxxxxxxxxxxxx
Author: nickm
Date: 2007-05-14 18:51:05 -0400 (Mon, 14 May 2007)
New Revision: 10192
Modified:
tor/trunk/
tor/trunk/src/or/or.h
tor/trunk/src/or/routerlist.c
tor/trunk/src/or/routerparse.c
Log:
r12758@catbus: nickm | 2007-05-14 15:19:29 -0400
Cleanup, lock-down, and refactor bits of routerparse.c: use a single unified function to check all signatures. Fix all DOCDOCs. Remove some old dead debugging code. Enforce some parsing rules better.
Property changes on: tor/trunk
___________________________________________________________________
svk:merge ticket from /tor/trunk [r12758] on 8246c3cf-6607-4228-993b-4d95d33730f1
Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h 2007-05-14 20:29:22 UTC (rev 10191)
+++ tor/trunk/src/or/or.h 2007-05-14 22:51:05 UTC (rev 10192)
@@ -1155,6 +1155,8 @@
/** If present, we didn't have the right key to verify this extra-info,
* so this is a copy of the signature in the document. */
char *pending_sig;
+ /** DOCDOC */
+ size_t pending_sig_len;
} extrainfo_t;
/** Contents of a single router entry in a network status object.
Modified: tor/trunk/src/or/routerlist.c
===================================================================
--- tor/trunk/src/or/routerlist.c 2007-05-14 20:29:22 UTC (rev 10191)
+++ tor/trunk/src/or/routerlist.c 2007-05-14 22:51:05 UTC (rev 10192)
@@ -4669,7 +4669,7 @@
if (ei->pending_sig) {
char signed_digest[128];
if (crypto_pk_public_checksig(ri->identity_pkey, signed_digest,
- ei->pending_sig, 128) != 20 ||
+ ei->pending_sig, ei->pending_sig_len) != DIGEST_LEN ||
memcmp(signed_digest, ei->cache_info.signed_descriptor_digest,
DIGEST_LEN)) {
ei->bad_sig = 1;
Modified: tor/trunk/src/or/routerparse.c
===================================================================
--- tor/trunk/src/or/routerparse.c 2007-05-14 20:29:22 UTC (rev 10191)
+++ tor/trunk/src/or/routerparse.c 2007-05-14 22:51:05 UTC (rev 10192)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2001 Matej Pfajfar.
+/* oCpyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2007, Roger Dingledine, Nick Mathewson. */
/* See LICENSE for licensing information */
@@ -102,61 +102,104 @@
/** Rules for whether the keyword needs an object. */
typedef enum {
- NO_OBJ, /**< No object, ever. */
- NEED_OBJ, /**< Object is required. */
- NEED_KEY_1024, /**< Object is required, and must be a public key of 1024 bits */
- NEED_KEY, /**< Object is required, and must be a public key. */
- OBJ_OK, /**< Object is optional. */
+ NO_OBJ, /**< No object, ever. */
+ NEED_OBJ, /**< Object is required. */
+ NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */
+ NEED_KEY, /**< Object is required, and must be a public key. */
+ OBJ_OK, /**< Object is optional. */
} obj_syntax;
-/** DOCDOC */
+#define AT_START 1
+#define AT_END 1
+
+/** Determines the parsing rules for a single token type. */
typedef struct token_rule_t {
- const char *t; directory_keyword v;
- int min_args; int max_args; int concat_args;
+ /** The string value of the keyword identifying the type of item. */
+ const char *t;
+ /** The corresponding directory_keyword enum. */
+ directory_keyword v;
+ /** Minimum number of arguments for this item */
+ int min_args;
+ /** Maximum number of arguments for this item */
+ int max_args;
+ /** If true, we concatenate all arguments for this item into a single
+ * string. */
+ int concat_args;
+ /** Requirments on object syntax for this item. */
obj_syntax os;
- int min_cnt; int max_cnt;
+ /** Lowest number of times this item may appear in a document. */
+ int min_cnt;
+ /** Highest number of times this item may appear in a document. */
+ int max_cnt;
+ /** One or more of AT_START/AT_END to limit where the item may appear in a
+ * document. */
+ int pos;
} token_rule_t;
-/** DOCDOC */
-#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 T1N(s,t,a,o) { s, t, a, o, 1, INT_MAX }
-#define T01(s,t,a,o) { s, t, a, o, 0, 1 }
+/*
+ * Helper macros to define token tables. 's' is a string, 't' is a
+ * directory_keyword, 'a' is a trio of argument multiplicities, and 'o' is an
+ * object syntax.
+ *
+ */
+/** Appears to indicate the end of a table. */
+#define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0 }
+/** An item with no restrictions: used for obsolete document types */
+#define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0 }
+/** An item with no restrictions on multiplicity or location. */
+#define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0 }
+/** An item that must appear exactly once */
+#define T1(s,t,a,o) { s, t, a, o, 1, 1, 0 }
+/** An item that must appear exactly once, at the start of the document */
+#define T1_START(s,t,a,o) { s, t, a, o, 1, 1, 0, AT_START }
+/** An item that must appear exactly once, at the end of the document */
+#define T1_END(s,t,a,o) { s, t, a, o, 1, 1, 0, AT_END }
+/** An item that must appear one or more times */
+#define T1N(s,t,a,o) { s, t, a, o, 1, INT_MAX, 0 }
+/** An item that must appear no more than once */
+#define T01(s,t,a,o) { s, t, a, o, 0, 1, 0 }
+
+/* Argument multiplicity: any number of arguments. */
#define ARGS 0,INT_MAX,0
+/* Argument multiplicity: no arguments. */
#define NO_ARGS 0,0,0
+/* Argument multiplicity: concatenate all arguments. */
#define CONCAT_ARGS 1,1,1
+/* Argument multiplicity: at least <b>n</b> arguments. */
#define GE(n) n,INT_MAX,0
+/* Argument multiplicity: exactly <b>n</b> arguments. */
#define EQ(n) n,n,0
-/** DOCDOC */
+/** List of tokens allowable in router derscriptors */
static token_rule_t routerdesc_token_table[] = {
+ T0N("reject", K_REJECT, ARGS, NO_OBJ ),
T0N("accept", K_ACCEPT, ARGS, NO_OBJ ),
- T0N("reject", K_REJECT, ARGS, NO_OBJ ),
T1( "router", K_ROUTER, GE(5), NO_OBJ ),
T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ),
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, GE(1), NO_OBJ ),
- T01("family", K_FAMILY, ARGS, NO_OBJ ),
T01("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ ),
+ T01("platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ ),
+ T01("contact", K_CONTACT, CONCAT_ARGS, 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, GE(1), NO_OBJ ),
+
+ T01("family", K_FAMILY, ARGS, NO_OBJ ),
T01("caches-extra-info", K_CACHES_EXTRA_INFO, NO_ARGS, NO_OBJ ),
+ T01("eventdns", K_EVENTDNS, ARGS, NO_OBJ ),
+
+ T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T1( "bandwidth", K_BANDWIDTH, GE(3), NO_OBJ ),
- T01("platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ ),
END_OF_TABLE
};
+/** List of tokens allowable in extra-info documents. */
static token_rule_t extrainfo_token_table[] = {
T1( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
@@ -168,6 +211,8 @@
END_OF_TABLE
};
+/** List of tokens allowable in the body part of v2 and v3 networkstatus
+ * documents. */
static token_rule_t rtrstatus_token_table[] = {
T1( "r", K_R, GE(8), NO_OBJ ),
T1( "s", K_S, ARGS, NO_OBJ ),
@@ -176,6 +221,8 @@
END_OF_TABLE
};
+/** List of tokens allowable in the header part of v2 networkstatus documents.
+ */
static token_rule_t netstatus_token_table[] = {
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
@@ -193,11 +240,14 @@
END_OF_TABLE
};
+/** List of tokens allowable in the footer of v1/v2 directory/networkstatus
+ * footers. */
static token_rule_t dir_footer_token_table[] = {
- T1( "directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ),
+ T1("directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ),
END_OF_TABLE
};
+/** List of tokens allowable in v1 diectory headers/footers. */
static token_rule_t dir_token_table[] = {
/* don't enforce counts; this is obsolete. */
T( "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ ),
@@ -216,6 +266,8 @@
END_OF_TABLE
};
+/** List of tokens allowable in the footer of v1/v2 directory/networkstatus
+ * footers. */
#define CERTIFICATE_MEMBERS \
T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \
GE(1), NO_OBJ ), \
@@ -307,14 +359,14 @@
directory_keyword keyword);
static int tokenize_string(const char *start, const char *end,
smartlist_t *out,
- struct token_rule_t *table);
+ token_rule_t *table);
static directory_token_t *get_next_token(const char **s,
- struct token_rule_t *table);
-static int check_directory_signature(const char *digest,
- directory_token_t *tok,
- crypto_pk_env_t *pkey,
- crypto_pk_env_t *declared_key,
- int check_authority);
+ token_rule_t *table);
+static int check_signature_token(const char *digest,
+ directory_token_t *tok,
+ crypto_pk_env_t *pkey,
+ int check_authority,
+ const char *doctype);
static crypto_pk_env_t *find_dir_signing_key(const char *str);
static int tor_version_same_series(tor_version_t *a, tor_version_t *b);
@@ -357,8 +409,8 @@
"network-status-version","\ndirectory-signature");
}
-/** DOCDOC
- */
+/** Set <b>digest</b> to the SHA-1 digest of the hash of the extrainfo
+ * string in <b>s</b>. Return 0 on success, -1 on failure. */
int
router_get_extrainfo_hash(const char *s, char *digest)
{
@@ -556,7 +608,7 @@
}
declared_key = find_dir_signing_key(str);
note_crypto_pk_op(VERIFY_DIR);
- if (check_directory_signature(digest, tok, NULL, declared_key, 1)<0)
+ if (check_signature_token(digest, tok, declared_key, 1, "directory")<0)
goto err;
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
@@ -642,7 +694,8 @@
}
declared_key = find_dir_signing_key(str);
note_crypto_pk_op(VERIFY_DIR);
- if (check_directory_signature(digest, tok, NULL, declared_key, 1) < 0)
+ if (check_signature_token(digest, tok, declared_key, 1, "running-routers")
+ < 0)
goto err;
/* Now that we know the signature is okay, and we have a
@@ -718,78 +771,64 @@
return 1;
}
-/** Check whether the K_DIRECTORY_SIGNATURE token in <b>tok</b> has a
- * good signature for <b>digest</b>. DOCDOC can be another type.
- *
- * If <b>declared_key</b> is set, the directory has declared what key
- * was used to sign it, so we will use that key only if it is an
- * authoritative directory signing key or if check_authority is 0.
- *
- * Otherwise, if pkey is provided, try to use it.
- *
- * (New callers should always use <b>declared_key</b> when possible;
- * <b>pkey</b> is only for debugging.)
+/** Check whether the object body of the token in <b>tok</b> has a good
+ * signature for <b>digest</b> using key <b>pkey</b>. If
+ * <b>check_authority</b> is set, make sure that <b>pkey</b> is the key of a
+ * directory authority. Use <b>doctype</b> as the type of the document when
+ * generating log messages. Return 0 on success, negative on failure.
*/
static int
-check_directory_signature(const char *digest,
- directory_token_t *tok,
- crypto_pk_env_t *pkey,
- crypto_pk_env_t *declared_key,
- int check_authority)
+check_signature_token(const char *digest,
+ directory_token_t *tok,
+ crypto_pk_env_t *pkey,
+ int check_authority,
+ const char *doctype)
{
char *signed_digest;
- crypto_pk_env_t *_pkey = NULL;
- if (declared_key) {
- if (!check_authority || dir_signing_key_is_trusted(declared_key))
- _pkey = declared_key;
- }
- if (!_pkey && pkey) {
- /* pkey provided for debugging purposes */
- _pkey = pkey;
- }
- if (!_pkey) {
- log_warn(LD_DIR,
- "Obsolete directory format (dir signing key not present) or "
- "signing key not trusted--rejecting.");
+ tor_assert(pkey);
+ tor_assert(tok);
+ tor_assert(digest);
+ tor_assert(doctype);
+
+ if (check_authority && !dir_signing_key_is_trusted(pkey)) {
+ log_warn(LD_DIR, "Key on %s did not come from an authority; rejecting",
+ doctype);
return -1;
}
if (strcmp(tok->object_type, "SIGNATURE")) {
- log_warn(LD_DIR, "Bad object type on directory signature");
+ log_warn(LD_DIR, "Bad object type on %s signature", doctype);
return -1;
}
- tor_assert(_pkey);
signed_digest = tor_malloc(tok->object_size);
- if (crypto_pk_public_checksig(_pkey, signed_digest, tok->object_body,
+ if (crypto_pk_public_checksig(pkey, signed_digest, tok->object_body,
tok->object_size)
- != 20) {
- log_warn(LD_DIR, "Error reading directory: invalid signature.");
+ != DIGEST_LEN) {
+ log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
return -1;
}
- log_debug(LD_DIR,"Signed directory hash starts %s",
+ log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
hex_str(signed_digest,4));
if (memcmp(digest, signed_digest, DIGEST_LEN)) {
- log_warn(LD_DIR, "Error reading directory: signature does not match.");
+ log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
return -1;
}
return 0;
}
/** Given a string *<b>s</b> containing a concatenated sequence of router
- * descriptors, parses them and stores the result in <b>dest</b>. All routers
- * are marked running and valid. Advances *s to a point immediately
- * following the last router entry. Ignore any trailing router entries that
- * are not complete.
+ * descriptors (or extra-info documents if <b>is_extrainfo</b> is set), parses
+ * them and stores the result in <b>dest</b>. All routers are marked running
+ * and valid. Advances *s to a point immediately following the last router
+ * entry. Ignore any trailing router entries that are not complete.
*
* If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each
* descriptor in the signed_descriptor_body field of each routerinfo_t. If it
* isn't SAVED_NOWHERE, remember the offset of each descriptor.
*
* Returns 0 on success and -1 on failure.
- *
- * DOCDOC is_extrainfo
*/
int
router_parse_list_from_string(const char **s, smartlist_t *dest,
@@ -817,6 +856,9 @@
if (strcmpstart(*s, "router ")!=0)
break;
}
+ /* XXXX020 this is hideously complicated. Can't we just search for the
+ * first -----END SIGNATURE----- and be done with it? Or the first
+ * -----END SIGNATURE----- after the first \nrouter-signature ?*/
if (is_extrainfo && (end = strstr(*s+1, "\nextra-info"))) {
cp = end;
end++;
@@ -911,11 +953,9 @@
int cache_copy)
{
routerinfo_t *router = NULL;
- char signed_digest[128];
char digest[128];
smartlist_t *tokens = NULL, *exit_policy_tokens = NULL;
directory_token_t *tok;
- int t;
struct in_addr in;
if (!end) {
@@ -1086,25 +1126,15 @@
tok = find_first_by_keyword(tokens, K_ROUTER_SIGNATURE);
tor_assert(tok);
- if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
- log_warn(LD_DIR, "Bad object type or length on router signature");
- goto err;
- }
note_crypto_pk_op(VERIFY_RTR);
#ifdef COUNT_DISTINCT_DIGESTS
if (!verified_digests)
verified_digests = digestmap_new();
digestmap_set(verified_digests, signed_digest, (void*)(uintptr_t)1);
#endif
- if ((t=crypto_pk_public_checksig(router->identity_pkey, signed_digest,
- tok->object_body, 128)) != 20) {
- log_warn(LD_DIR, "Invalid signature %d",t);
+ if (check_signature_token(digest, tok, router->identity_pkey, 0,
+ "router descriptor") < 0)
goto err;
- }
- if (memcmp(digest, signed_digest, DIGEST_LEN)) {
- log_warn(LD_DIR, "Mismatched signature");
- goto err;
- }
if (!router->or_port) {
log_warn(LD_DIR,"or_port unreadable or 0. Failing.");
@@ -1131,17 +1161,20 @@
return router;
}
-/* DOCDOC */
+/** Parse a single extrainfo entry from the string <b>s</b>, ending at
+ * <b>end</b>. (If <b>end</b> is NULL, parse up to the end of <b>s</b>.) If
+ * <b>cache_copy</b> is true, make a copy of the extra-info document in the
+ * cache_info fields of the result. If <b>routermap</b> is provided, use it
+ * as a map from router identity to routerinfo_t when looking up signing keys.
+ */
extrainfo_t *
extrainfo_parse_entry_from_string(const char *s, const char *end,
int cache_copy, digestmap_t *routermap)
{
extrainfo_t *extrainfo = NULL;
- char signed_digest[128];
char digest[128];
smartlist_t *tokens = NULL;
directory_token_t *tok;
- int t;
crypto_pk_env_t *key = NULL;
routerinfo_t *router;
@@ -1210,29 +1243,27 @@
tok = find_first_by_keyword(tokens, K_ROUTER_SIGNATURE);
tor_assert(tok);
- if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
- log_warn(LD_DIR, "Bad object type or length on router signature");
+ if (strcmp(tok->object_type, "SIGNATURE") ||
+ tok->object_size < 128 || tok->object_size > 512) {
+ log_warn(LD_DIR, "Bad object type or length on extra-info signature");
goto err;
}
if (key) {
note_crypto_pk_op(VERIFY_RTR);
- if ((t=crypto_pk_public_checksig(key, signed_digest,
- tok->object_body, 128)) != 20) {
- log_warn(LD_DIR, "Invalid signature %d",t);
+ if (check_signature_token(digest, tok, key, 0, "extra-info") < 0)
goto err;
- }
- if (memcmp(digest, signed_digest, DIGEST_LEN)) {
- log_warn(LD_DIR, "Mismatched signature");
- goto err;
- }
+
} else {
- extrainfo->pending_sig = tor_memdup(tok->object_body, 128);
+ extrainfo->pending_sig = tor_memdup(tok->object_body,
+ tok->object_size);
+ extrainfo->pending_sig_len = tok->object_size;
}
goto done;
err:
- // extrainfo_free(extrainfo); // DOCDOC
+ if (extrainfo)
+ extrainfo_free(extrainfo);
extrainfo = NULL;
done:
if (tokens) {
@@ -1242,7 +1273,7 @@
return extrainfo;
}
-/** DOCDOC */
+/** Free storage held in <b>cert</b>. */
void
authority_cert_free(authority_cert_t *cert)
{
@@ -1258,7 +1289,8 @@
tor_free(cert);
}
-/** DOCDOC */
+/** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
+ * the first character after the certificate. */
authority_cert_t *
authority_cert_parse_from_string(const char *s, char **end_of_string)
{
@@ -1344,7 +1376,8 @@
/* XXXXX This doesn't check whether the key is an authority. IS that what we
* want? */
- if (check_directory_signature(digest, tok, NULL, cert->identity_key, 0)) {
+ if (check_signature_token(digest, tok, cert->identity_key, 0,
+ "key certificate")) {
goto err;
}
@@ -1664,7 +1697,8 @@
}
note_crypto_pk_op(VERIFY_DIR);
- if (check_directory_signature(ns_digest, tok, NULL, ns->signing_key, 0))
+ if (check_signature_token(ns_digest, tok, ns->signing_key, 0,
+ "network-status") < 0)
goto err;
goto done;
@@ -1885,14 +1919,65 @@
tor_free(tok);
}
-/** Helper function: read the next token from *s, advance *s to the end
- * of the token, and return the parsed token. DOCDOC table
+#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)
+
+static INLINE directory_token_t *
+token_check_object(const char *kwd,
+ directory_token_t *tok, obj_syntax o_syn)
+{
+ char ebuf[128];
+ switch (o_syn) {
+ case NO_OBJ:
+ 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) {
+ tor_snprintf(ebuf, sizeof(ebuf), "Missing object for %s", kwd);
+ RET_ERR(ebuf);
+ }
+ break;
+ case NEED_KEY_1024:
+ if (tok->key && crypto_pk_keysize(tok->key) != PK_BYTES) {
+ tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits",
+ kwd, (int)crypto_pk_keysize(tok->key));
+ RET_ERR(ebuf);
+ }
+ /* fall through */
+ case NEED_KEY:
+ if (!tok->key) {
+ tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd);
+ }
+ break;
+ case OBJ_OK:
+ break;
+ }
+
+ done_tokenizing:
+ return tok;
+}
+
+/** Helper function: read the next token from *s, advance *s to the end of the
+ * token, and return the parsed token. Parse *<b>s</b> according to the list
+ * of tokens in <b>table</b>.
*/
static directory_token_t *
-get_next_token(const char **s, struct token_rule_t *table)
+get_next_token(const char **s, token_rule_t *table)
{
const char *next, *obstart;
- int i, j, done, allocated, is_opt;
+ int i, j, done, allocated;
directory_token_t *tok;
obj_syntax o_syn = NO_OBJ;
char ebuf[128];
@@ -1919,8 +2004,8 @@
tok->error = tor_strdup("Unexpected EOF"); return tok;
}
/* It's a keyword... but which one? */
- is_opt = !strncmp("opt", *s, next-*s);
- if (is_opt) {
+ if (!strncmp("opt", *s, next-*s)) {
+ /* Skip past an "opt" at the start of the line. */
*s = eat_whitespace(next);
next = NULL;
if (**s)
@@ -1929,6 +2014,8 @@
RET_ERR("opt without keyword");
}
}
+ /* Search the table for the appropriate entry. (I tried a binary search
+ * instead, but it wasn't any faster.) */
for (i = 0; table[i].t ; ++i) {
if (!strncmp(table[i].t, *s, next-*s)) {
/* We've found the keyword. */
@@ -1990,7 +2077,7 @@
}
*s = eat_whitespace(*s);
if (strcmpstart(*s, "-----BEGIN ")) {
- goto done_tokenizing;
+ goto check_object;
}
obstart = *s;
*s += 11; /* length of "-----BEGIN ". */
@@ -2026,48 +2113,18 @@
}
*s += i+6;
}
- switch (o_syn)
- {
- case NO_OBJ:
- 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) {
- tor_snprintf(ebuf, sizeof(ebuf), "Missing object for %s", kwd);
- RET_ERR(ebuf);
- }
- break;
- case NEED_KEY_1024:
- if (tok->key && crypto_pk_keysize(tok->key) != PK_BYTES) {
- tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits",
- kwd, (int)crypto_pk_keysize(tok->key));
- RET_ERR(ebuf);
- }
- /* fall through */
- case NEED_KEY:
- if (!tok->key) {
- tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd);
- }
- break;
- case OBJ_OK:
- break;
- }
+ check_object:
+ tok = token_check_object(kwd, tok, o_syn);
+
done_tokenizing:
+ return tok;
- return tok;
#undef RET_ERR
}
/** Read all tokens from a string between <b>start</b> and <b>end</b>, and add
- * them to <b>out</b>. DOCDOC table.
+ * them to <b>out</b>. Parse according to the token rules in <b>table</b>.
*/
static int
tokenize_string(const char *start, const char *end, smartlist_t *out,
@@ -2105,6 +2162,20 @@
log_warn(LD_DIR, "Parse error: too many %s elements.", table[i].t);
return -1;
}
+ if (table[i].pos & AT_START) {
+ if (smartlist_len(out) < 1 ||
+ (tok = smartlist_get(out, 0))->tp != table[i].v) {
+ log_warn(LD_DIR, "Parse error: first item is not %s.", table[i].t);
+ return -1;
+ }
+ }
+ if (table[i].pos & AT_END) {
+ if (smartlist_len(out) < 1 ||
+ (tok = smartlist_get(out, smartlist_len(out)-1))->tp != table[i].v) {
+ log_warn(LD_DIR, "Parse error: last item is not %s.", table[i].t);
+ return -1;
+ }
+ }
}
return 0;
}