static int parse_ipv4(struct ip_addr* ip, cfg_token_t* token, cfg_parser_t* st) { int ret, i; cfg_token_t t; unsigned int v; ip->af = AF_INET; ip->len = 4; if (str2int(&token->val, &v) < 0) goto err; if (v < 0 || v > 255) goto err; ip->u.addr[0] = v; for(i = 1; i < 4; i++) { ret = cfg_get_token(&t, st, 0); if (ret < 0) return -1; if (ret > 0 || t.type != '.') goto err; ret = cfg_get_token(&t, st, 0); if (ret < 0) return -1; if (ret > 0 || t.type != CFG_TOKEN_ALPHA) goto err; if (str2int(&t.val, &v) < 0) goto err; if (v < 0 || v > 255) goto err; ip->u.addr[i] = v; } return 0; err: ERR("%s:%d:%d: Invalid IPv4 address\n", st->file, token->start.line, token->start.col); return -1; }
static int cfg_next (char **item, char **value) { char *this; if (last_item) { *item = last_item; *value = last_value; last_item = NULL; return 1; } *value = NULL; if (!(*item = cfg_get_token ())) return 0; if (!strcmp (*item, "=")) cfg_error ("Syntax error"); if (!(this = cfg_get_token ())) return 1; if (strcmp (this, "=")) { cfg_return_token (this); return 1; } if (!(*value = cfg_get_token ())) cfg_error ("Value expected at EOF"); if (!strcmp (*value, "=")) cfg_error ("Syntax error after %s", *item); return 1; }
static int parse_ipv6(struct ip_addr* ip, cfg_token_t* token, cfg_parser_t* st) { int ret; cfg_token_t t; struct ip_addr* ipv6; str ip6_str; while(1) { ret = cfg_get_token(&t, st, 0); if (ret != 0) goto err; if (t.type == ']') break; if (t.type != CFG_TOKEN_ALPHA && t.type != ':') goto err; } ip6_str.s = t.val.s; ip6_str.len = (int)(long)(t.val.s - ip6_str.s); ipv6 = str2ip6(&ip6_str); if (ipv6 == 0) goto err; *ip = *ipv6; return 0; err: ERR("%s:%d:%d: Invalid IPv6 address\n", st->file, token->start.line, token->start.col); return -1; }
int cfg_parse_bool(void* param, cfg_parser_t* st, unsigned int flags) { int ret, *val; cfg_token_t t; cfg_option_t* map; val = (int*)param; ret = cfg_get_token(&t, st, flags); if (ret != 0) return ret; if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) { ERR("%s:%d:%d: Invalid option value '%.*s', boolean expected\n", st->file, t.start.line, t.start.col, STR_FMT(&t.val)); return -1; } if ((map = cfg_lookup_token(cfg_bool_values, &t.val)) == NULL) { ERR("%s:%d:%d: Invalid option value '%.*s', boolean expected\n", st->file, t.start.line, t.start.col, STR_FMT(&t.val)); return -1; } if (val) *val = map->val; return 0; }
int cfg_parse_int(void* param, cfg_parser_t* st, unsigned int flags) { int* val; int ret, tmp; cfg_token_t t; val = (int*)param; ret = cfg_get_token(&t, st, flags); if (ret != 0) return ret; if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) { ERR("%s:%d:%d: Invalid integer value '%.*s'\n", st->file, t.start.line, t.start.col, STR_FMT(&t.val)); return -1; } if (str2sint(&t.val, &tmp) < 0) { ERR("%s:%d:%d: Invalid integer value '%.*s'\n", st->file, t.start.line, t.start.col, STR_FMT(&t.val)); return -1; } if (val) *val = tmp; return 0; }
int cfg_parse_enum(void* param, cfg_parser_t* st, unsigned int flags) { int ret; cfg_token_t t; cfg_option_t* values, *val; values = (cfg_option_t*)param; ret = cfg_get_token(&t, st, flags); if (ret != 0) return ret; if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) { ERR("%s:%d:%d: Invalid enum value '%.*s'\n", st->file, t.start.line, t.start.col, STR_FMT(&t.val)); return -1; } if (values) { if ((val = cfg_lookup_token(values, &t.val)) == NULL) { ERR("%s:%d:%d Unsupported enum value '%.*s'\n", st->file, t.start.line, t.start.col, STR_FMT(&t.val)); return -1; } return process_option(st, val); } else { return 0; } }
static int parse_ipv6(struct ip_addr* ip, cfg_token_t* token, cfg_parser_t* st) { int ret; cfg_token_t t; struct ip_addr* ipv6; str ip6_str; char ip6_buff[IP_ADDR_MAX_STR_SIZE+3]; ip6_buff[0] = '\0'; while(1) { ret = cfg_get_token(&t, st, 0); if (ret != 0) goto err; if (t.type == ']') break; if (t.type != CFG_TOKEN_ALPHA && t.type != ':') goto err; strncat(ip6_buff, t.val.s, t.val.len); } ip6_str.s = ip6_buff; ip6_str.len = strlen(ip6_buff); LM_DBG("found IPv6 address [%.*s]\n", ip6_str.len, ip6_str.s); ipv6 = str2ip6(&ip6_str); if (ipv6 == 0) goto err; *ip = *ipv6; return 0; err: LM_ERR("%s:%d:%d: Invalid IPv6 address\n", st->file, token->start.line, token->start.col); return -1; }
int cfg_parse_str(void* param, cfg_parser_t* st, unsigned int flags) { str* val; int ret; char* buf; cfg_token_t t; ret = cfg_get_token(&t, st, flags); if (ret != 0) return ret; if (t.type != CFG_TOKEN_ALPHA && t.type != CFG_TOKEN_STRING) { ERR("%s:%d:%d: Invalid string value '%.*s', a string expected.\n", st->file, t.start.line, t.start.col, STR_FMT(&t.val)); return -1; } if (!param) return 0; val = (str*)param; if (flags & CFG_STR_STATIC) { if (!val->s || val->len <= t.val.len) { ERR("%s:%d:%d: Destination string buffer too small\n", st->file, t.start.line, t.start.col); return -1; } buf = val->s; } else if (flags & CFG_STR_SHMMEM) { if ((buf = shm_malloc(t.val.len + 1)) == NULL) { ERR("%s:%d:%d: Out of shared memory\n", st->file, t.start.line, t.start.col); return -1; } if (val->s) shm_free(val->s); } else if (flags & CFG_STR_MALLOC) { if ((buf = malloc(t.val.len + 1)) == NULL) { ERR("%s:%d:%d: Out of malloc memory\n", st->file, t.start.line, t.start.col); return -1; } if (val->s) free(val->s); } else if (flags & CFG_STR_PKGMEM) { if ((buf = pkg_malloc(t.val.len + 1)) == NULL) { ERR("%s:%d:%d: Out of private memory\n", st->file, t.start.line, t.start.col); return -1; } if (val->s) pkg_free(val->s); } else { *val = t.val; return 0; } memcpy(buf, t.val.s, t.val.len); buf[t.val.len] = '\0'; val->s = buf; val->len = t.val.len; return 0; }
int cfg_eat_eol(cfg_parser_t* st, unsigned int flags) { cfg_token_t t; int ret; /* Skip EOL */ ret = cfg_get_token(&t, st, 0); if (ret < 0) return ret; if (ret > 0) return 0; if (t.type != '\n') { ERR("%s:%d:%d: End of line expected\n", st->file, t.start.line, t.start.col); return -1; } return 0; }
int sr_cfg_parse(cfg_parser_t* st) { int ret; cfg_token_t t; cfg_option_t* opt; while(1) { ret = cfg_get_token(&t, st, 0); if (ret < 0) return ret; if (ret > 0) break; switch(t.type) { case CFG_TOKEN_ALPHA: /* Lookup the option name */ if ((opt = cfg_lookup_token(st->options, &t.val)) == NULL) { ERR("%s:%d:%d: Unsupported option '%.*s'\n", st->file, t.start.line, t.start.col, STR_FMT(&t.val)); return -1; } st->cur_opt = &t; if (process_option(st, opt) < 0) { st->cur_opt = 0; return -1; } st->cur_opt = 0; break; case '[': if (st->section.parser == NULL) { ERR("%s:%d:%d: Syntax error\n", st->file, t.start.line, t.start.col); return -1; } if (st->section.parser(st->section.param, st, 0) < 0) return -1; break; /* Empty line */ case '\n': continue; default: ERR("%s:%d:%d: Syntax error\n", st->file, t.start.line, t.start.col); return -1; } } return 0; }
int cfg_parse_section(void* param, cfg_parser_t* st, unsigned int flags) { cfg_token_t t; int ret; ret = cfg_parse_str(param, st, flags); if (ret < 0) return ret; if (ret > 0) { ERR("%s:%d:%d: Section name missing.\n", st->file, st->line, st->col); return ret; } ret = cfg_get_token(&t, st, flags); if (ret < 0) goto error; if (ret > 0) { ERR("%s:%d:%d: Closing ']' missing\n", st->file, st->line, st->col); goto error; } if (t.type != ']') { ERR("%s:%d:%d: Syntax error, ']' expected\n", st->file, t.start.line, t.start.col); goto error; } if (cfg_eat_eol(st, flags)) goto error; return 0; error: if (param && ((str*)param)->s) { if (flags & CFG_STR_PKGMEM) { pkg_free(((str*)param)->s); ((str*)param)->s = NULL; } else if (flags & CFG_STR_SHMMEM) { shm_free(((str*)param)->s); ((str*)param)->s = NULL; } else if (flags & CFG_STR_MALLOC) { free(((str*)param)->s); ((str*)param)->s = NULL; } } return -1; }
int cfg_eat_equal(cfg_parser_t* st, unsigned int flags) { cfg_token_t t; int ret; ret = cfg_get_token(&t, st, flags); if (ret < 0) return ret; if (ret > 0) { ERR("%s:%d:%d: Delimiter '=' missing\n", st->file, st->line, st->col); return ret; } if (t.type != '=') { ERR("%s:%d:%d: Syntax error, '=' expected\n", st->file, t.start.line, t.start.col); return -1; } return 0; }
static int parse_domain(void* param, cfg_parser_t* st, unsigned int flags) { cfg_token_t t; int ret; cfg_option_t* opt; int type; struct ip_addr ip; unsigned int port; memset(&ip, 0, sizeof(struct ip_addr)); ret = cfg_get_token(&t, st, 0); if (ret < 0) return -1; if (ret > 0) { ERR("%s:%d:%d: TLS domain type missing\n", st->file, st->line, st->col); return -1; } if (t.type != CFG_TOKEN_ALPHA || ((opt = cfg_lookup_token(domain_types, &t.val)) == NULL)) { ERR("%s:%d:%d: Invalid TLS domain type %d:'%.*s'\n", st->file, t.start.line, t.start.col, t.type, STR_FMT(&t.val)); return -1; } ret = cfg_get_token(&t, st, 0); if (ret < 0) return -1; if (ret > 0) { ERR("%s:%d:%d: TLS domain IP address missing\n", st->file, st->line, st->col); return -1; } if (t.type != ':') { ERR("%s:%d:%d: Syntax error, ':' expected\n", st->file, t.start.line, t.start.col); return -1; } port = 0; if (parse_hostport(&type, &ip, &port, &t, st) < 0) return -1; ret = cfg_get_token(&t, st, 0); if (ret < 0) return -1; if (ret > 0) { ERR("%s:%d:%d: Closing ']' missing\n", st->file, st->line, st->col); return -1; } if (t.type != ']') { ERR("%s:%d:%d: Syntax error, ']' expected\n", st->file, t.start.line, t.start.col); return -1; } if (cfg_eat_eol(st, flags)) return -1; if ((domain = tls_new_domain(opt->val | type, &ip, port)) == NULL) { ERR("%s:%d: Cannot create TLS domain structure\n", st->file, st->line); return -1; } ret = tls_add_domain(cfg, domain); if (ret < 0) { ERR("%s:%d: Error while creating TLS domain structure\n", st->file, st->line); tls_free_domain(domain); return -1; } else if (ret == 1) { ERR("%s:%d: Duplicate TLS domain (appears earlier in the config file)\n", st->file, st->line); tls_free_domain(domain); return -1; } update_opt_variables(); cfg_set_options(st, options); return 0; }
static int parse_hostport(int* type, struct ip_addr* ip, unsigned int* port, cfg_token_t* token, cfg_parser_t* st) { int ret; cfg_token_t t; cfg_option_t* opt; ret = cfg_get_token(&t, st, 0); if (ret < 0) return -1; if (ret > 0) { ERR("%s:%d:%d: Missing IP address\n", st->file, token->start.line, token->start.col); return -1; } if (t.type == '[') { if (parse_ipv6(ip, &t, st) < 0) return -1; } else if (t.type == CFG_TOKEN_ALPHA) { opt = cfg_lookup_token(token_default, &t.val); if (opt) { *type = TLS_DOMAIN_DEF; /* Default domain */ return 0; } else { if (parse_ipv4(ip, &t, st) < 0) return -1; } } else { ERR("%s:%d:%d: Syntax error, IP address expected\n", st->file, t.start.line, t.start.col); return -1; } *type = 0; /* Parse port */ ret = cfg_get_token(&t, st, 0); if (ret < 0) return -1; if (ret > 0) { ERR("%s:%d:%d: Syntax error, ':' expected\n", st->file, st->line, st->col); return -1; } if (t.type != ':') { ERR("%s:%d:%d: Syntax error, ':' expected\n", st->file, t.start.line, t.start.col); return -1; } ret = cfg_get_token(&t, st, 0); if (ret < 0) return -1; if (ret > 0) { ERR("%s:%d:%d: Premature end of file, port number missing\n", st->file, t.start.line, t.start.col); return -1; } if (t.type != CFG_TOKEN_ALPHA || (str2int(&t.val, port) < 0)) { ERR("%s:%d:%d: Invalid port number '%.*s'\n", st->file, t.start.line, t.start.col, STR_FMT(&t.val)); return -1; } return 0; }