From d2225f10b7e0888edfadf685953a641d869ebb84 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 1 Apr 2021 15:04:53 +0000 Subject: [PATCH] Feature: Warn about unknown, and obsolete tags in config --- src/admin.c | 4 ++ src/cfgfile.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++---- src/cfgfile.h | 2 + 3 files changed, 148 insertions(+), 10 deletions(-) diff --git a/src/admin.c b/src/admin.c index f77dd9b0..09379cad 100644 --- a/src/admin.c +++ b/src/admin.c @@ -1486,6 +1486,10 @@ static void command_dashboard (client_t *client, source_t *source, adm __reportxml_add_maintenance(reportnode, config->reportxml_db, "cf86d88e-dc20-4359-b446-110e7065d17a", "warning", "No admin contact given in . YP directory support will is disabled.", NULL); if (config->config_problems & CONFIG_PROBLEM_PRNG) __reportxml_add_maintenance(reportnode, config->reportxml_db, "e2ba5a8b-4e4f-41ca-b455-68ae5fb6cae0", "error", "No PRNG seed configured. PRNG is insecure.", NULL); + if (config->config_problems & CONFIG_PROBLEM_UNKNOWN_NODE) + __reportxml_add_maintenance(reportnode, config->reportxml_db, "6620ef7b-46ef-4781-9a5e-8ee7f0f9d44e", "error", "Unknown tags are used in the config file. See the error.log for details.", NULL); + if (config->config_problems & CONFIG_PROBLEM_OBSOLETE_NODE) + __reportxml_add_maintenance(reportnode, config->reportxml_db, "b6224fc4-53a1-433f-a6cd-d5b85c60f1c9", "error", "Obsolete tags are used in the config file. See the error.log for details and update your configuration accordingly.", NULL); if (!has_sources) __reportxml_add_maintenance(reportnode, config->reportxml_db, "f68dd8a3-22b1-4118-aba6-b039f2c5b51e", "info", "Currently no sources are connected to this server.", NULL); diff --git a/src/cfgfile.c b/src/cfgfile.c index 68dbf8e7..33c9eabd 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -156,6 +156,11 @@ #define CONFIG_LEGACY_ANONYMOUS_ALLOW_WEB 1 #define CONFIG_LEGACY_ANONYMOUS_ALLOW_ADMIN NULL +enum bad_tag_reason { + BTR_UNKNOWN, + BTR_OBSOLETE +}; + static ice_config_t _current_configuration; static ice_config_locks _locks; @@ -372,6 +377,118 @@ static int __check_node_impl(xmlNodePtr node, const char *def) return res; } +static char *__build_node_name(xmlNodePtr node) +{ + char *buf[4]; + size_t have; + size_t i; + size_t len = 4; + char *ret; + char *p; + + memset(buf, 0, sizeof(buf)); + + for (have = 0; have < (sizeof(buf)/sizeof(*buf)); have++) { + int ret = -1; + xmlChar *id; + + id = xmlGetProp(node, XMLSTR("id")); + if (id) { + ret = asprintf(&(buf[have]), "%s[@id=\"%s\"]", node->name, id); + xmlFree(id); + } else if (xmlStrcmp(node->name, XMLSTR("mount")) == 0) { + xmlChar *mount = NULL; + xmlNodePtr child = node->xmlChildrenNode; + while (child && !mount) { + if (xmlStrcmp(child->name, XMLSTR("mount-name")) == 0) { + mount = xmlNodeListGetString(child->doc, child->xmlChildrenNode, 1); + } + child = child->next; + } + if (mount) { + ret = asprintf(&(buf[have]), "%s[mount-name/text()=\"%s\"]", node->name, mount); + xmlFree(mount); + } else { + ret = asprintf(&(buf[have]), "%s", node->name); + } + } else { + ret = asprintf(&(buf[have]), "%s", node->name); + } + + if (ret < 1) { + buf[have] = NULL; + for (i = 0; i < (sizeof(buf)/sizeof(*buf)); i++) + free(buf[i]); + return ""; + } + + node = node->parent; + if (!node) + break; + } + + for (i = 0; i < (sizeof(buf)/sizeof(*buf)); i++) { + if (buf[i]) + len += strlen(buf[i]) + 1; + } + + p = ret = malloc(len); + if (!ret) { + for (i = 0; i < (sizeof(buf)/sizeof(*buf)); i++) + free(buf[i]); + return ""; + } + + if (node && node->type != XML_DOCUMENT_NODE) { + memcpy(p, "...", 3); + p += 3; + } + + for (i = have; i > 0; i--) { + char *b = buf[i - 1]; + + if (b) { + size_t l = strlen(b); + + *p = '/'; + p++; + memcpy(p, b, l); + p += l; + free(b); + } + } + + *p = 0; + + return ret; +} + +static void __found_bad_tag(ice_config_t *configuration, xmlNodePtr node, enum bad_tag_reason reason, const char *replacement) +{ + char *name; + + // ignore comments. + if (node->type == XML_COMMENT_NODE) + return; + + name = __build_node_name(node); + + switch (reason) { + case BTR_UNKNOWN: + configuration->config_problems |= CONFIG_PROBLEM_UNKNOWN_NODE; + ICECAST_LOG_WARN("Unknown tag in config: %s", name); + break; + case BTR_OBSOLETE: + configuration->config_problems |= CONFIG_PROBLEM_OBSOLETE_NODE; + ICECAST_LOG_WARN("Obsolete tag in config: %s", name); + if (replacement) { + ICECAST_LOG_WARN("Obsolete tag %s can be replaced: %s", name, replacement); + } + break; + } + + free(name); +} static void __append_old_style_auth(auth_stack_t **stack, const char *name, @@ -1063,12 +1180,14 @@ static void _parse_root(xmlDocPtr doc, ICECAST_LOG_WARN(" defined outside " ". This is deprecated and will be removed in " "version 2.X.0"); + __found_bad_tag(configuration, node, BTR_OBSOLETE, "Use in ."); /* FIXME Settle target version for removal of this functionality! */ if (source_password) xmlFree(source_password); source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("icelogin")) == 0) { ICECAST_LOG_ERROR(" support has been removed."); + __found_bad_tag(configuration, node, BTR_OBSOLETE, NULL); } else if (xmlStrcmp(node->name, XMLSTR("fileserve")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->fileserve = util_str_to_bool(tmp); @@ -1084,7 +1203,7 @@ static void _parse_root(xmlDocPtr doc, xmlFree(configuration->hostname); configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("mime-types")) == 0) { - ICECAST_LOG_WARN(" has been moved into . Please update your configuration file."); + __found_bad_tag(configuration, node, BTR_OBSOLETE, "Use in ."); if (configuration->mimetypes_fn) xmlFree(configuration->mimetypes_fn); configuration->mimetypes_fn = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); @@ -1144,6 +1263,8 @@ static void _parse_root(xmlDocPtr doc, } else if (xmlStrcmp(node->name, XMLSTR("event-bindings")) == 0 || xmlStrcmp(node->name, XMLSTR("kartoffelsalat")) == 0) { _parse_events(&configuration->event, node->xmlChildrenNode); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); @@ -1259,7 +1380,7 @@ static void _parse_limits(xmlDocPtr doc, } else if (xmlStrcmp(node->name, XMLSTR("body-timeout")) == 0) { __read_int(doc, node, &configuration->body_timeout, " must not be empty."); } else if (xmlStrcmp(node->name, XMLSTR("burst-on-connect")) == 0) { - ICECAST_LOG_WARN(" is deprecated, use instead."); + __found_bad_tag(configuration, node, BTR_OBSOLETE, "Use ."); tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (util_str_to_int(tmp, 0) == 0) configuration->burst_size = 0; @@ -1267,8 +1388,8 @@ static void _parse_limits(xmlDocPtr doc, xmlFree(tmp); } else if (xmlStrcmp(node->name, XMLSTR("burst-size")) == 0) { __read_unsigned_int(doc, node, &configuration->burst_size, " must not be empty."); - } else if (node->type == XML_ELEMENT_NODE) { - ICECAST_LOG_ERROR("Unknown config tag: %s", node->name); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); } @@ -1548,9 +1669,7 @@ static void _parse_mount(xmlDocPtr doc, mount->charset = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("mp3-metadata-interval")) == 0) { - ICECAST_LOG_WARN(" is deprecated and will be " - "removed in a future version. " - "Please use instead."); + __found_bad_tag(configuration, node, BTR_OBSOLETE, "Use ."); /* FIXME when do we plan to remove this? */ __read_int(doc, node, &mount->mp3_meta_interval, " must not be empty."); } else if (xmlStrcmp(node->name, XMLSTR("icy-metadata-interval")) == 0) { @@ -1566,8 +1685,7 @@ static void _parse_mount(xmlDocPtr doc, if(tmp) xmlFree(tmp); } else if (xmlStrcmp(node->name, XMLSTR("no-yp")) == 0) { - ICECAST_LOG_WARN(" defined. Please use . This is " - "deprecated and will be removed in a future version."); + __found_bad_tag(configuration, node, BTR_OBSOLETE, "Use ."); /* FIXME when do we plan to remove this? */ tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->yp_public = util_str_to_bool(tmp) == 0 ? -1 : 0; @@ -1643,6 +1761,8 @@ static void _parse_mount(xmlDocPtr doc, } else if (xmlStrcmp(node->name, XMLSTR("event-bindings")) == 0 || xmlStrcmp(node->name, XMLSTR("kartoffelsalat")) == 0) { _parse_events(&mount->event, node->xmlChildrenNode); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); @@ -1918,6 +2038,8 @@ static void _parse_relay(xmlDocPtr doc, if (tmp) xmlFree(tmp); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); @@ -2001,6 +2123,8 @@ static void _parse_listen_socket(xmlDocPtr doc, _parse_authentication_node(node, &(listener->authstack)); } else if (xmlStrcmp(node->name, XMLSTR("http-headers")) == 0) { config_parse_http_headers(node->xmlChildrenNode, &(listener->http_headers)); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); @@ -2071,6 +2195,8 @@ static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, auth_t *auth = auth_get_authenticator(node); auth_stack_push(&new_style, auth); auth_release(auth); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); @@ -2408,6 +2534,8 @@ static void _parse_paths(xmlDocPtr doc, xmlFree(temp); } else if (xmlStrcmp(node->name, XMLSTR("resource")) == 0 || xmlStrcmp(node->name, XMLSTR("alias")) == 0) { _parse_resource(doc, node, configuration); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); } @@ -2480,6 +2608,8 @@ static void _parse_logging(xmlDocPtr doc, configuration->access_log_lines_kept = val; configuration->playlist_log_lines_kept = val; } + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); } @@ -2526,7 +2656,7 @@ static void _parse_tls_context(xmlDocPtr doc, xmlFree(context->cipher_list); context->cipher_list = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else { - ICECAST_LOG_ERROR("Unknown config tag: %s", node->name); + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); @@ -2608,6 +2738,8 @@ static void _parse_security(xmlDocPtr doc, seed->next = configuration->prng_seed; configuration->prng_seed = seed; } + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); } diff --git a/src/cfgfile.h b/src/cfgfile.h index d980ccbf..e348c2e8 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -32,6 +32,8 @@ #define CONFIG_PROBLEM_LOCATION 0x0002U #define CONFIG_PROBLEM_ADMIN 0x0004U #define CONFIG_PROBLEM_PRNG 0x0008U +#define CONFIG_PROBLEM_UNKNOWN_NODE 0x0010U +#define CONFIG_PROBLEM_OBSOLETE_NODE 0x0020U typedef enum _http_header_type { /* static: headers are passed as is to the client. */