diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca0eda52a211ca62d546353b4c3784d075189a54..feee6655fa6ea8186eb1b435446f6178b793f808 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,9 +4,10 @@ build: GIT_SUBMODULE_STRATEGY: recursive tags: - - alpine - docker + image: alpine:3.12 + stage: build before_script: diff --git a/admin/moveclients.xsl b/admin/moveclients.xsl index 9328998a07cffe558bc02b020e656cce7062f80a..33ec6857be04a92ea0e63eb3448855da811dd945 100644 --- a/admin/moveclients.xsl +++ b/admin/moveclients.xsl @@ -26,9 +26,9 @@
- + Move from + + to + with direction +   diff --git a/conf/icecast.xml.in b/conf/icecast.xml.in index 54f7ba901f26ed4d7e1eba1af65b1c8a5da09dd9..7a9e7fbbc5b0f9cfc880ef5eda4d381ef5e2b4b6 100644 --- a/conf/icecast.xml.in +++ b/conf/icecast.xml.in @@ -267,7 +267,7 @@ @localstatedir@/log/@PACKAGE@ @pkgdatadir@/web @pkgdatadir@/admin - @pkgdatadir@/report-db.xml + @pkgdatadir@/report-db.xml + + + + + + + diff --git a/configure.ac b/configure.ac index d2d914e4d8ef88a164ad306a7b05716015a0ef49..ea9b315b25ac0258d5964d0e21f1e705c4c3081d 100644 --- a/configure.ac +++ b/configure.ac @@ -100,6 +100,8 @@ AC_CHECK_HEADERS([sys/timeb.h]) AC_CHECK_HEADERS([sys/socket.h]) AC_CHECK_HEADERS([pwd.h grp.h]) +AC_C_BIGENDIAN + XIPH_NET dnl Check for functions diff --git a/src/Makefile.am b/src/Makefile.am index 8051f70784100f4eeac7183508c55787336db2e0..1b49e3068bf2b0ad46293dac06011dd7325c0bd0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,9 +28,12 @@ noinst_HEADERS = \ xslt.h \ yp.h \ md5.h \ + digest.h \ + prng.h \ matchfile.h \ tls.h \ refobject.h \ + rqueue.h \ buffer.h \ module.h \ reportxml.h \ @@ -39,6 +42,7 @@ noinst_HEADERS = \ xml2json.h \ listensocket.h \ fastevent.h \ + navigation.h \ event.h \ event_log.h \ event_exec.h \ @@ -75,8 +79,11 @@ icecast_SOURCES = \ xslt.c \ fserve.c \ admin.c \ + rqueue.c \ resourcematch.c \ md5.c \ + digest.c \ + prng.c \ matchfile.c \ tls.c \ refobject.c \ @@ -88,6 +95,7 @@ icecast_SOURCES = \ xml2json.c \ listensocket.c \ fastevent.c \ + navigation.c \ format.c \ format_ogg.c \ format_mp3.c \ diff --git a/src/acl.c b/src/acl.c index bd02e7df80b743ef9b30d8ec9a9329d19c549ca1..908ffe64de156ee785ac22dcc730c240558b023c 100644 --- a/src/acl.c +++ b/src/acl.c @@ -121,7 +121,7 @@ acl_t *acl_new(void) return ret; } -acl_t *acl_new_from_xml_node(xmlNodePtr node) +acl_t *acl_new_from_xml_node(ice_config_t *configuration, xmlNodePtr node) { acl_t * ret; char * tmp; @@ -212,7 +212,7 @@ acl_t *acl_new_from_xml_node(xmlNodePtr node) if (xmlIsBlankNode(child)) continue; if (xmlStrcmp(child->name, XMLSTR("http-headers")) == 0) { - config_parse_http_headers(child->xmlChildrenNode, &(ret->http_headers)); + config_parse_http_headers(child->xmlChildrenNode, &(ret->http_headers), configuration); } } while ((child = child->next)); } diff --git a/src/acl.h b/src/acl.h index 6d53d28accd0503e0c7c3b6f64e7e97a6066bacc..fd6d91165828c17294fba9131039f87273350a2e 100644 --- a/src/acl.h +++ b/src/acl.h @@ -33,7 +33,7 @@ typedef enum acl_policy_tag { /* basic functions to work with ACLs */ acl_t * acl_new(void); -acl_t * acl_new_from_xml_node(xmlNodePtr node); +acl_t * acl_new_from_xml_node(ice_config_t *configuration, xmlNodePtr node); void acl_addref(acl_t * acl); void acl_release(acl_t * acl); diff --git a/src/admin.c b/src/admin.c index bfc57cc6c42a1aee22e38a9cd2a923f4faa208d2..3f51d9b694fe5c9feaec50dcb31df8865dcb2dfc 100644 --- a/src/admin.c +++ b/src/admin.c @@ -118,6 +118,8 @@ #define DEFAULT_RAW_REQUEST "" #define DEFAULT_HTML_REQUEST "" #define BUILDM3U_RAW_REQUEST "buildm3u" +#define RCHANNEL_AUTO_REQUEST "rchannel" +#define RCHANNEL_SOURCE_REQUEST "getrchannel" typedef struct { const char *prefix; @@ -207,9 +209,18 @@ static const admin_command_handler_t ui_handlers[] = { { "%s", ADMINTYPE_HYBRID, ADMIN_FORMAT_AUTO, ADMINSAFE_SAFE, NULL, ui_command} }; +static void command_rchannel (client_t *client, source_t *source, admin_format_t response); +static void command_get_rchannel (client_t *client, source_t *source, admin_format_t response); + +static const admin_command_handler_t rchannel_handlers[] = { + { RCHANNEL_AUTO_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_AUTO, ADMINSAFE_SAFE, command_rchannel, NULL}, + { RCHANNEL_SOURCE_REQUEST, ADMINTYPE_MOUNT, ADMIN_FORMAT_AUTO, ADMINSAFE_SAFE, command_get_rchannel, NULL} +}; + static admin_command_table_t command_tables[ADMIN_MAX_COMMAND_TABLES] = { {.prefix = NULL, .length = (sizeof(handlers)/sizeof(*handlers)), .handlers = handlers}, {.prefix = "ui", .length = (sizeof(ui_handlers)/sizeof(*ui_handlers)), .handlers = ui_handlers}, + {.prefix = "rchannel", .length = (sizeof(rchannel_handlers)/sizeof(*rchannel_handlers)), .handlers = rchannel_handlers} }; static inline int __is_command_table_valid(const admin_command_table_t * table) @@ -716,6 +727,7 @@ static void command_move_clients(client_t *client, { const char *dest_source; const char *idtext = NULL; + const char *directiontext = NULL; connection_id_t id; source_t *dest; char buf[255]; @@ -730,6 +742,8 @@ static void command_move_clients(client_t *client, } else { idtext = NULL; } + COMMAND_OPTIONAL(client, "direction", directiontext); + ICECAST_LOG_DEBUG("Done optional check (%d)", parameters_passed); if (!parameters_passed) { xmlDocPtr doc = admin_build_sourcelist(source->mount, client, response); @@ -766,7 +780,7 @@ static void command_move_clients(client_t *client, ICECAST_LOG_INFO("source is \"%s\", destination is \"%s\"", source->mount, dest->mount); - source_move_clients(source, dest, idtext ? &id : NULL); + source_move_clients(source, dest, idtext ? &id : NULL, navigation_str_to_direction(directiontext, NAVIGATION_DIRECTION_REPLACE_ALL)); snprintf(buf, sizeof(buf), "Clients moved from %s to %s", source->mount, dest_source); @@ -827,6 +841,15 @@ static inline xmlNodePtr __add_listener(client_t *client, xmlNewTextChild(node, NULL, XMLSTR("protocol"), XMLSTR(client_protocol_to_string(client->protocol))); + do { + xmlNodePtr history = xmlNewChild(node, NULL, XMLSTR("history"), NULL); + size_t i; + + for (i = 0; i < client->history.fill; i++) { + xmlNewTextChild(history, NULL, XMLSTR("mount"), XMLSTR(mount_identifier_get_mount(client->history.history[i]))); + } + } while (0); + return node; } @@ -1472,6 +1495,14 @@ static void command_dashboard (client_t *client, source_t *source, adm __reportxml_add_maintenance(reportnode, config->reportxml_db, "8defae31-a52e-4bba-b904-76db5362860f", "warning", "No useful location is given in .", NULL); if (config->config_problems & CONFIG_PROBLEM_ADMIN) __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 (config->config_problems & CONFIG_PROBLEM_INVALID_NODE) + __reportxml_add_maintenance(reportnode, config->reportxml_db, "0f6f757d-52d8-4b9a-8e57-9bcd528fffba", "error", "Invalid 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); @@ -1549,3 +1580,65 @@ static void ui_command(client_t * client, source_t * source, admin_format_t form client_send_error_by_id(client, ICECAST_ERROR_ADMIN_UNRECOGNISED_COMMAND); } } + +static void command_rchannel(client_t *client, source_t *source, admin_format_t response) +{ + if(source == NULL){ + ICECAST_LOG_DEBUG("Rchannel: Source is NULL"); + return; + } + const char * message = NULL; + COMMAND_REQUIRE(client, "message", message); + int message_length = strlen(message); + if(message_length == 0) + client_send_error_by_id(client, ICECAST_ERROR_RCHANNEL_MESSAGE_EMPTY); + else if(message_length > MESSAGE_MAXSIZE) + client_send_error_by_id(client, ICECAST_ERROR_RCHANNEL_MESSAGE_TOO_LONG); + else if(get_rchannel_queue_size(source) == RCHANNEL_QUEUE_MAXSIZE) /*QUEUE is full*/ + client_send_error_by_id(client, ICECAST_ERROR_RCHANNEL_QUEUE_FULL); + else { + add_message_rchannel_queue(source,message); + admin_send_response_simple(client,source,response,"Message Recieved",0); + } +} +static void command_get_rchannel(client_t *client, source_t *source, admin_format_t response){ + if(source == NULL) { + ICECAST_LOG_ERROR("Rchannel: Source is NULL"); + return; + } + else if(get_rchannel_queue_size(source) == 0) + client_send_error_by_id(client, ICECAST_ERROR_RCHANNEL_QUEUE_EMPTY); + else { + reportxml_node_t *rootnode; + reportxml_node_t *incidentnode; + reportxml_node_t *statenode; + reportxml_node_t *resource; + reportxml_node_t *messagenode; + reportxml_t *report = refobject_new(reportxml_t); + rootnode = reportxml_get_root_node(report); + int size = get_rchannel_queue_size(source); + while(size > 0){ + ICECAST_LOG_DEBUG("Inside the loop size is %d", size); + incidentnode = reportxml_node_new(REPORTXML_NODE_TYPE_INCIDENT, NULL, NULL, NULL); + statenode = reportxml_node_new(REPORTXML_NODE_TYPE_STATE, NULL, "348f649c-f78f-4741-977a-f1ad8afb514a", NULL); + resource = reportxml_node_new(REPORTXML_NODE_TYPE_RESOURCE, NULL, NULL, NULL); + messagenode = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL); + char *buf = get_message_rchannel_queue(source); + reportxml_helper_add_value_string(messagenode,"message",buf); + remove_message_rchannel_queue(source); + reportxml_node_add_child(resource, messagenode); + reportxml_node_add_child(incidentnode, statenode); + reportxml_node_add_child(incidentnode, resource); + reportxml_node_add_child(rootnode, incidentnode); + refobject_unref(messagenode); + refobject_unref(statenode); + refobject_unref(resource); + refobject_unref(incidentnode); + free(buf); + size--; + } + client_send_reportxml(client, report, DOCUMENT_DOMAIN_ADMIN, NULL, response, 200, NULL); + refobject_unref(rootnode); + refobject_unref(report); + } +} \ No newline at end of file diff --git a/src/auth.c b/src/auth.c index 5a550ac0030bbebf33154bf403ccfa0f4710a38e..210f7edf745dd8ef2f0bf4ac5196b54cc4e1dcba 100644 --- a/src/auth.c +++ b/src/auth.c @@ -795,7 +795,7 @@ static inline int auth_get_authenticator__permission_alter(auth_t *auth, xmlNode return 0; } -auth_t *auth_get_authenticator(xmlNodePtr node) +auth_t *auth_get_authenticator(ice_config_t *configuration, xmlNodePtr node) { auth_t *auth = calloc(1, sizeof(auth_t)); config_options_t *options = NULL, **next_option = &options; @@ -931,10 +931,10 @@ auth_t *auth_get_authenticator(xmlNodePtr node) *next_option = opt; next_option = &opt->next; } else if (xmlStrcmp (child->name, XMLSTR("http-headers")) == 0) { - config_parse_http_headers(child->xmlChildrenNode, &(auth->http_headers)); + config_parse_http_headers(child->xmlChildrenNode, &(auth->http_headers), configuration); } else if (xmlStrcmp (child->name, XMLSTR("acl")) == 0) { if (!auth->acl) { - auth->acl = acl_new_from_xml_node(child); + auth->acl = acl_new_from_xml_node(configuration, child); } else { ICECAST_LOG_ERROR("More than one ACL defined in role! Not supported (yet)."); } @@ -971,7 +971,7 @@ auth_t *auth_get_authenticator(xmlNodePtr node) if (!auth->acl) { /* If we did not get a try ACL as part of (old style). */ - auth->acl = acl_new_from_xml_node(node); + auth->acl = acl_new_from_xml_node(configuration, node); } if (!auth->acl) { auth_release(auth); diff --git a/src/auth.h b/src/auth.h index cacd9e99bc8ea7f5f11c6fb9e27d858c3b6f3511..4f99873cfa52c47db7c0fa89e34cbe1b4a12de29 100644 --- a/src/auth.h +++ b/src/auth.h @@ -186,7 +186,7 @@ void auth_shutdown(void); auth_result auth_str2result(const char *str); -auth_t *auth_get_authenticator(xmlNodePtr node); +auth_t *auth_get_authenticator(ice_config_t *configuration, xmlNodePtr node); void auth_release(auth_t *authenticator); void auth_addref(auth_t *authenticator); diff --git a/src/cfgfile.c b/src/cfgfile.c index 89d3ec581040f9102a90050d90536b6285625a00..e771c5c56602c2637006d588000784a550bcf51c 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -45,6 +45,7 @@ #include "main.h" #include "slave.h" #include "xslt.h" +#include "prng.h" #define CATMODULE "CONFIG" #define CONFIG_DEFAULT_LOCATION "Earth" @@ -155,9 +156,17 @@ #define CONFIG_LEGACY_ANONYMOUS_ALLOW_WEB 1 #define CONFIG_LEGACY_ANONYMOUS_ALLOW_ADMIN NULL +enum bad_tag_reason { + BTR_UNKNOWN, + BTR_OBSOLETE, + BTR_INVALID, + BTR_EMPTY +}; + static ice_config_t _current_configuration; static ice_config_locks _locks; +static void __found_bad_tag(ice_config_t *configuration, xmlNodePtr node, enum bad_tag_reason reason, const char *extra); static void _set_defaults(ice_config_t *c); static void _parse_root(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); @@ -184,7 +193,7 @@ static void _parse_events(event_registration_t **events, xmlNodePtr node); static void merge_mounts(mount_proxy * dst, mount_proxy * src); static inline void _merge_mounts_all(ice_config_t *c); -operation_mode config_str_to_omode(const char *str) +operation_mode config_str_to_omode(ice_config_t *configuration, xmlNodePtr node, const char *str) { if (!str || !*str) return OMODE_DEFAULT; @@ -197,12 +206,13 @@ operation_mode config_str_to_omode(const char *str) } else if (strcasecmp(str, "strict") == 0) { return OMODE_STRICT; } else { + __found_bad_tag(configuration, node, BTR_INVALID, str); ICECAST_LOG_ERROR("Unknown operation mode \"%s\", falling back to DEFAULT.", str); return OMODE_DEFAULT; } } -static listener_type_t config_str_to_listener_type(const char *str) +static listener_type_t config_str_to_listener_type(ice_config_t *configuration, xmlNodePtr node, const char *str) { if (!str || !*str) { return LISTENER_TYPE_NORMAL; @@ -211,17 +221,38 @@ static listener_type_t config_str_to_listener_type(const char *str) } else if (strcasecmp(str, "virtual") == 0) { return LISTENER_TYPE_VIRTUAL; } else { + __found_bad_tag(configuration, node, BTR_INVALID, str); ICECAST_LOG_ERROR("Unknown listener type \"%s\", falling back to NORMAL.", str); return LISTENER_TYPE_NORMAL; } } -char * config_href_to_id(const char *href) +static fallback_override_t config_str_to_fallback_override_t(ice_config_t *configuration, xmlNodePtr node, const char *str) +{ + if (!str || !*str || strcmp(str, "none") == 0) { + return FALLBACK_OVERRIDE_NONE; + } else if (strcasecmp(str, "all") == 0) { + return FALLBACK_OVERRIDE_ALL; + } else if (strcasecmp(str, "own") == 0) { + return FALLBACK_OVERRIDE_OWN; + } else { + if (util_str_to_bool(str)) { + ICECAST_LOG_WARN("Old style fallback override setting. Please replace %#H with \"all\".", str); + return FALLBACK_OVERRIDE_ALL; + } else { + ICECAST_LOG_WARN("Old style fallback override setting. Please replace %#H with \"none\".", str); + return FALLBACK_OVERRIDE_NONE; + } + } +} + +char * config_href_to_id(ice_config_t *configuration, xmlNodePtr node, const char *href) { if (!href || !*href) return NULL; if (*href != '#') { + __found_bad_tag(configuration, node, BTR_INVALID, href); ICECAST_LOG_ERROR("Can not convert string \"%H\" to ID.", href); return NULL; } @@ -261,11 +292,11 @@ void config_init_configuration(ice_config_t *configuration) configuration->reportxml_db = refobject_new(reportxml_database_t); } -static inline void __read_int(xmlDocPtr doc, xmlNodePtr node, int *val, const char *warning) +static inline void __read_int(ice_config_t *configuration, xmlDocPtr doc, xmlNodePtr node, int *val) { char *str = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (!str || !*str) { - ICECAST_LOG_WARN("%s", warning); + __found_bad_tag(configuration, node, BTR_EMPTY, NULL); } else { *val = util_str_to_int(str, *val); } @@ -273,11 +304,11 @@ static inline void __read_int(xmlDocPtr doc, xmlNodePtr node, int *val, const ch xmlFree(str); } -static inline void __read_unsigned_int(xmlDocPtr doc, xmlNodePtr node, unsigned int *val, const char *warning) +static inline void __read_unsigned_int(ice_config_t *configuration, xmlDocPtr doc, xmlNodePtr node, unsigned int *val) { char *str = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (!str || !*str) { - ICECAST_LOG_WARN("%s", warning); + __found_bad_tag(configuration, node, BTR_EMPTY, NULL); } else { *val = util_str_to_unsigned_int(str, *val); } @@ -352,8 +383,154 @@ 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 *extra) +{ + char *name = NULL; + + /* ignore non-configuration errors */ + if (!configuration) + return; + + // ignore comments. + if (node->type == XML_COMMENT_NODE) + return; + + if (node) + name = __build_node_name(node); -static void __append_old_style_auth(auth_stack_t **stack, + switch (reason) { + case BTR_UNKNOWN: + configuration->config_problems |= CONFIG_PROBLEM_UNKNOWN_NODE; + if (name) { + ICECAST_LOG_WARN("Unknown tag in config: %s", name); + } else { + ICECAST_LOG_WARN("Unknown tag in config"); + } + break; + case BTR_OBSOLETE: + configuration->config_problems |= CONFIG_PROBLEM_OBSOLETE_NODE; + if (name) { + ICECAST_LOG_WARN("Obsolete tag in config: %s", name); + if (extra) { + ICECAST_LOG_WARN("Obsolete tag %s can be replaced: %s", name, extra); + } + } else { + ICECAST_LOG_WARN("Obsolete tag in config"); + } + break; + case BTR_INVALID: + configuration->config_problems |= CONFIG_PROBLEM_INVALID_NODE; + if (name) { + if (extra) { + ICECAST_LOG_WARN("Invalid content for tag: %s: %s", name, extra); + } else { + ICECAST_LOG_WARN("Invalid content for tag: %s", name); + } + } else { + ICECAST_LOG_WARN("Invalid content for tag"); + } + break; + case BTR_EMPTY: + configuration->config_problems |= CONFIG_PROBLEM_INVALID_NODE; + if (name) { + ICECAST_LOG_WARN("Invalid empty tag: %s", name); + } else { + ICECAST_LOG_WARN("Invalid empty tag"); + } + break; + } + + free(name); +} + +static void __append_old_style_auth(ice_config_t *configuration, + auth_stack_t **stack, const char *name, const char *type, const char *username, @@ -409,7 +586,7 @@ static void __append_old_style_auth(auth_stack_t **stack, xmlSetProp(pass, XMLSTR("value"), XMLSTR(password)); } - auth = auth_get_authenticator(role); + auth = auth_get_authenticator(configuration, role); auth_stack_push(stack, auth); auth_release(auth); @@ -430,7 +607,8 @@ static void __append_option_tag(xmlNodePtr parent, xmlSetProp(node, XMLSTR("value"), XMLSTR(value)); } -static void __append_old_style_urlauth(auth_stack_t **stack, +static void __append_old_style_urlauth(ice_config_t *configuration, + auth_stack_t **stack, const char *client_add, const char *client_remove, const char *action_add, @@ -478,7 +656,7 @@ static void __append_old_style_urlauth(auth_stack_t **stack, __append_option_tag(role, "headers", headers); __append_option_tag(role, "header_prefix", header_prefix); - auth = auth_get_authenticator(role); + auth = auth_get_authenticator(configuration, role); if (auth) { auth_stack_push(stack, auth); auth_release(auth); @@ -663,6 +841,15 @@ listener_t *config_clear_listener(listener_t *listener) return next; } +static void config_clear_prng_seed(prng_seed_config_t *seed) +{ + while (seed) { + prng_seed_config_t *next = seed->next; + if (seed->filename) xmlFree(seed->filename); + seed = next; + } +} + void config_clear(ice_config_t *c) { mount_proxy *mount, @@ -728,6 +915,8 @@ void config_clear(ice_config_t *c) refobject_unref(c->reportxml_db); + config_clear_prng_seed(c->prng_seed); + memset(c, 0, sizeof(ice_config_t)); } @@ -765,6 +954,7 @@ void config_reread_config(void) config_set_config(&new_config); config = config_get_config_unlocked(); restart_logging(config); + prng_configure(config); main_config_reload(config); connection_reread_config(config); yp_recheck_config(config); @@ -1031,12 +1221,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); @@ -1052,7 +1244,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); @@ -1084,9 +1276,9 @@ static void _parse_root(xmlDocPtr doc, xmlFree(configuration->master_password); configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("master-server-port")) == 0) { - __read_int(doc, node, &configuration->master_server_port, " must not be empty."); + __read_int(configuration, doc, node, &configuration->master_server_port); } else if (xmlStrcmp(node->name, XMLSTR("master-update-interval")) == 0) { - __read_int(doc, node, &configuration->master_update_interval, " must not be empty."); + __read_int(configuration, doc, node, &configuration->master_update_interval); } else if (xmlStrcmp(node->name, XMLSTR("shoutcast-mount")) == 0) { if (configuration->shoutcast_mount) xmlFree(configuration->shoutcast_mount); @@ -1094,7 +1286,7 @@ static void _parse_root(xmlDocPtr doc, } else if (xmlStrcmp(node->name, XMLSTR("limits")) == 0) { _parse_limits(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp(node->name, XMLSTR("http-headers")) == 0) { - config_parse_http_headers(node->xmlChildrenNode, &(configuration->http_headers)); + config_parse_http_headers(node->xmlChildrenNode, &(configuration->http_headers), configuration); } else if (xmlStrcmp(node->name, XMLSTR("relay")) == 0) { _parse_relay(doc, node->xmlChildrenNode, configuration, NULL); } else if (xmlStrcmp(node->name, XMLSTR("mount")) == 0) { @@ -1112,6 +1304,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)); @@ -1132,7 +1326,7 @@ static void _parse_root(xmlDocPtr doc, } if (mount) { if (!mount->authstack) { - __append_old_style_auth(&mount->authstack, + __append_old_style_auth(configuration, &mount->authstack, CONFIG_LEGACY_SOURCE_NAME_GLOBAL, AUTH_TYPE_STATIC, "source", source_password, NULL, @@ -1153,6 +1347,23 @@ static void _parse_root(xmlDocPtr doc, if (configuration->port == 0) configuration->port = 8000; + if (!configuration->prng_seed) { + configuration->config_problems |= CONFIG_PROBLEM_PRNG; +#ifndef _WIN32 + configuration->prng_seed = calloc(1, sizeof(prng_seed_config_t)); + if (configuration->prng_seed) { + configuration->prng_seed->filename = (char*)xmlStrdup(XMLSTR("linux")); // the linux profile is also fine on BSD. + configuration->prng_seed->type = PRNG_SEED_TYPE_PROFILE; + configuration->prng_seed->size = -1; + ICECAST_LOG_WARN("Warning, no PRNG seed configured, using default profile \"linux\"."); + } else { + ICECAST_LOG_ERROR("No PRNG seed configured and unable to add one. PRNG is insecure."); + } +#else + ICECAST_LOG_ERROR("No PRNG seed configured and unable to add one. PRNG is insecure."); +#endif + } + /* issue some warnings on bad configurations */ if (!configuration->fileserve) ICECAST_LOG_WARN("Warning, serving of static files has been disabled " @@ -1194,37 +1405,37 @@ static void _parse_limits(xmlDocPtr doc, continue; if (xmlStrcmp(node->name, XMLSTR("clients")) == 0) { - __read_int(doc, node, &configuration->client_limit, " must not be empty."); + __read_int(configuration, doc, node, &configuration->client_limit); } else if (xmlStrcmp(node->name, XMLSTR("sources")) == 0) { - __read_int(doc, node, &configuration->source_limit, " must not be empty."); + __read_int(configuration, doc, node, &configuration->source_limit); } else if (xmlStrcmp(node->name, XMLSTR("bodysize")) == 0) { - __read_int(doc, node, &configuration->body_size_limit, " must not be empty."); + __read_int(configuration, doc, node, &configuration->body_size_limit); } else if (xmlStrcmp(node->name, XMLSTR("queue-size")) == 0) { - __read_unsigned_int(doc, node, &configuration->queue_size_limit, " must not be empty."); + __read_unsigned_int(configuration, doc, node, &configuration->queue_size_limit); } else if (xmlStrcmp(node->name, XMLSTR("client-timeout")) == 0) { - __read_int(doc, node, &configuration->client_timeout, " must not be empty."); + __read_int(configuration, doc, node, &configuration->client_timeout); } else if (xmlStrcmp(node->name, XMLSTR("header-timeout")) == 0) { - __read_int(doc, node, &configuration->header_timeout, " must not be empty."); + __read_int(configuration, doc, node, &configuration->header_timeout); } else if (xmlStrcmp(node->name, XMLSTR("source-timeout")) == 0) { - __read_int(doc, node, &configuration->source_timeout, " must not be empty."); + __read_int(configuration, doc, node, &configuration->source_timeout); } else if (xmlStrcmp(node->name, XMLSTR("body-timeout")) == 0) { - __read_int(doc, node, &configuration->body_timeout, " must not be empty."); + __read_int(configuration, doc, node, &configuration->body_timeout); } 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; if (tmp) 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); + __read_unsigned_int(configuration, doc, node, &configuration->burst_size); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); } -static void _parse_authentication_node(xmlNodePtr node, auth_stack_t **authstack) +static void _parse_authentication_node(ice_config_t *configuration, xmlNodePtr node, auth_stack_t **authstack) { xmlChar *tmp; @@ -1245,7 +1456,7 @@ static void _parse_authentication_node(xmlNodePtr node, auth_stack_t **authstac if (xmlIsBlankNode(child)) continue; if (xmlStrcmp(child->name, XMLSTR("role")) == 0) { - auth_t *auth = auth_get_authenticator(child); + auth_t *auth = auth_get_authenticator(configuration, child); auth_stack_push(authstack, auth); auth_release(auth); } @@ -1254,7 +1465,8 @@ static void _parse_authentication_node(xmlNodePtr node, auth_stack_t **authstac static void _parse_mount_oldstyle_authentication(mount_proxy *mount, xmlNodePtr node, - auth_stack_t **authstack) + auth_stack_t **authstack, + ice_config_t *configuration) { int allow_duplicate_users = 1; auth_t *auth; @@ -1287,13 +1499,13 @@ static void _parse_mount_oldstyle_authentication(mount_proxy *mount, if (!allow_duplicate_users) xmlSetProp(node, XMLSTR("connections-per-user"), XMLSTR("0")); - auth = auth_get_authenticator(node); + auth = auth_get_authenticator(configuration, node); if (auth) { auth_stack_push(authstack, auth); auth_release(auth); } - __append_old_style_auth(authstack, NULL, AUTH_TYPE_ANONYMOUS, + __append_old_style_auth(configuration, authstack, NULL, AUTH_TYPE_ANONYMOUS, NULL, NULL, CONFIG_LEGACY_ANONYMOUS_METHODS, NULL, 0, NULL); } else if (strcmp(type, AUTH_TYPE_URL) == 0) { /* This block is super fun! Attention! Super fun ahead! Ladies and Gentlemen take care and watch your children! */ @@ -1375,17 +1587,17 @@ static void _parse_mount_oldstyle_authentication(mount_proxy *mount, __append_old_style_url_event(&mount->event, "source-disconnect", mount_add, "mount_remove", username, password); - __append_old_style_urlauth(authstack, listener_add, listener_remove, + __append_old_style_urlauth(configuration, authstack, listener_add, listener_remove, "listener_add", "listener_remove", username, password, 0, auth_header, timelimit_header, headers, header_prefix); - __append_old_style_urlauth(authstack, stream_auth, NULL, "stream_auth", + __append_old_style_urlauth(configuration, authstack, stream_auth, NULL, "stream_auth", NULL, username, password, 1, auth_header, timelimit_header, headers, header_prefix); if (listener_add) - __append_old_style_auth(authstack, NULL, AUTH_TYPE_ANONYMOUS, NULL, + __append_old_style_auth(configuration, authstack, NULL, AUTH_TYPE_ANONYMOUS, NULL, NULL, CONFIG_LEGACY_ANONYMOUS_METHODS, NULL, 0, NULL); if (stream_auth) - __append_old_style_auth(authstack, NULL, AUTH_TYPE_ANONYMOUS, NULL, + __append_old_style_auth(configuration, authstack, NULL, AUTH_TYPE_ANONYMOUS, NULL, NULL, CONFIG_LEGACY_SOURCE_METHODS, NULL, 0, NULL); if (mount_add) @@ -1413,7 +1625,7 @@ static void _parse_mount_oldstyle_authentication(mount_proxy *mount, } else { ICECAST_LOG_ERROR("Unknown authentication type in legacy mode. " "Anonymous listeners and global login for sources disabled."); - __append_old_style_auth(authstack, NULL, AUTH_TYPE_ANONYMOUS, NULL, + __append_old_style_auth(configuration, authstack, NULL, AUTH_TYPE_ANONYMOUS, NULL, NULL, NULL, NULL, 0, NULL); } xmlFree(type); @@ -1487,7 +1699,7 @@ static void _parse_mount(xmlDocPtr doc, if(tmp) xmlFree(tmp); } else if (xmlStrcmp(node->name, XMLSTR("max-listeners")) == 0) { - __read_int(doc, node, &mount->max_listeners, " must not be empty."); + __read_int(configuration, doc, node, &mount->max_listeners); } else if (xmlStrcmp(node->name, XMLSTR("max-history")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->max_history = util_str_to_int(tmp, mount->max_history); @@ -1499,16 +1711,14 @@ 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."); + __read_int(configuration, doc, node, &mount->mp3_meta_interval); } else if (xmlStrcmp(node->name, XMLSTR("icy-metadata-interval")) == 0) { - __read_int(doc, node, &mount->mp3_meta_interval, " must not be empty."); + __read_int(configuration, doc, node, &mount->mp3_meta_interval); } else if (xmlStrcmp(node->name, XMLSTR("fallback-override")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - mount->fallback_override = util_str_to_bool(tmp); + mount->fallback_override = config_str_to_fallback_override_t(configuration, node, tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp(node->name, XMLSTR("no-mount")) == 0) { @@ -1517,8 +1727,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; @@ -1533,9 +1742,9 @@ static void _parse_mount(xmlDocPtr doc, tmp = (char *)xmlGetProp(node, XMLSTR("type")); if (tmp) { xmlFree(tmp); - _parse_mount_oldstyle_authentication(mount, node, &authstack); + _parse_mount_oldstyle_authentication(mount, node, &authstack, configuration); } else { - _parse_authentication_node(node, &authstack); + _parse_authentication_node(configuration, node, &authstack); } } else if (xmlStrcmp(node->name, XMLSTR("on-connect")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); @@ -1552,13 +1761,13 @@ static void _parse_mount(xmlDocPtr doc, xmlFree(tmp); } } else if (xmlStrcmp(node->name, XMLSTR("max-listener-duration")) == 0) { - __read_unsigned_int(doc, node, &mount->max_listener_duration, " must not be empty."); + __read_unsigned_int(configuration, doc, node, &mount->max_listener_duration); } else if (xmlStrcmp(node->name, XMLSTR("queue-size")) == 0) { - __read_unsigned_int(doc, node, &mount->queue_size_limit, " must not be empty."); + __read_unsigned_int(configuration, doc, node, &mount->queue_size_limit); } else if (xmlStrcmp(node->name, XMLSTR("source-timeout")) == 0) { - __read_unsigned_int(doc, node, &mount->source_timeout, " must not be empty."); + __read_unsigned_int(configuration, doc, node, &mount->source_timeout); } else if (xmlStrcmp(node->name, XMLSTR("burst-size")) == 0) { - __read_int(doc, node, &mount->burst_size, " must not be empty."); + __read_int(configuration, doc, node, &mount->burst_size); } else if (xmlStrcmp(node->name, XMLSTR("cluster-password")) == 0) { mount->cluster_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); @@ -1590,10 +1799,12 @@ static void _parse_mount(xmlDocPtr doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("http-headers")) == 0) { config_parse_http_headers(node->xmlChildrenNode, - &(mount->http_headers)); + &(mount->http_headers), configuration); } 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)); @@ -1618,7 +1829,7 @@ static void _parse_mount(xmlDocPtr doc, if (password) { auth_stack_t *old_style = NULL; - __append_old_style_auth(&old_style, CONFIG_LEGACY_SOURCE_NAME_MOUNT, + __append_old_style_auth(configuration, &old_style, CONFIG_LEGACY_SOURCE_NAME_MOUNT, AUTH_TYPE_STATIC, username ? username : "source", password, NULL, CONFIG_LEGACY_SOURCE_METHODS, CONFIG_LEGACY_SOURCE_ALLOW_WEB, CONFIG_LEGACY_SOURCE_ALLOW_ADMIN); if (authstack) { @@ -1665,7 +1876,7 @@ static void _parse_mount(xmlDocPtr doc, current = current->next; } - if (!mount->fallback_mount && (mount->fallback_when_full || mount->fallback_override)) { + if (!mount->fallback_mount && (mount->fallback_when_full || mount->fallback_override != FALLBACK_OVERRIDE_NONE)) { ICECAST_LOG_WARN("Config for mount %s contains fallback options " "but no fallback mount.", mount->mountname); } @@ -1678,7 +1889,8 @@ static void _parse_mount(xmlDocPtr doc, } void config_parse_http_headers(xmlNodePtr node, - ice_config_http_header_t **http_headers) + ice_config_http_header_t **http_headers, + ice_config_t *configuration) { ice_config_http_header_t *header; ice_config_http_header_t *next; @@ -1707,8 +1919,7 @@ void config_parse_http_headers(xmlNodePtr node, } else if (strcmp(tmp, "cors") == 0 || strcmp(tmp, "corpse") == 0) { type = HTTP_HEADER_TYPE_CORS; } else { - ICECAST_LOG_WARN("Unknown type %s for " - "HTTP Header %s", tmp, name); + __found_bad_tag(configuration, node, BTR_INVALID, tmp); xmlFree(tmp); break; } @@ -1751,7 +1962,8 @@ void config_parse_http_headers(xmlNodePtr node, static void _parse_relay_upstream(xmlDocPtr doc, xmlNodePtr node, - relay_config_upstream_t *upstream) + relay_config_upstream_t *upstream, + ice_config_t *configuration) { char *tmp; @@ -1767,7 +1979,7 @@ static void _parse_relay_upstream(xmlDocPtr doc, upstream->server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("port")) == 0) { - __read_int(doc, node, &upstream->port, " setting must not be empty."); + __read_int(configuration, doc, node, &upstream->port); } else if (xmlStrcmp(node->name, XMLSTR("mount")) == 0) { if (upstream->mount) xmlFree(upstream->mount); @@ -1828,7 +2040,7 @@ static void _parse_relay(xmlDocPtr doc, relay->upstream_default.mp3metadata = 1; relay->on_demand = configuration->on_demand; - _parse_relay_upstream(doc, node, &(relay->upstream_default)); + _parse_relay_upstream(doc, node, &(relay->upstream_default), configuration); do { if (node == NULL) @@ -1858,17 +2070,25 @@ static void _parse_relay(xmlDocPtr doc, if (n) { relay->upstream = n; memset(&(n[relay->upstreams]), 0, sizeof(relay_config_upstream_t)); - _parse_relay_upstream(doc, node->xmlChildrenNode, &(n[relay->upstreams])); + _parse_relay_upstream(doc, node->xmlChildrenNode, &(n[relay->upstreams]), configuration); relay->upstreams++; } } else if (strcmp(tmp, "default") == 0) { - _parse_relay_upstream(doc, node->xmlChildrenNode, &(relay->upstream_default)); + _parse_relay_upstream(doc, node->xmlChildrenNode, &(relay->upstream_default), configuration); } else { + __found_bad_tag(configuration, node, BTR_INVALID, tmp); ICECAST_LOG_WARN(" of unknown type is ignored."); } if (tmp) xmlFree(tmp); + } else if (xmlStrcmp(node->name, XMLSTR("server")) == 0 || xmlStrcmp(node->name, XMLSTR("port")) == 0 || + xmlStrcmp(node->name, XMLSTR("mount")) == 0 || xmlStrcmp(node->name, XMLSTR("relay-shoutcast-metadata")) == 0 || + xmlStrcmp(node->name, XMLSTR("username")) == 0 || xmlStrcmp(node->name, XMLSTR("password")) == 0 || + xmlStrcmp(node->name, XMLSTR("bind")) == 0) { + __found_bad_tag(configuration, node, BTR_OBSOLETE, "Use a block."); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); @@ -1897,12 +2117,12 @@ static void _parse_listen_socket(xmlDocPtr doc, tmp = (char*)xmlGetProp(node, XMLSTR("on-behalf-of")); if (tmp) { - listener->on_behalf_of = config_href_to_id(tmp); + listener->on_behalf_of = config_href_to_id(configuration, node, tmp); xmlFree(tmp); } tmp = (char *)xmlGetProp(node, XMLSTR("type")); - listener->type = config_str_to_listener_type(tmp); + listener->type = config_str_to_listener_type(configuration, node, tmp); xmlFree(tmp); node = node->xmlChildrenNode; @@ -1945,13 +2165,15 @@ static void _parse_listen_socket(xmlDocPtr doc, listener->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("so-sndbuf")) == 0) { - __read_int(doc, node, &listener->so_sndbuf, " must not be empty."); + __read_int(configuration, doc, node, &listener->so_sndbuf); } else if (xmlStrcmp(node->name, XMLSTR("listen-backlog")) == 0) { - __read_int(doc, node, &listener->listen_backlog, " must not be empty."); + __read_int(configuration, doc, node, &listener->listen_backlog); } else if (xmlStrcmp(node->name, XMLSTR("authentication")) == 0) { - _parse_authentication_node(node, &(listener->authstack)); + _parse_authentication_node(configuration, node, &(listener->authstack)); } else if (xmlStrcmp(node->name, XMLSTR("http-headers")) == 0) { - config_parse_http_headers(node->xmlChildrenNode, &(listener->http_headers)); + config_parse_http_headers(node->xmlChildrenNode, &(listener->http_headers), configuration); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); @@ -2019,18 +2241,20 @@ static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, xmlFree(configuration->shoutcast_user); configuration->shoutcast_user = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("role")) == 0) { - auth_t *auth = auth_get_authenticator(node); + auth_t *auth = auth_get_authenticator(configuration, node); auth_stack_push(&new_style, auth); auth_release(auth); + } else { + __found_bad_tag(configuration, node, BTR_UNKNOWN, NULL); } } while ((node = node->next)); if (admin_password && admin_username) - __append_old_style_auth(&old_style, CONFIG_LEGACY_ADMIN_NAME, AUTH_TYPE_STATIC, + __append_old_style_auth(configuration, &old_style, CONFIG_LEGACY_ADMIN_NAME, AUTH_TYPE_STATIC, admin_username, admin_password, NULL, CONFIG_LEGACY_ADMIN_METHODS, CONFIG_LEGACY_ADMIN_ALLOW_WEB, CONFIG_LEGACY_ADMIN_ALLOW_ADMIN); if (relay_password && relay_username) - __append_old_style_auth(&old_style, CONFIG_LEGACY_RELAY_NAME, AUTH_TYPE_STATIC, + __append_old_style_auth(configuration, &old_style, CONFIG_LEGACY_RELAY_NAME, AUTH_TYPE_STATIC, relay_username, relay_password, NULL, CONFIG_LEGACY_RELAY_METHODS, CONFIG_LEGACY_RELAY_ALLOW_WEB, CONFIG_LEGACY_RELAY_ALLOW_ADMIN); if (admin_password) @@ -2050,7 +2274,7 @@ static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, } /* default unauthed anonymous account */ - __append_old_style_auth(&old_style, CONFIG_LEGACY_ANONYMOUS_NAME, AUTH_TYPE_ANONYMOUS, + __append_old_style_auth(configuration, &old_style, CONFIG_LEGACY_ANONYMOUS_NAME, AUTH_TYPE_ANONYMOUS, NULL, NULL, NULL, CONFIG_LEGACY_ANONYMOUS_METHODS, CONFIG_LEGACY_ANONYMOUS_ALLOW_WEB, CONFIG_LEGACY_ANONYMOUS_ALLOW_ADMIN); if (!old_style) ICECAST_LOG_ERROR("BAD. old_style=NULL"); @@ -2084,9 +2308,9 @@ static void _parse_oldstyle_directory(xmlDocPtr doc, xmlFree(yp_dir->url); yp_dir->url = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("yp-url-timeout")) == 0) { - __read_int(doc, node, &yp_dir->timeout, " must not be empty."); + __read_int(configuration, doc, node, &yp_dir->timeout); } else if (xmlStrcmp(node->name, XMLSTR("touch-interval")) == 0) { - __read_int(doc, node, &yp_dir->touch_interval, " must not be empty."); + __read_int(configuration, doc, node, &yp_dir->touch_interval); } } while ((node = node->next)); @@ -2148,7 +2372,8 @@ static void _parse_yp_directory(xmlDocPtr doc, "Only the last one will be used."); free(yp_dir->listen_socket_id); } - yp_dir->listen_socket_id = config_href_to_id(opt->value); + /* FIXME: Pass the correct node to config_href_to_id(). */ + yp_dir->listen_socket_id = config_href_to_id(configuration, NULL, opt->value); } else { ICECAST_LOG_WARN("Invalid YP