From 4eed8fe78dcd9c99b8545eb41b5d79402edf1dcb Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Mon, 10 Nov 2014 11:15:49 +0000 Subject: [PATCH] sync with master svn path=/icecast/branches/ph3/icecast/; revision=19301 --- AUTHORS | 2 +- ChangeLog | 130 ++++++++++++++++++++++++++++++++++++ admin/vclt.xsl | 4 +- admin/xspf.xsl | 2 +- conf/icecast.xml.in | 95 +++++++++++++++++++++----- conf/icecast_minimal.xml.in | 8 ++- src/admin.c | 71 ++++++++++++++++++-- src/cfgfile.c | 6 +- src/client.c | 21 ++++++ src/client.h | 1 + src/format.c | 24 ++++++- src/fserve.c | 15 +++++ src/xslt.c | 49 +++++++++++--- 13 files changed, 385 insertions(+), 43 deletions(-) diff --git a/AUTHORS b/AUTHORS index b063debc..47a45b4e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,5 +3,5 @@ Michael Smith oddsock Karl Heyes Philipp "ph3-der-loewe" Schafft -Thomas B. "dm8tbr" Ruecker +Thomas B. "dm8tbr" Ruecker David "oneman" Richards diff --git a/ChangeLog b/ChangeLog index 82933642..94377864 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,133 @@ + +2014-11-08 16:23:26 dm8tbr + + * Applying patch by ph3-der-loewe, HTTP PUT requires content-type + * In case of SOURCE we are lenient and thus quite some source clients + don't send a proper content-type, especially if they only support mp3. + * This was meant to be introduced in 2.4.0 already, sadly we missed it. + * All source clients MUST send proper content-type after migrating to + Icecast HTTP PUT protocol. + +2014-11-08 13:34:45 ph3-der-loewe + + * Fixed regression introduced in r18356 (CVE-2011-4612): client + duration time is now correctly logged. PRIu64 MUST NOT be used with + log_write_direct() as depending on platform PRIu64 may be using + something not supported by __vsnprintf() of log/log.c. + +2014-11-08 12:28:17 ph3-der-loewe + + * make use of sizeof() not explicit magic numbers + +2014-11-07 23:10:43 ph3-der-loewe + + * fixing some compiler warnings + +2014-11-07 22:06:06 ph3-der-loewe + + * updated some copyright headers + +2014-11-07 20:56:04 ph3-der-loewe + + * fix for %z on win*. hope it doesn't breaky anything else. + +2014-11-07 19:14:28 ph3-der-loewe + + * added warnings on empty and default values of , + , , and + +2014-11-07 11:18:54 ph3-der-loewe + + * send errorlog (loglevel WARN) to stderr prior to opening the real + logfiles. + +2014-11-07 10:12:24 ph3-der-loewe + + * added support for type="" and status="" in
+ (subelement of ). + +2014-11-07 02:55:57 ph3-der-loewe + + * Added support for within . + Also support merging of headers (normal mount + default mount). + +2014-11-07 01:40:28 ph3-der-loewe + + * handle empty strings in config file better. Now empty strings are + handled in: accesslog, errorlog, logdir, webroot, adminroot and + hopefully all kinds of port. + +2014-11-07 00:56:02 ph3-der-loewe + + * initial patch to allow adding user defined headers + +2014-11-06 23:55:58 ph3-der-loewe + + * coding style and typo correcion + +2014-11-06 12:02:00 dm8tbr + + * Be more verbose in case of fileserve off + +2014-11-05 10:09:07 dm8tbr + + * applied patch to update the default ciphers to be more secure + * tested this successfully against https://www.ssllabs.com/ssltest/ + +2014-11-03 19:34:10 ph3-der-loewe + + * applied patch to disable SSLv3 and SSL compression explicitly + +2014-11-02 20:19:29 dm8tbr + + * fix JSON status API problems + * Put the last item check into every filtered tag. + * This way we shouldn't run into problems of this type anymore. + * Also it should be easier to customize this way, + if someone wants to filter differently. + + +2014-10-31 09:00:45 ph3-der-loewe + + * rename ICE_LISTEN_QUEUE, ICE_RUNNING and ICE_HALTING + so they have a prefix of ICECAST_ + +2014-10-31 08:46:58 ph3-der-loewe + + * LOG_{ERROR|WARN|INFO|DEBUG}() + -> ICECAST_LOG_{ERROR|WARN|INFO|DEBUG}() + * avoid collision with LOG_INFO that is defined as part of syslog. + +2014-10-26 14:03:57 ph3-der-loewe + + * make in work if no is + given. + +2014-10-23 20:41:38 epirat + + * More detailed logging + * Add source IP adress to startup and source exit logging + * Add mountpoint to some log lines + +2014-10-18 16:25:29 ph3-der-loewe + + * fix warnings, mostly related to win*-builds + +2014-10-09 10:39:13 ph3-der-loewe + + * Replace the old logging macros with variadic argument macros. + (patch by ePirat) + +2014-07-23 16:55:57 dm8tbr + + * removed threadpool from example config + it is long gone and unused + +2014-07-23 10:20:47 dm8tbr + + * Fix autogen.sh to work properly on Mac OS + * Applying patch by ePirat + 2014-05-06 05:23:42 dm8tbr * This is Icecast 2.4.0! diff --git a/admin/vclt.xsl b/admin/vclt.xsl index 0526ba0b..2b6eab22 100644 --- a/admin/vclt.xsl +++ b/admin/vclt.xsl @@ -1,8 +1,8 @@ + 100 2 @@ -28,7 +35,7 @@ hackme - + hackme @@ -48,11 +55,12 @@ 15 http://dir.xiph.org/cgi-bin/yp-cgi - --> + --> + It affects mainly the urls generated by Icecast for playlists and yp + listings. You MUST configure it properly for YP listings to work! + --> localhost @@ -63,10 +71,34 @@ + + + + + +
+ + + + @@ -80,7 +112,7 @@ - + + + + + + - + 1 - + @pkgdatadir@ + --> + --> + access.log error.log - 3 - 10000 + 3 + 10000 @@ -30,6 +31,9 @@ access.log error.log - 3 + 3 + +
+ diff --git a/src/admin.c b/src/admin.c index cc7c68d5..3b26f790 100644 --- a/src/admin.c +++ b/src/admin.c @@ -277,21 +277,57 @@ void admin_send_response (xmlDocPtr doc, client_t *client, { xmlChar *buff = NULL; int len = 0; - unsigned int buf_len; + size_t buf_len; + ssize_t ret; + xmlDocDumpMemory(doc, &buff, &len); - buf_len = len + 256 /* just a random medium number */; + + buf_len = len + 1024; + if (buf_len < 4096) + buf_len = 4096; client_set_queue (client, NULL); client->refbuf = refbuf_new (buf_len); - /* FIXME: in this section we hope no function will ever return -1 */ - len = util_http_build_header(client->refbuf->data, buf_len, 0, + ret = util_http_build_header(client->refbuf->data, buf_len, 0, 0, 200, NULL, "text/xml", "utf-8", NULL, NULL); - len += snprintf (client->refbuf->data + len, buf_len - len, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff); + if (ret == -1) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + xmlFree(buff); + return; + } else if (buf_len < (len + ret + 64)) { + void *new_data; + buf_len = ret + len + 64; + new_data = realloc(client->refbuf->data, buf_len); + if (new_data) { + ICECAST_LOG_DEBUG("Client buffer reallocation succeeded."); + client->refbuf->data = new_data; + client->refbuf->len = buf_len; + ret = util_http_build_header(client->refbuf->data, buf_len, 0, + 0, 200, NULL, + "text/xml", "utf-8", + NULL, NULL); + if (ret == -1) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + xmlFree(buff); + return; + } + } else { + ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); + client_send_500(client, "Buffer reallocation failed."); + xmlFree(buff); + return; + } + } - client->refbuf->len = len; + /* FIXME: in this section we hope no function will ever return -1 */ + ret += snprintf (client->refbuf->data + ret, buf_len - ret, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff); + + client->refbuf->len = ret; xmlFree(buff); client->respcode = 200; fserve_add_client (client, NULL); @@ -589,6 +625,13 @@ static void html_success(client_t *client, char *message) 0, 200, NULL, "text/html", "utf-8", "", NULL); + + if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + return; + } + snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, "Admin request successful" "

