diff --git a/ChangeLog b/ChangeLog index d96fb39..60ec481 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,9 @@ vNEXT: Added symbol to support libconfig 1.4.9, still in use in CentOS7. + Warn about unknown settings in the configuration + file. + v1.21: 11JUL2020 WARNING: Moved configuration and command-line management to diff --git a/sslh-conf.c b/sslh-conf.c index f421284..fd4cc32 100644 --- a/sslh-conf.c +++ b/sslh-conf.c @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) - * on Tue Aug 11 17:35:54 2020. + * on Sat Aug 29 18:12:55 2020. # conf2struct: generate libconf parsers that read to structs # Copyright (C) 2018-2019 Yves Rutschle @@ -171,13 +171,30 @@ char* config_error_text(config_t* c) { } #endif +/* This is the same as config_setting_lookup_string() except +it allocates a new string which belongs to the caller */ +static int myconfig_setting_lookup_stringcpy( + const config_setting_t* setting, + const char* name, + char** value) +{ + const char* str; + *value = NULL; + if (config_setting_lookup_string(setting, name, &str) == CONFIG_TRUE) { + asprintf(value, "%s", str); + return CONFIG_TRUE; + } else { + return CONFIG_FALSE; + } +} + typedef int (*lookup_fn)(const config_setting_t*, const char*, void*); lookup_fn lookup_fns[] = { (lookup_fn)config_setting_lookup_bool, (lookup_fn)config_setting_lookup_int, (lookup_fn)config_setting_lookup_int64, (lookup_fn)config_setting_lookup_float, - (lookup_fn)config_setting_lookup_string, + (lookup_fn)myconfig_setting_lookup_stringcpy, NULL, /* CFG_GROUP */ NULL, /* CFG_ARRAY */ NULL, /* CFG_LIST */ @@ -1120,7 +1137,7 @@ static void print_setting(config_type type, void* val) /* Changes all dashes to underscores in a string of * vice-versa */ -void strswap_ud(const char target, char* str) +static void strswap_ud(const char target, char* str) { char* c; for (c = str; *c; c++) @@ -1130,7 +1147,7 @@ void strswap_ud(const char target, char* str) /* Same as config_setting_lookup() but looks up with dash or * underscore so `my_setting` and `my-setting` match the same */ -config_setting_t* config_setting_lookup_ud(config_setting_t* cfg, struct config_desc* desc) +static config_setting_t* config_setting_lookup_ud(config_setting_t* cfg, struct config_desc* desc) { config_setting_t* setting; char name[strlen(desc->name)+1];; @@ -1146,7 +1163,7 @@ config_setting_t* config_setting_lookup_ud(config_setting_t* cfg, struct config_ return setting; } -int lookup_typed_ud(config_setting_t* cfg, void* target, struct config_desc *desc) +static int lookup_typed_ud(config_setting_t* cfg, void* target, struct config_desc *desc) { lookup_fn lookup_fn = lookup_fns[desc->type]; char name[strlen(desc->name)+1];; @@ -1160,6 +1177,22 @@ int lookup_typed_ud(config_setting_t* cfg, void* target, struct config_desc *des return lookup_fn(cfg, name, ((char*)target) + desc->offset); } +/* Removes a setting, trying both underscores and dashes as +* name (so deleting 'my-setting' deletes both 'my_setting' +* and 'my-setting') */ +static int setting_delete_ud(config_setting_t* cfg, struct config_desc *desc) +{ + char name[strlen(desc->name)+1];; + strcpy(name, desc->name); + + strswap_ud('_', name); + if (config_setting_remove(cfg, name) == CONFIG_TRUE) + return CONFIG_TRUE; + + strswap_ud('-', name); + return config_setting_remove(cfg, name); +} + /* When traversing configuration, allocate memory for plural * types, init for scalars */ static void read_block_init(void* target, config_setting_t* cfg, struct config_desc* desc) @@ -1244,6 +1277,7 @@ static int read_block_setval(void* target, TRACE_READ(("[%d] = ", i)); print_setting(desc->array_type, (char*)block + desc->size *i); TRACE_READ(("\n")); } + setting_delete_ud(cfg, desc); } break; @@ -1265,6 +1299,7 @@ static int read_block_setval(void* target, return 0; } print_setting(desc->type, (((char*)target) + desc->offset)); + setting_delete_ud(cfg, desc); in_cfg = 1; } else { TRACE_READ((" not in config file")); @@ -1556,6 +1591,86 @@ static int c2s_parse_file(const char* filename, config_t* c, char**errmsg) return 1; } +/* Allocates a new string that represents the setting value, which must be a scalar */ +static void scalar_to_string(char** strp, config_setting_t* s) +{ + switch(config_setting_type(s)) { + case CONFIG_TYPE_INT: + asprintf(strp, "%d\n", config_setting_get_int(s)); + break; + + case CONFIG_TYPE_BOOL: + asprintf(strp, "%s\n", config_setting_get_bool(s) ? "[true]" : "[false]" ); + break; + + case CONFIG_TYPE_INT64: + asprintf(strp, "%lld\n", config_setting_get_int64(s)); + break; + + case CONFIG_TYPE_FLOAT: + asprintf(strp, "%lf\n", config_setting_get_float(s)); + break; + + case CONFIG_TYPE_STRING: + asprintf(strp, "%s\n", config_setting_get_string(s)); + break; + + default: /* This means a bug */ + fprintf(stderr, "Unexpected type %d\n", config_setting_type(s)); + exit(1); + } +} + +/* Typesets all the settings in a configuration as a +* newly-allocated string. The string management is caller's +* responsability. +* Returns the number of scalars in the configuration */ +static int cfg_as_string(config_setting_t* parent, const char* path, char** strp) +{ + int i, len, res = 0; + config_setting_t* child; + char* subpath, *value, *old; + const char* name; + + len = config_setting_length(parent); + for (i = 0; i < len; i++) { + child = config_setting_get_elem(parent, i); + name = config_setting_name(child); + if (!name) name = ""; + + if(config_setting_is_list(parent) || + config_setting_is_array(parent)) { + asprintf(&subpath, "%s[%d]%s", path, config_setting_index(child), name); + } else { + asprintf(&subpath, "%s/%s", path, name); + } + + if (config_setting_is_scalar(child)) { + scalar_to_string(&value, child); + + /* Add value to the output string */ + if (*strp) { + asprintf(&old, "%s", *strp); + free(*strp); + } else { + asprintf(&old, "%s", ""); + } + asprintf(strp, "%s%s:%s", old, subpath, value); + free(value); + free(old); + + res++; /* At least one scalar was found */ + } else { + /* It's an aggregate -- descend into it */ + res += cfg_as_string(child, subpath, strp); + } + + free(subpath); + } + return res; +} + + /* 0: success <0: error */ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg) @@ -1625,6 +1740,11 @@ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg) return -1; } + errmsg = NULL; + res = cfg_as_string(s, "", &errmsg); + if (res) + fprintf(stderr, "Unknown settings:\n%s\n", errmsg); + return 0; } diff --git a/sslh-conf.h b/sslh-conf.h index edc7f21..53f6361 100644 --- a/sslh-conf.h +++ b/sslh-conf.h @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) - * on Tue Aug 11 17:35:54 2020. + * on Sat Aug 29 18:12:55 2020. # conf2struct: generate libconf parsers that read to structs # Copyright (C) 2018-2019 Yves Rutschle diff --git a/test.cfg b/test.cfg index 44790ea..d08c565 100644 --- a/test.cfg +++ b/test.cfg @@ -33,7 +33,7 @@ protocols: { name: "regex"; host: "localhost"; port: "9011"; regex_patterns: [ "^foo", "^bar" ]; minlength: 4; - test_patterns: ( + test_patterns: ( # this is used by the test script, not by sslh { pattern: "foo"; result: "ssh"; }, # After timeout { pattern: "fooo"; result: "regex"; }, { pattern: "bar"; result: "ssh"; },