1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-06-23 06:25:24 +00:00

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
This commit is contained in:
Philipp Schafft 2016-11-30 11:22:36 +00:00
parent 70265c466e
commit ce2b4195da
3 changed files with 86 additions and 107 deletions

View File

@ -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));

View File

@ -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;

View File

@ -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);