%s

", message); @@ -729,6 +772,13 @@ static void command_buildm3u(client_t *client, const char *mount) "audio/x-mpegurl", NULL, NULL, NULL); + if (ret == -1 || ret >= (PER_CLIENT_REFBUF_SIZE - 512)) { /* we want at least 512 Byte left for data */ + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + return; + } + + config = config_get_config(); snprintf (client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, "Content-Disposition = attachment; filename=listen.m3u\r\n\r\n" @@ -1063,10 +1113,17 @@ static void command_list_mounts(client_t *client, int response) if (response == PLAINTEXT) { - util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, + ssize_t ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, 0, 200, NULL, "text/plain", "utf-8", "", NULL); + + if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + return; + } + client->refbuf->len = strlen (client->refbuf->data); client->respcode = 200; diff --git a/src/cfgfile.c b/src/cfgfile.c index 34867599..37211f30 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -8,8 +8,8 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). - * Copyright 2011, Thomas B. "dm8tbr" Ruecker , - * Dave 'justdave' Miller . + * Copyright 2011, Dave 'justdave' Miller . + * Copyright 2011-2014, Thomas B. "dm8tbr" Ruecker , * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft , */ @@ -59,7 +59,7 @@ #define CONFIG_DEFAULT_GROUP NULL #define CONFIG_MASTER_UPDATE_INTERVAL 120 #define CONFIG_YP_URL_TIMEOUT 10 -#define CONFIG_DEFAULT_CIPHER_LIST "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS" +#define CONFIG_DEFAULT_CIPHER_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA" #ifndef _WIN32 #define CONFIG_DEFAULT_BASE_DIR "/usr/local/icecast" diff --git a/src/client.c b/src/client.c index 22906ba2..c302cf48 100644 --- a/src/client.c +++ b/src/client.c @@ -192,6 +192,12 @@ static void client_send_error(client_t *client, int status, int plain, const cha plain ? "text/plain" : "text/html", "utf-8", plain ? message : "", NULL); + if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + return; + } + if (!plain) snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, "Error %i%i - %s\r\n", @@ -228,6 +234,21 @@ void client_send_403(client_t *client, const char *message) client_send_error(client, 403, 1, message); } +/* this function is designed to work even if client is in bad state */ +void client_send_500(client_t *client, const char *message) { + const char header[] = "HTTP/1.0 500 Internal Server Error\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n" + "500 - Internal Server Error\n---------------------------\n"; + const size_t header_len = sizeof(header) - 1; + int ret; + + ret = client_send_bytes(client, header, header_len); + + /* only send message if we have one AND if header could have transmitted completly */ + if (message && ret == header_len) + client_send_bytes(client, message, strlen(message)); + + client_destroy(client); +} /* helper function for sending the data to a client */ int client_send_bytes (client_t *client, const void *buf, unsigned len) diff --git a/src/client.h b/src/client.h index c3429676..c89e1025 100644 --- a/src/client.h +++ b/src/client.h @@ -75,6 +75,7 @@ void client_send_404(client_t *client, const char *message); void client_send_401(client_t *client); void client_send_403(client_t *client, const char *message); void client_send_400(client_t *client, const char *message); +void client_send_500(client_t *client, const char *message); int client_send_bytes (client_t *client, const void *buf, unsigned len); int client_read_bytes (client_t *client, void *buf, unsigned len); void client_set_queue (client_t *client, refbuf_t *refbuf); diff --git a/src/format.c b/src/format.c index d87b0496..74fc055a 100644 --- a/src/format.c +++ b/src/format.c @@ -299,7 +299,29 @@ static int format_prepare_headers (source_t *source, client_t *client) ptr = client->refbuf->data; client->respcode = 200; - bytes = util_http_build_header (ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source); + bytes = util_http_build_header(ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source); + if (bytes == -1) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + return -1; + } else if ((bytes + 1024) >= remaining) { /* we don't know yet how much to follow but want at least 1kB free space */ + void *new_ptr = realloc(ptr, bytes + 1024); + if (new_ptr) { + ICECAST_LOG_DEBUG("Client buffer reallocation succeeded."); + client->refbuf->data = ptr = new_ptr; + client->refbuf->len = remaining = bytes + 1024; + bytes = util_http_build_header(ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source); + if (bytes == -1 ) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + return -1; + } + } else { + ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); + client_send_500(client, "Buffer reallocation failed."); + return -1; + } + } remaining -= bytes; ptr += bytes; diff --git a/src/fserve.c b/src/fserve.c index 90ecac00..fd8d4961 100644 --- a/src/fserve.c +++ b/src/fserve.c @@ -459,6 +459,11 @@ int fserve_client_create (client_t *httpclient, const char *path) ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 200, NULL, "audio/x-mpegurl", NULL, "", NULL); + if (ret == -1 || ret >= (BUFSIZE - 512)) { /* we want at least 512 bytes left for the content of the playlist */ + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(httpclient, "Header generation failed."); + return -1; + } if (host == NULL) { config = config_get_config(); @@ -568,6 +573,11 @@ int fserve_client_create (client_t *httpclient, const char *path) 0, 206, NULL, type, NULL, NULL, NULL); + if (bytes == -1 || bytes >= (BUFSIZE - 512)) { /* we want at least 512 bytes left */ + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(httpclient, "Header generation failed."); + return -1; + } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n" @@ -594,6 +604,11 @@ int fserve_client_create (client_t *httpclient, const char *path) 0, 200, NULL, type, NULL, NULL, NULL); + if (bytes == -1 || bytes >= (BUFSIZE - 512)) { /* we want at least 512 bytes left */ + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(httpclient, "Header generation failed."); + return -1; + } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n\r\n", diff --git a/src/xslt.c b/src/xslt.c index 080c7102..5db92327 100644 --- a/src/xslt.c +++ b/src/xslt.c @@ -231,23 +231,52 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client) } if (problem == 0) { - /* the 100 is to allow for the hardcoded headers */ - unsigned int full_len = strlen (mediatype) + len + 256; + size_t full_len = strlen (mediatype) + len + 1024; refbuf_t *refbuf = refbuf_new (full_len); ssize_t ret; + int failed = 0; + + if (full_len < 4096) + full_len = 4096; if (string == NULL) string = xmlCharStrdup (""); ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL); - snprintf (refbuf->data + ret, full_len - ret, - "Content-Length: %d\r\n\r\n%s", - len, string); + if (ret == -1) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + } else { + if ( full_len < (ret + len + 64) ) { + void *new_data; + full_len = ret + len + 64; + new_data = realloc(refbuf->data, full_len); + if (new_data) { + ICECAST_LOG_DEBUG("Client buffer reallocation succeeded."); + refbuf->data = new_data; + refbuf->len = full_len; + ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL); + if (ret == -1) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + failed = 1; + } + } else { + ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); + client_send_500(client, "Buffer reallocation failed."); + failed = 1; + } + } - client->respcode = 200; - client_set_queue (client, NULL); - client->refbuf = refbuf; - refbuf->len = strlen (refbuf->data); - fserve_add_client (client, NULL); + if (!failed) { + snprintf(refbuf->data + ret, full_len - ret, "Content-Length: %d\r\n\r\n%s", len, string); + + client->respcode = 200; + client_set_queue (client, NULL); + client->refbuf = refbuf; + refbuf->len = strlen (refbuf->data); + fserve_add_client (client, NULL); + } + } xmlFree (string); } else