From 1dab82d655b8f54e344f21f062495d5cb35c8c4c Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 27 Jun 2020 23:24:59 +0100 Subject: Improve user choices file processing Improve the key/value processing in choices file. Fixes several oddities discovered including: removing the last character of the last value. possible buffer overflow with certian values --- utils/nsoption.c | 115 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 27 deletions(-) diff --git a/utils/nsoption.c b/utils/nsoption.c index 6985b3cb8..a8a29b3bf 100644 --- a/utils/nsoption.c +++ b/utils/nsoption.c @@ -540,6 +540,89 @@ nsoption_free(struct nsoption_s *opts) } +/** + * extract key/value from a line of input + * + * \retun NSERROR_OK and key_out and value_out updated + * NSERROR_NOT_FOUND if not a key/value input line + * NSERROR_INVALID if the line is and invalid format (missing colon) + */ +static nserror +get_key_value(char *line, int linelen, char **key_out, char **value_out) +{ + char *key; + char *value; + + /* skip leading whitespace for start of key */ + for (key = line; *key != 0; key++) { + if ((*key != ' ') && (*key != '\t') && (*key != '\n')) { + break; + } + } + + /* empty line or only whitespace */ + if (*key == 0) { + return NSERROR_NOT_FOUND; + } + + /* comment */ + if (*key == '#') { + return NSERROR_NOT_FOUND; + } + + /* get start of value */ + for (value = key; *value != 0; value++) { + if (*value == ':') { + *value = 0; + value++; + break; + } + } + + /* missing colon separator */ + if (*value == 0) { + return NSERROR_INVALID; + } + + /* remove delimiter from value */ + if (line[linelen - 1] == '\n') { + linelen--; + line[linelen] = 0; + } + + *key_out = key; + *value_out = value; + return NSERROR_OK; +} + + +/** + * Process a line from a user option file + */ +static nserror optionline(struct nsoption_s *opts, char *line, int linelen) +{ + nserror res; + char *key; + char *value; + int idx; + + res = get_key_value(line, linelen, &key, &value); + if (res != NSERROR_OK) { + /* skip line as no valid key value pair found */ + return res; + } + + for (idx = 0; opts[idx].key != NULL; idx++) { + if (strcasecmp(key, opts[idx].key) == 0) { + strtooption(value, &opts[idx]); + break; + } + } + + return res; +} + + /* exported interface documented in utils/nsoption.h */ nserror nsoption_init(nsoption_set_default_t *set_defaults, @@ -645,7 +728,9 @@ nsoption_read(const char *path, struct nsoption_s *opts) opts = nsoptions; } - /** @todo is this and API bug not being a parameter */ + /** + * @todo is this an API bug not being a parameter + */ defs = nsoptions_default; if ((opts == NULL) || (defs == NULL)) { @@ -658,34 +743,10 @@ nsoption_read(const char *path, struct nsoption_s *opts) return NSERROR_NOT_FOUND; } - NSLOG(netsurf, INFO, "Successfully opened '%s' for Options file", - path); + NSLOG(netsurf, INFO, "Successfully opened '%s' for Options file", path); while (fgets(s, NSOPTION_MAX_LINE_LEN, fp)) { - char *colon, *value; - unsigned int idx; - - if ((s[0] == 0) || (s[0] == '#')) { - continue; - } - - colon = strchr(s, ':'); - if (colon == 0) { - continue; - } - - s[strlen(s) - 1] = 0; /* remove \n at end */ - *colon = 0; /* terminate key */ - value = colon + 1; - - for (idx = 0; opts[idx].key != NULL; idx++) { - if (strcasecmp(s, opts[idx].key) != 0) { - continue; - } - - strtooption(value, &opts[idx]); - break; - } + optionline(opts, s, strlen(s)); } fclose(fp); -- cgit v1.2.3