Commit ce2b4195 authored by Philipp Schafft's avatar Philipp Schafft 🦁

Fix: Fixes a number of empty string segfaults in config parser

This fixes a number of segfault happening in case config tags are
empty. This patch also adds warnings for most cases.

Please test for any regressions.
This should likely be ported to 2.4.4 as well.

Closes: #2265
parent 70265c46
......@@ -195,6 +195,30 @@ void config_init_configuration(ice_config_t *configuration)
_set_defaults(configuration);
}
static inline void __read_int(xmlDocPtr doc, xmlNodePtr node, int *val, const char *warning)
{
char *str = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
if (!str || !*str) {
ICECAST_LOG_WARN("%s", warning);
} else {
*val = util_str_to_int(str, *val);
}
if (str)
xmlFree(str);
}
static inline void __read_unsigned_int(xmlDocPtr doc, xmlNodePtr node, unsigned int *val, const char *warning)
{
char *str = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
if (!str || !*str) {
ICECAST_LOG_WARN("%s", warning);
} else {
*val = util_str_to_unsigned_int(str, *val);
}
if (str)
xmlFree(str);
}
static inline int __parse_public(const char *str)
{
/* values that are not bool */
......@@ -895,7 +919,7 @@ static void _parse_root(xmlDocPtr doc,
_parse_listen_socket(doc, node->xmlChildrenNode, configuration);
} else if (xmlStrcmp(node->name, XMLSTR("port")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
if (tmp) {
if (tmp && *tmp) {
configuration->port = atoi(tmp);
configuration->listen_sock->port = atoi(tmp);
xmlFree(tmp);
......@@ -919,13 +943,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) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->master_server_port = atoi(tmp);
xmlFree(tmp);
__read_int(doc, node, &configuration->master_server_port, "<master-server-port> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("master-update-interval")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->master_update_interval = atoi(tmp);
xmlFree(tmp);
__read_int(doc, node, &configuration->master_update_interval, "<master-update-interval> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("shoutcast-mount")) == 0) {
if (configuration->shoutcast_mount)
xmlFree(configuration->shoutcast_mount);
......@@ -1029,49 +1049,29 @@ static void _parse_limits(xmlDocPtr doc,
continue;
if (xmlStrcmp(node->name, XMLSTR("clients")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->client_limit = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &configuration->client_limit, "<clients> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("sources")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->source_limit = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &configuration->source_limit, "<sources> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("queue-size")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->queue_size_limit = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_unsigned_int(doc, node, &configuration->queue_size_limit, "<queue-size> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("threadpool")) == 0) {
ICECAST_LOG_WARN("<threadpool> functionality was removed in Icecast"
" version 2.3.0, please remove this from your config.");
} else if (xmlStrcmp(node->name, XMLSTR("client-timeout")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->client_timeout = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &configuration->client_timeout, "<client-timeout> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("header-timeout")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->header_timeout = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &configuration->header_timeout, "<header-timeout> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("source-timeout")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->source_timeout = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &configuration->source_timeout, "<source-timeout> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("burst-on-connect")) == 0) {
ICECAST_LOG_WARN("<burst-on-connect> is deprecated, use <burst-size> instead.");
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
if (atoi(tmp) == 0)
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) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->burst_size = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_unsigned_int(doc, node, &configuration->burst_size, "<burst-size> must not be empty.");
}
} while ((node = node->next));
}
......@@ -1313,13 +1313,10 @@ static void _parse_mount(xmlDocPtr doc,
if(tmp)
xmlFree(tmp);
} else if (xmlStrcmp(node->name, XMLSTR("max-listeners")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
mount->max_listeners = atoi(tmp);
if(tmp)
xmlFree(tmp);
__read_int(doc, node, &mount->max_listeners, "<max-listeners> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("max-history")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
mount->max_history = atoi(tmp);
mount->max_history = util_str_to_int(tmp, mount->max_history);
if (mount->max_history < 1 || mount->max_history > 256)
mount->max_history = 256; /* deny super huge values */
if(tmp)
......@@ -1332,15 +1329,9 @@ static void _parse_mount(xmlDocPtr doc,
"removed in a future version. "
"Please use <icy-metadata-interval> instead.");
/* FIXME when do we plan to remove this? */
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
mount->mp3_meta_interval = atoi(tmp);
if(tmp)
xmlFree(tmp);
__read_int(doc, node, &mount->mp3_meta_interval, "<mp3-metadata-interval> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("icy-metadata-interval")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
mount->mp3_meta_interval = atoi(tmp);
if(tmp)
xmlFree(tmp);
__read_int(doc, node, &mount->mp3_meta_interval, "<icy-metadata-interval> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("fallback-override")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
mount->fallback_override = util_str_to_bool(tmp);
......@@ -1398,26 +1389,13 @@ static void _parse_mount(xmlDocPtr doc,
xmlFree(tmp);
}
} else if (xmlStrcmp(node->name, XMLSTR("max-listener-duration")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
mount->max_listener_duration = atoi(tmp);
if(tmp)
xmlFree(tmp);
__read_unsigned_int(doc, node, &mount->max_listener_duration, "<max-listener-duration> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("queue-size")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
mount->queue_size_limit = atoi(tmp);
if(tmp)
xmlFree(tmp);
__read_unsigned_int(doc, node, &mount->queue_size_limit, "<queue-size> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("source-timeout")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
if (tmp) {
mount->source_timeout = atoi(tmp);
xmlFree(tmp);
}
__read_unsigned_int(doc, node, &mount->source_timeout, "<source-timeout> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("burst-size")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
mount->burst_size = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &mount->burst_size, "<burst-size> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("cluster-password")) == 0) {
mount->cluster_password = (char *)xmlNodeListGetString(doc,
node->xmlChildrenNode, 1);
......@@ -1556,7 +1534,7 @@ static void _parse_http_headers(xmlDocPtr doc,
status = 0; /* default: any */
if ((tmp = (char *)xmlGetProp(node, XMLSTR("status")))) {
status = atoi(tmp);
status = util_str_to_int(tmp, 0);
xmlFree(tmp);
}
......@@ -1626,13 +1604,7 @@ static void _parse_relay(xmlDocPtr doc,
relay->server = (char *)xmlNodeListGetString(doc,
node->xmlChildrenNode, 1);
} else if (xmlStrcmp(node->name, XMLSTR("port")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
if (tmp) {
relay->port = atoi(tmp);
xmlFree(tmp);
} else {
ICECAST_LOG_WARN("<port> setting must not be empty.");
}
__read_int(doc, node, &relay->port, "<port> setting must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("mount")) == 0) {
if (relay->mount)
xmlFree(relay->mount);
......@@ -1695,8 +1667,8 @@ static void _parse_listen_socket(xmlDocPtr doc,
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
if (tmp) {
if(configuration->port == 0)
configuration->port = atoi(tmp);
listener->port = atoi(tmp);
configuration->port = util_str_to_int(tmp, 0);
listener->port = util_str_to_int(tmp, listener->port);
xmlFree(tmp);
} else {
ICECAST_LOG_WARN("<port> setting must not be empty.");
......@@ -1723,10 +1695,7 @@ 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) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
listener->so_sndbuf = atoi(tmp);
if(tmp)
xmlFree(tmp);
__read_int(doc, node, &listener->so_sndbuf, "<so-sndbuf> must not be empty.");
}
} while ((node = node->next));
......@@ -1835,8 +1804,6 @@ static void _parse_directory(xmlDocPtr doc,
xmlNodePtr node,
ice_config_t *configuration)
{
char *tmp;
if (configuration->num_yp_directories >= MAX_YP_DIRECTORIES) {
ICECAST_LOG_ERROR("Maximum number of yp directories exceeded!");
return;
......@@ -1853,20 +1820,11 @@ static void _parse_directory(xmlDocPtr doc,
configuration->yp_url[configuration->num_yp_directories] =
(char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
} else if (xmlStrcmp(node->name, XMLSTR("yp-url-timeout")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->yp_url_timeout[configuration->num_yp_directories] =
atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &configuration->yp_url_timeout[configuration->num_yp_directories], "<yp-url-timeout> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("server")) == 0) {
_add_server(doc, node->xmlChildrenNode, configuration);
} else if (xmlStrcmp(node->name, XMLSTR("touch-interval")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration
->yp_touch_interval[configuration->num_yp_directories] =
atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &configuration->yp_touch_interval[configuration->num_yp_directories], "<touch-interval> must not be empty.");
}
} while ((node = node->next));
if (configuration->yp_url[configuration->num_yp_directories] == NULL)
......@@ -1971,7 +1929,7 @@ static void _parse_paths(xmlDocPtr doc,
}
temp = (char *)xmlGetProp(node, XMLSTR("port"));
if(temp != NULL) {
alias->port = atoi(temp);
alias->port = util_str_to_int(temp, alias->port);
xmlFree(temp);
} else {
alias->port = -1;
......@@ -2032,20 +1990,14 @@ static void _parse_logging(xmlDocPtr doc,
xmlFree(configuration->playlist_log);
configuration->playlist_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
} else if (xmlStrcmp(node->name, XMLSTR("logsize")) == 0) {
char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->logsize = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &configuration->logsize, "<logsize> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("loglevel")) == 0) {
char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->loglevel = util_str_to_loglevel(tmp);
if (tmp)
xmlFree(tmp);
} else if (xmlStrcmp(node->name, XMLSTR("logarchive")) == 0) {
char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->logarchive = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &configuration->logarchive, "<logarchive> must not be empty.");
}
} while ((node = node->next));
}
......@@ -2099,7 +2051,6 @@ static void _add_server(xmlDocPtr doc,
ice_config_dir_t *dirnode,
*server;
int addnode;
char *tmp;
server = (ice_config_dir_t *)malloc(sizeof(ice_config_dir_t));
server->touch_interval = configuration->touch_interval;
......@@ -2117,10 +2068,7 @@ static void _add_server(xmlDocPtr doc,
node->xmlChildrenNode, 1);
addnode = 1;
} else if (xmlStrcmp(node->name, XMLSTR("touch-interval")) == 0) {
tmp = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
server->touch_interval = atoi(tmp);
if (tmp)
xmlFree(tmp);
__read_int(doc, node, &server->touch_interval, "<touch-interval> must not be empty.");
}
server->next = NULL;
} while ((node = node->next));
......
......@@ -565,6 +565,35 @@ int util_str_to_loglevel(const char *str) {
return atoi(str);
}
int util_str_to_int(const char *str, const int default_value)
{
/* consider NULL and empty strings default */
if (!str || !*str)
return default_value;
return atoi(str);
}
unsigned int util_str_to_unsigned_int(const char *str, const unsigned int default_value)
{
long int val;
char *rem = NULL;
/* consider NULL and empty strings default */
if (!str || !*str)
return default_value;
val = strtol(str, &rem, 10);
/* There is a left over */
if (rem && *rem)
return default_value;
if (val < 0)
return default_value;
return (unsigned int)(unsigned long int)val;
}
/* TODO, FIXME: handle memory allocation errors better. */
static inline void _build_headers_loop(char **ret, size_t *len, ice_config_http_header_t *header, int status) {
size_t headerlen;
......
......@@ -51,6 +51,8 @@ util_hostcheck_type util_hostcheck(const char *hostname);
int util_str_to_bool(const char *str);
int util_str_to_loglevel(const char *str);
int util_str_to_int(const char *str, const int default_value);
unsigned int util_str_to_unsigned_int(const char *str, const unsigned int default_value);
char *util_url_unescape(const char *src);
char *util_url_escape(const char *src);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment