...
 
Commits (48)
2018-10-31 09:07 ph3-der-loewe
* Update: Changed set of default headers
* Improve compatibility with broken clients
2018-10-30 13:53 tbr
* Win32 clean up
* Removed all files related to the removed Windows UI
* Added files needed by NSIS
* Added batch file used to start icecast on Windows
* Include icecast.bat into Makefile
2018-10-28 10:42 ph3-der-loewe
* Fix: Worked around buffer overflows in URL auth's cURL interface
2018-10-27 17:42 ph3-der-loewe
* Security fix: Fixed buffer overflows in URL auth code.
* CVE-2018-18820
* Fix: Fixed a memory leak
* Fix: Removed integer overflows
2018-10-27 11:59 ph3-der-loewe
* Fix: Corrected possible bufferoverflows in format_prepare_headers()
2018-06-17 06:50 ph3-der-loewe
* Fix: Do not shut down fserve engine if not started up
* Fix: Corrected const for SSL_METHOD*.
2018-06-10 18:13 tbr
* Release preparation for Icecast 2.4.4
2018-05-26 06:15 ph3-der-loewe
* Fix: Fixed segfault in htpasswd auth if no filename is set
2018-05-08 07:24 ph3-der-loewe
* Fix: Do not report hashed user passworts in user list.
2018-05-05 07:23 Marvin Scholz
* Fix two mistakes in the default config's comments
2018-05-05 07:23 Marvin Scholz
* Add log message for succesful streamlist requests
2018-05-05 07:23 JRS
* Fix: update_from_master() for receiving HTTP/1.1
2018-05-05 07:23 tbr
* Fix: Spelling, thanks to Ukikie
2018-05-05 06:41 ph3-der-loewe
* Fix: Fixed a segfault when xsltApplyStylesheet() returns error
2018-04-21 10:30 ph3-der-loewe
* Fix: Do not segfaul on bad Opus streams
2018-04-21 10:29 ph3-der-loewe
* Fix: Corrected response and fixed TLS for 416 Request Range Not Satisfiable
responses
2018-04-21 10:13 ph3-der-loewe
* Fix: TLS for ICECAST_PROTOCOL_SHOUTCAST source clients
2018-04-16 13:42 Marvin Scholz
* Fix: global listener count could be negative under certain circumstances
Thanks a lot to Simeon Völkel (0xBD4E031CDB4043C9) for reporting
and investigating the bug.
2018-04-13 13:46 ph3-der-loewe
* Fix: Send "Content-Length: 0" on 100-continue
2018-04-13 11:18 ph3-der-loewe
* Fix: Do not send 100-continue in plain over TLS sockets
2016-12-27 11:49 ph3-der-loewe
* Fix: Added needed code to announce Opus streams as such to yp.
This fixes the situation at least for Opus. It should be checked
if the same problem applies to other codecs as well.
If so, maybe a better solution should be considered for 2.5.x.
2016-12-07 18:42 ph3-der-loewe
* Cleanup: Updated usage of global.running to be more clear
2016-12-07 18:38 ph3-der-loewe
* Fix: Avoid invalid locking in signal handlers.
2016-10-29 11:42 ph3-der-loewe
* Workaround: avoid libspeex printing warnings on Opus streams.
2016-08-15 11:51 ph3-der-loewe
* Fix: Fixed regression introduced by r19250.
This fixes the regression introduced by r19250
(461a537561580cb32dac327bae73f7e670188bd4).
The fix checks if the source client is actually
known before printing it's IP-Address.
2016-02-10 10:00 ph3-der-loewe
* Fix: do not allow unescaped strings in XML output.
2015-12-24 00:38 ph3-der-loewe
* RELEASE 2.4.3
* Windows security fix: remove trailing dots in URI
This addresses CVE-2005-0837 (sic!), which was sadly ignored after
ticket #635 got closed erroneously.
* Linux/Unix installations were never affected, Windows only release!
* Impact is low: most installations run default XSLT files and
there is nothing to be learned in such a case. Also a majority
of production Icecast servers don't run on Windows.
2015-04-08 10:07:42 dm8tbr
* RELEASE 2.4.2
* apply fix for documentation (needed by distro packaging)
2015-04-08 09:09:26 ph3-der-loewe
* Fix: Do not crash URL Auth is used with stream_auth
and no credentials are given.
This fixes a crash (NULL reference) in case URL Auth is used
and stream_auth is trigged with no credentials passed by the client.
Username and password is now set to empty strings and transmited to
the backend server this way.
See #2191 for more details and to keep track of the problem.
Closes: #2191, DEB#782120
2015-04-08 09:02:20 ph3-der-loewe
* Fix: Let util_url_escape() handle NULL parameter.
This lets util_url_escape() handle NULL passed as parameter.
In case the parameter is NULL it will also return NULL.
This patch also does some cleanup of the code such as migration
away from int and thus avoiding future failures.
2015-04-08 08:32:23 dm8tbr
* update version number to 2.4.2 in preparation for release
this will be a strict security release
2015-04-08 08:18:40 dm8tbr
* applying curl fix for win32 from master
2014-11-19 13:42:23 dm8tbr
* This is Spaaarrr^w Icecast 2.4.1!
......
This diff is collapsed.
......@@ -87,9 +87,9 @@
</div>
</xsl:for-each>
<div id="footer">
Support icecast development at <a href="http://www.icecast.org">www.icecast.org</a>
Support icecast development at <a href="https://www.icecast.org/">www.icecast.org</a>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
\ No newline at end of file
</xsl:stylesheet>
......@@ -53,9 +53,9 @@
</div>
</xsl:for-each>
<div id="footer">
Support icecast development at <a href="http://www.icecast.org">www.icecast.org</a>
Support icecast development at <a href="https://www.icecast.org/">www.icecast.org</a>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
\ No newline at end of file
</xsl:stylesheet>
......@@ -83,9 +83,9 @@
</div>
</xsl:for-each>
<div id="footer">
Support icecast development at <a href="http://www.icecast.org">www.icecast.org</a>
Support icecast development at <a href="https://www.icecast.org/">www.icecast.org</a>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
\ No newline at end of file
</xsl:stylesheet>
......@@ -31,9 +31,9 @@
</xsl:for-each>
</div>
<div id="footer">
Support icecast development at <a href="http://www.icecast.org">www.icecast.org</a>
Support icecast development at <a href="https://www.icecast.org/">www.icecast.org</a>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
\ No newline at end of file
</xsl:stylesheet>
......@@ -27,7 +27,7 @@
</div>
</xsl:for-each>
<div id="footer">
Support icecast development at <a href="http://www.icecast.org">www.icecast.org</a>
Support icecast development at <a href="https://www.icecast.org/">www.icecast.org</a>
</div>
</body>
</html>
......
......@@ -92,7 +92,7 @@
</xsl:for-each>
<!--end mount point stats-->
<div id="footer">
Support icecast development at <a href="http://www.icecast.org">www.icecast.org</a>
Support icecast development at <a href="https://www.icecast.org/">www.icecast.org</a>
</div>
</body>
</html>
......
......@@ -41,9 +41,9 @@
</div>
</xsl:for-each>
<div id="footer">
Support icecast development at <a href="http://www.icecast.org">www.icecast.org</a>
Support icecast development at <a href="https://www.icecast.org/">www.icecast.org</a>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
\ No newline at end of file
</xsl:stylesheet>
......@@ -63,7 +63,7 @@
-->
<hostname>localhost</hostname>
<!-- You may have multiple <listener> elements -->
<!-- You may have multiple <listen-socket> elements -->
<listen-socket>
<port>8000</port>
<!-- <bind-address>127.0.0.1</bind-address> -->
......@@ -97,7 +97,7 @@
<!-- Relaying
You don't need this if you only have one server.
Please refer to the config for a detailed explanation.
Please refer to the documentation for a detailed explanation.
-->
<!--<master-server>127.0.0.1</master-server>-->
<!--<master-server-port>8001</master-server-port>-->
......
AC_INIT([Icecast], [2.4.1], [icecast@xiph.org])
AC_INIT([Icecast], [2.4.4], [icecast@xiph.org])
AC_PREREQ(2.54)
AC_CONFIG_SRCDIR(src/main.c)
......@@ -156,6 +156,6 @@ AC_SUBST(KATE_LIBS)
AC_OUTPUT([Makefile conf/Makefile src/Makefile src/avl/Makefile
src/httpp/Makefile src/thread/Makefile src/log/Makefile
src/net/Makefile src/timing/Makefile doc/Makefile doc/img/Makefile
doc/assets/Makefile doc/assets/css/Makefile doc/assets/font/Makefile
doc/assets/img/Makefile web/Makefile admin/Makefile win32/Makefile
win32/res/Makefile examples/Makefile])
doc/assets/Makefile doc/assets/css/Makefile doc/assets/font/Makefile
doc/assets/img/Makefile web/Makefile admin/Makefile win32/Makefile
examples/Makefile])
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Admin Interface</h2>
<h2>Icecast 2.4.4 Docs &mdash; Admin Interface</h2>
<div class="article">
......
......@@ -2,7 +2,7 @@
AUTOMAKE_OPTIONS = foreign
docdir = $(datadir)/doc/icecast/assets/css
doc_DATA = style.css
otherdocdir = $(docdir)/assets/css
otherdoc_DATA = style.css
EXTRA_DIST = $(doc_DATA)
EXTRA_DIST = $(otherdoc_DATA)
......@@ -2,12 +2,12 @@
AUTOMAKE_OPTIONS = foreign
docdir = $(datadir)/doc/icecast/assets/font
doc_DATA = FiraMono-Bold.eot FiraMono-Regular.eot \
otherdocdir = $(docdir)/assets/font
otherdoc_DATA = FiraMono-Bold.eot FiraMono-Regular.eot \
FiraSans-Bold.eot FiraSans-BoldItalic.woff \
FiraSans-Italic.eot FiraSans-Regular.eot \
FiraMono-Bold.woff FiraMono-Regular.woff \
FiraSans-BoldItalic.eot FiraSans-Bold.woff \
FiraSans-Italic.woff FiraSans-Regular.woff
EXTRA_DIST = $(doc_DATA)
EXTRA_DIST = $(otherdoc_DATA)
......@@ -2,7 +2,7 @@
AUTOMAKE_OPTIONS = foreign
docdir = $(datadir)/doc/icecast/assets/img
doc_DATA = xiph-community.svg
otherdocdir = $(docdir)/assets/img
otherdoc_DATA = xiph-community.svg
EXTRA_DIST = $(doc_DATA)
EXTRA_DIST = $(otherdoc_DATA)
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Authentication</h2>
<h2>Icecast 2.4.4 Docs &mdash; Authentication</h2>
<div class="article">
<h3 id="listener-authentication">Listener Authentication</h3>
......
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Basic Setup</h2>
<h2>Icecast 2.4.4 Docs &mdash; Basic Setup</h2>
<div class="article">
<h3 id="basic-requirements">Basic Requirements</h3>
......
......@@ -16,8 +16,74 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Changes</h2>
<h2>Icecast 2.4.4 Docs &mdash; Changes</h2>
<div id="v2.4.4" class="article">
<h3 id="version-244">Version 2.4.4</h3>
<h4 id="fixes-4">Fixes</h4>
<ul>
<li><strong>Security fix</strong>: Buffer overflow in URL-auth <br />
<ul>
<li>A malicious client can send long HTTP headers, leading to a buffer overflow and potential remote code execution.</li>
<li>The issue has been assigned CVE-2018-18820.</li>
<li>An Icecast server (version &lt;2.4.4) is only vulnerable if a &lt;mount&gt; definition exists that enables URL authentication.</li>
<li>The problematic code exists since version 2.4.0 and was now brought to our attention by Nick Rolfe of <a href="https://lgtm.com/security">Semmle Security Research Team</a></li>
</ul>
<li>Fixed segfault in htpasswd auth, if no filename was set</li>
<li>Do not report hashed user passwords in user list</li>
<li>Fix two mistakes in the default config's comments</li>
<li>Add log message for succesful streamlist requests</li>
<li>Fix update_from_master() for receiving HTTP/1.1</li>
<li>Spelling fix, thanks to Ukikie</li>
<li>Fixed a segfault when xsltApplyStylesheet() returns error</li>
<li>Fixed segfault on bad Opus streams</li>
<li>Corrected response and fixed TLS for 416 Request Range Not Satisfiable responses</li>
</ul>
<h4 id="known-issues-3">Known issues</h4>
<ul>
<li>See <a href="#known-issues">2.4.1</a></li>
</ul>
</div>
<div id="v2.4.3" class="article">
<h3 id="version-243">Version 2.4.3</h3>
<h4 id="fixes-3">Fixes</h4>
<ul>
<li><strong>Security fix</strong>: Windows - remove trailing dots in URI. <br /> A quirk in the Windows API made it possible to request the raw stylesheet file from webroot. Only XSLT files are affected, no internal state data is available this way. <br /> This addresses CVE-2005-0837 (sic!), which was sadly ignored after the initial ticket got closed erroneously.</li>
<li><strong>Expected impact is low</strong>: most installations run with default XSLT files and there is nothing new to be learned in such a case. Also a majority of production Icecast servers don't run on Windows to start with.</li>
<li><strong>Linux/Unix installations were never affected, this is a Windows only release!</strong></li>
</li>
</ul>
<h4 id="known-issues-3">Known issues</h4>
<ul>
<li>See <a href="#known-issues">2.4.1</a></li>
</ul>
</div>
<div id="v2.4.2" class="article">
<h3 id="version-242">Version 2.4.2</h3>
<h4 id="fixes-2">Fixes</h4>
<ul>
<li><strong>Security fix</strong>: Do not crash if URL Auth is used with stream_auth.</li>
</ul>
<h4 id="known-issues-2">Known issues</h4>
<ul>
<li>See <a href="#known-issues">2.4.1</a></li>
</ul>
</div>
<div id="v2.4.1" class="article">
<h3 id="version-241">Version 2.4.1</h3>
......@@ -134,4 +200,4 @@ This allows you to define a global set of defaults for ALL mounts. This way you
</div>
</body>
</html>
\ No newline at end of file
</html>
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Config File</h2>
<h2>Icecast 2.4.4 Docs &mdash; Config File</h2>
<div class="article">
<h3 id="overview">Overview</h3>
......@@ -168,7 +168,7 @@ The value for this setting is provided by the owner of the Directory server.</dd
<span class="nt">&lt;location&gt;</span>earth<span class="nt">&lt;/location&gt;</span>
<span class="nt">&lt;admin&gt;</span>icemaster@localhost<span class="nt">&lt;/admin&gt;</span>
<span class="nt">&lt;fileserve&gt;</span>1<span class="nt">&lt;/fileserve&gt;</span>
<span class="nt">&lt;server-id&gt;</span>icecast 2.4.1<span class="nt">&lt;/server-id&gt;</span></code></pre></div>
<span class="nt">&lt;server-id&gt;</span>icecast 2.4.4<span class="nt">&lt;/server-id&gt;</span></code></pre></div>
<dl>
<dt>hostname</dt>
......
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; FAQ</h2>
<h2>Icecast 2.4.4 Docs &mdash; FAQ</h2>
<div class="article">
<h3 id="general-questions">General Questions</h3>
......
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Glossary</h2>
<h2>Icecast 2.4.4 Docs &mdash; Glossary</h2>
<div class="article">
<dl>
......
......@@ -2,7 +2,7 @@
AUTOMAKE_OPTIONS = foreign
docdir = $(datadir)/doc/icecast/img
doc_DATA = listener_auth1.png listener_auth2.png listener_auth3.png masterslave.png relay.png
otherdocdir = $(docdir)/img
otherdoc_DATA = listener_auth1.png listener_auth2.png listener_auth3.png masterslave.png relay.png
EXTRA_DIST = $(doc_DATA)
EXTRA_DIST = $(otherdoc_DATA)
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Table of Contents</h2>
<h2>Icecast 2.4.4 Docs &mdash; Table of Contents</h2>
<div class="article">
<h3 id="pages">Pages</h3>
......@@ -39,7 +39,7 @@
</div>
<div class="article">
<h3 id="icecast-241-readme">Icecast 2.4.1 Readme</h3>
<h3 id="icecast-241-readme">Icecast 2.4.4 Readme</h3>
<p>Icecast is a streaming media server which currently supports Ogg
Vorbis and MP3 audio streams. It can be used to create an Internet
radio station or a privately running jukebox and many things in
......
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Introduction</h2>
<h2>Icecast 2.4.4 Docs &mdash; Introduction</h2>
<div class="article">
<h3 id="what-is-icecast">What is Icecast?</h3>
......
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Relaying</h2>
<h2>Icecast 2.4.4 Docs &mdash; Relaying</h2>
<div class="article">
<h3 id="overview">Overview</h3>
......
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Server Statistics</h2>
<h2>Icecast 2.4.4 Docs &mdash; Server Statistics</h2>
<div class="article">
<h3 id="overview">Overview</h3>
......
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; Win32 Specifics</h2>
<h2>Icecast 2.4.4 Docs &mdash; Win32 Specifics</h2>
<div class="article">
<p>The Win32 port of Icecast 2 is a simple command line application,
......
......@@ -16,7 +16,7 @@
<div class="section">
<h2>Icecast 2.4.1 Docs &mdash; YP Directories</h2>
<h2>Icecast 2.4.4 Docs &mdash; YP Directories</h2>
<div class="article">
<h3 id="overview">Overview</h3>
......
......@@ -58,7 +58,7 @@ int main()
{
return 0;
}
]),,[curl_ok="no"])
]),,[curl_ok="no"],[curl_ok="yes"])
fi
if test "$curl_ok" = "yes"; then
AC_MSG_RESULT(yes)
......
......@@ -209,7 +209,7 @@ xmlDocPtr admin_build_sourcelist (const char *mount)
xmlDocSetRootElement(doc, xmlnode);
if (mount) {
xmlNewChild (xmlnode, NULL, XMLSTR("current_source"), XMLSTR(mount));
xmlNewTextChild (xmlnode, NULL, XMLSTR("current_source"), XMLSTR(mount));
}
node = avl_get_first(global.source_tree);
......@@ -229,17 +229,17 @@ xmlDocPtr admin_build_sourcelist (const char *mount)
srcnode = xmlNewChild(xmlnode, NULL, XMLSTR("source"), NULL);
xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(source->mount));
xmlNewChild(srcnode, NULL, XMLSTR("fallback"),
xmlNewTextChild(srcnode, NULL, XMLSTR("fallback"),
(source->fallback_mount != NULL)?
XMLSTR(source->fallback_mount):XMLSTR(""));
snprintf (buf, sizeof(buf), "%lu", source->listeners);
xmlNewChild(srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf));
xmlNewTextChild(srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf));
config = config_get_config();
mountinfo = config_find_mount (config, source->mount, MOUNT_TYPE_NORMAL);
if (mountinfo && mountinfo->auth)
{
xmlNewChild(srcnode, NULL, XMLSTR("authenticator"),
xmlNewTextChild(srcnode, NULL, XMLSTR("authenticator"),
XMLSTR(mountinfo->auth->type));
}
config_release_config();
......@@ -250,9 +250,9 @@ xmlDocPtr admin_build_sourcelist (const char *mount)
{
snprintf (buf, sizeof(buf), "%lu",
(unsigned long)(now - source->con->con_time));
xmlNewChild (srcnode, NULL, XMLSTR("Connected"), XMLSTR(buf));
xmlNewTextChild (srcnode, NULL, XMLSTR("Connected"), XMLSTR(buf));
}
xmlNewChild (srcnode, NULL, XMLSTR("content-type"),
xmlNewTextChild (srcnode, NULL, XMLSTR("content-type"),
XMLSTR(source->format->contenttype));
}
}
......@@ -681,8 +681,8 @@ static void command_move_clients(client_t *client, source_t *source,
memset(buf, '\000', sizeof(buf));
snprintf (buf, sizeof(buf), "Clients moved from %s to %s",
source->mount, dest_source);
xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(buf));
xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
xmlNewTextChild(node, NULL, XMLSTR("message"), XMLSTR(buf));
xmlNewTextChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
admin_send_response(doc, client, response,
ADMIN_XSL_RESPONSE);
......@@ -708,7 +708,7 @@ static void command_show_listeners(client_t *client, source_t *source,
memset(buf, '\000', sizeof(buf));
snprintf (buf, sizeof(buf), "%lu", source->listeners);
xmlNewChild(srcnode, NULL, XMLSTR("Listeners"), XMLSTR(buf));
xmlNewTextChild(srcnode, NULL, XMLSTR("Listeners"), XMLSTR(buf));
avl_tree_rlock(source->client_tree);
......@@ -716,22 +716,22 @@ static void command_show_listeners(client_t *client, source_t *source,
while(client_node) {
current = (client_t *)client_node->key;
listenernode = xmlNewChild(srcnode, NULL, XMLSTR("listener"), NULL);
xmlNewChild(listenernode, NULL, XMLSTR("IP"), XMLSTR(current->con->ip));
xmlNewTextChild(listenernode, NULL, XMLSTR("IP"), XMLSTR(current->con->ip));
userAgent = httpp_getvar(current->parser, "user-agent");
if (userAgent) {
xmlNewChild(listenernode, NULL, XMLSTR("UserAgent"), XMLSTR(userAgent));
xmlNewTextChild(listenernode, NULL, XMLSTR("UserAgent"), XMLSTR(userAgent));
}
else {
xmlNewChild(listenernode, NULL, XMLSTR("UserAgent"), XMLSTR("Unknown"));
xmlNewTextChild(listenernode, NULL, XMLSTR("UserAgent"), XMLSTR("Unknown"));
}
memset(buf, '\000', sizeof(buf));
snprintf(buf, sizeof(buf), "%lu", (unsigned long)(now - current->con->con_time));
xmlNewChild(listenernode, NULL, XMLSTR("Connected"), XMLSTR(buf));
xmlNewTextChild(listenernode, NULL, XMLSTR("Connected"), XMLSTR(buf));
memset(buf, '\000', sizeof(buf));
snprintf(buf, sizeof(buf)-1, "%lu", current->con->id);
xmlNewChild(listenernode, NULL, XMLSTR("ID"), XMLSTR(buf));
xmlNewTextChild(listenernode, NULL, XMLSTR("ID"), XMLSTR(buf));
if (current->username) {
xmlNewChild(listenernode, NULL, XMLSTR("username"), XMLSTR(current->username));
xmlNewTextChild(listenernode, NULL, XMLSTR("username"), XMLSTR(current->username));
}
client_node = avl_get_next(client_node);
}
......@@ -851,7 +851,7 @@ static void command_manageauth(client_t *client, source_t *source,
if (message) {
msgnode = xmlNewChild(node, NULL, XMLSTR("iceresponse"), NULL);
xmlNewChild(msgnode, NULL, XMLSTR("message"), XMLSTR(message));
xmlNewTextChild(msgnode, NULL, XMLSTR("message"), XMLSTR(message));
}
xmlDocSetRootElement(doc, node);
......@@ -880,8 +880,8 @@ static void command_kill_source(client_t *client, source_t *source,
doc = xmlNewDoc (XMLSTR("1.0"));
node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR("Source Removed"));
xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
xmlNewTextChild(node, NULL, XMLSTR("message"), XMLSTR("Source Removed"));
xmlNewTextChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
xmlDocSetRootElement(doc, node);
source->running = 0;
......@@ -921,14 +921,14 @@ static void command_kill_client(client_t *client, source_t *source,
listener->con->error = 1;
memset(buf, '\000', sizeof(buf));
snprintf(buf, sizeof(buf)-1, "Client %d removed", id);
xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(buf));
xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
xmlNewTextChild(node, NULL, XMLSTR("message"), XMLSTR(buf));
xmlNewTextChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
}
else {
memset(buf, '\000', sizeof(buf));
snprintf(buf, sizeof(buf)-1, "Client %d not found", id);
xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(buf));
xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("0"));
xmlNewTextChild(node, NULL, XMLSTR("message"), XMLSTR(buf));
xmlNewTextChild(node, NULL, XMLSTR("return"), XMLSTR("0"));
}
admin_send_response(doc, client, response,
ADMIN_XSL_RESPONSE);
......@@ -976,8 +976,8 @@ static void command_metadata(client_t *client, source_t *source,
if (strcmp (action, "updinfo") != 0)
{
xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR("No such action"));
xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("0"));
xmlNewTextChild(node, NULL, XMLSTR("message"), XMLSTR("No such action"));
xmlNewTextChild(node, NULL, XMLSTR("return"), XMLSTR("0"));
admin_send_response(doc, client, response,
ADMIN_XSL_RESPONSE);
xmlFreeDoc(doc);
......@@ -1011,17 +1011,17 @@ static void command_metadata(client_t *client, source_t *source,
}
else
{
xmlNewChild(node, NULL, XMLSTR("message"),
xmlNewTextChild(node, NULL, XMLSTR("message"),
XMLSTR("Mountpoint will not accept URL updates"));
xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
xmlNewTextChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
admin_send_response(doc, client, response,
ADMIN_XSL_RESPONSE);
xmlFreeDoc(doc);
return;
}
xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR("Metadata update successful"));
xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
xmlNewTextChild(node, NULL, XMLSTR("message"), XMLSTR("Metadata update successful"));
xmlNewTextChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
admin_send_response(doc, client, response,
ADMIN_XSL_RESPONSE);
xmlFreeDoc(doc);
......
......@@ -194,6 +194,11 @@ static auth_result htpasswd_auth (auth_client *auth_user)
}
htpasswd_recheckfile (htpasswd);
if (htpasswd->users == NULL) {
ICECAST_LOG_ERROR("No user list.");
return AUTH_FAILED;
}
thread_rwlock_rlock (&htpasswd->file_rwlock);
entry.name = client->username;
if (avl_get_by_key (htpasswd->users, &entry, &result) == 0)
......@@ -262,8 +267,18 @@ static auth_result htpasswd_adduser (auth_t *auth, const char *username, const c
htpasswd_user entry;
void *result;
if (state->filename == NULL) {
ICECAST_LOG_ERROR("No filename given in options for authenticator.");
return AUTH_FAILED;
}
htpasswd_recheckfile (state);
if (state->filename == NULL) {
ICECAST_LOG_ERROR("No user list.");
return AUTH_FAILED;
}
thread_rwlock_wlock (&state->file_rwlock);
entry.name = (char*)username;
......@@ -308,6 +323,17 @@ static auth_result htpasswd_deleteuser(auth_t *auth, const char *username)
struct stat file_info;
state = auth->state;
if (state->filename == NULL) {
ICECAST_LOG_ERROR("No filename given in options for authenticator.");
return AUTH_FAILED;
}
if (state->users == NULL) {
ICECAST_LOG_ERROR("No user list.");
return AUTH_FAILED;
}
thread_rwlock_wlock (&state->file_rwlock);
passwdfile = fopen(state->filename, "rb");
......@@ -392,16 +418,25 @@ static auth_result htpasswd_userlist(auth_t *auth, xmlNodePtr srcnode)
state = auth->state;
if (state->filename == NULL) {
ICECAST_LOG_ERROR("No filename given in options for authenticator.");
return AUTH_FAILED;
}
htpasswd_recheckfile (state);
if (state->users == NULL) {
ICECAST_LOG_ERROR("No user list.");
return AUTH_FAILED;
}
thread_rwlock_rlock (&state->file_rwlock);
node = avl_get_first (state->users);
while (node)
{
htpasswd_user *user = (htpasswd_user *)node->key;
newnode = xmlNewChild (srcnode, NULL, XMLSTR("User"), NULL);
xmlNewChild(newnode, NULL, XMLSTR("username"), XMLSTR(user->name));
xmlNewChild(newnode, NULL, XMLSTR("password"), XMLSTR(user->pass));
xmlNewTextChild(newnode, NULL, XMLSTR("username"), XMLSTR(user->name));
node = avl_get_next (node);
}
thread_rwlock_unlock (&state->file_rwlock);
......
......@@ -141,40 +141,58 @@ static int my_getpass(void *client, char *prompt, char *buffer, int buflen)
static size_t handle_returned_header (void *ptr, size_t size, size_t nmemb, void *stream)
{
auth_client *auth_user = stream;
unsigned bytes = size * nmemb;
size_t len = size * nmemb;
client_t *client = auth_user->client;
if (client)
{
if (client) {
auth_t *auth = client->auth;
auth_url *url = auth->state;
if (strncasecmp (ptr, url->auth_header, url->auth_header_len) == 0)
if (url->auth_header && len >= url->auth_header_len && strncasecmp(ptr, url->auth_header, url->auth_header_len) == 0)
client->authenticated = 1;
if (strncasecmp (ptr, url->timelimit_header, url->timelimit_header_len) == 0)
{
if (url->timelimit_header && len > url->timelimit_header_len && strncasecmp(ptr, url->timelimit_header, url->timelimit_header_len) == 0) {
const char *input = ptr;
unsigned int limit = 0;
sscanf ((char *)ptr+url->timelimit_header_len, "%u\r\n", &limit);
client->con->discon_time = time(NULL) + limit;
if (len >= 2 && input[len - 2] == '\r' && input[len - 1] == '\n') {
input += url->timelimit_header_len;
if (sscanf(input, "%u\r\n", &limit) == 1) {
client->con->discon_time = time(NULL) + limit;
} else {
ICECAST_LOG_ERROR("Auth backend returned invalid timeline header: Can not parse limit");
}
} else {
ICECAST_LOG_ERROR("Auth backend returned invalid timelimit header.");
}
}
if (strncasecmp (ptr, "icecast-auth-message: ", 22) == 0)
{
char *eol;
snprintf (url->errormsg, sizeof (url->errormsg), "%s", (char*)ptr+22);
eol = strchr (url->errormsg, '\r');
if (eol == NULL)
eol = strchr (url->errormsg, '\n');
if (eol)
*eol = '\0';
if (len > 24 && strncasecmp(ptr, "icecast-auth-message: ", 22) == 0) {
const char *input = ptr;
size_t copy_len = len - 24 + 1; /* length of string plus \0-termination */
if (copy_len > sizeof(url->errormsg)) {
copy_len = sizeof(url->errormsg);
}
if (len >= 2 && input[len - 2] == '\r' && input[len - 1] == '\n') {
input += 22;
memcpy(url->errormsg, input, copy_len);
url->errormsg[copy_len-1] = 0;
} else {
ICECAST_LOG_ERROR("Auth backend returned invalid message header.");
}
}
}
return (int)bytes;
return len;
}
/* capture returned data, but don't do anything with it */
static size_t handle_returned_data (void *ptr, size_t size, size_t nmemb, void *stream)
{
return (int)(size*nmemb);
return size * nmemb;
}
......@@ -191,6 +209,7 @@ static auth_result url_remove_listener (auth_client *auth_user)
char *userpwd = NULL, post [4096];
const char *agent;
char *user_agent, *ipaddr;
int ret;
if (url->removeurl == NULL)
return AUTH_OK;
......@@ -223,11 +242,11 @@ static auth_result url_remove_listener (auth_client *auth_user)
mount = util_url_escape (mountreq);
ipaddr = util_url_escape (client->con->ip);
snprintf (post, sizeof (post),
"action=listener_remove&server=%s&port=%d&client=%lu&mount=%s"
"&user=%s&pass=%s&duration=%lu&ip=%s&agent=%s",
server, port, client->con->id, mount, username,
password, (long unsigned)duration, ipaddr, user_agent);
ret = snprintf(post, sizeof(post),
"action=listener_remove&server=%s&port=%d&client=%lu&mount=%s"
"&user=%s&pass=%s&duration=%lu&ip=%s&agent=%s",
server, port, client->con->id, mount, username,
password, (long unsigned)duration, ipaddr, user_agent);
free (server);
free (mount);
free (username);
......@@ -235,6 +254,11 @@ static auth_result url_remove_listener (auth_client *auth_user)
free (ipaddr);
free (user_agent);
if (ret <= 0 || ret >= sizeof(post)) {
ICECAST_LOG_ERROR("POST body too long for buffer on mount point \"%H\" client %p.", auth_user->mount, client);
return AUTH_FAILED;
}
if (strchr (url->removeurl, '@') == NULL)
{
if (url->userpwd)
......@@ -331,6 +355,11 @@ static auth_result url_add_listener (auth_client *auth_user)
free (password);
free (ipaddr);
if (post_offset <= 0 || post_offset >= sizeof(post)) {
ICECAST_LOG_ERROR("POST body too long for buffer on mount point \"%H\" client %p.", auth_user->mount, client);
return AUTH_FAILED;
}
pass_headers = NULL;
if (url->pass_headers)
pass_headers = strdup (url->pass_headers);
......@@ -349,15 +378,26 @@ static auth_result url_add_listener (auth_client *auth_user)
header_val = httpp_getvar (client->parser, cur_header);
if (header_val)
{
size_t left = sizeof(post) - post_offset;
int ret;
header_valesc = util_url_escape (header_val);
post_offset += snprintf (post+post_offset, sizeof (post)-post_offset, "&%s%s=%s",
ret = snprintf (post+post_offset, left, "&%s%s=%s",
url->prefix_headers ? url->prefix_headers : "",
cur_header, header_valesc);
free (header_valesc);
if (ret <= 0 || ret >= left) {
ICECAST_LOG_ERROR("POST body too long for buffer on mount point \"%H\" client %p.", auth_user->mount, client);
free(pass_headers);
return AUTH_FAILED;
} else {
post_offset += ret;
}
}
cur_header = next_header;
}
free(pass_headers);
}
if (strchr (url->addurl, '@') == NULL)
......@@ -418,6 +458,7 @@ static void url_stream_start (auth_client *auth_user)
char *stream_start_url;
int port;
char post [4096];
int ret;
if (url->stream_start == NULL)
{
......@@ -433,11 +474,17 @@ static void url_stream_start (auth_client *auth_user)
config_release_config ();
mount = util_url_escape (auth_user->mount);
snprintf (post, sizeof (post),
"action=mount_add&mount=%s&server=%s&port=%d", mount, server, port);
ret = snprintf(post, sizeof(post), "action=mount_add&mount=%s&server=%s&port=%d", mount, server, port);
free (server);
free (mount);
if (ret <= 0 || ret >= sizeof(post)) {
ICECAST_LOG_ERROR("POST body too long for buffer on mount point \"%H\".", auth_user->mount);
auth_release(auth);
free(stream_start_url);
return;
}
if (strchr (url->stream_start, '@') == NULL)
{
if (url->userpwd)
......@@ -470,6 +517,7 @@ static void url_stream_end (auth_client *auth_user)
char *stream_end_url;
int port;
char post [4096];
int ret;
if (url->stream_end == NULL)
{
......@@ -485,11 +533,17 @@ static void url_stream_end (auth_client *auth_user)
config_release_config ();
mount = util_url_escape (auth_user->mount);
snprintf (post, sizeof (post),
"action=mount_remove&mount=%s&server=%s&port=%d", mount, server, port);
ret = snprintf(post, sizeof(post), "action=mount_remove&mount=%s&server=%s&port=%d", mount, server, port);
free (server);
free (mount);
if (ret <= 0 || ret >= sizeof(post)) {
ICECAST_LOG_ERROR("POST body too long for buffer on mount point \"%H\".", auth_user->mount);
auth_release(auth);
free(stream_end_url);
return;
}
if (strchr (url->stream_end, '@') == NULL)
{
if (url->userpwd)
......@@ -519,6 +573,7 @@ static void url_stream_auth (auth_client *auth_user)
auth_url *url = client->auth->state;
char *mount, *host, *user, *pass, *ipaddr, *admin="";
char post [4096];
int ret;
if (strchr (url->stream_auth, '@') == NULL)
{
......@@ -539,13 +594,23 @@ static void url_stream_auth (auth_client *auth_user)
host = util_url_escape (config->hostname);
port = config->port;
config_release_config ();
user = util_url_escape (client->username);
pass = util_url_escape (client->password);
ipaddr = util_url_escape (client->con->ip);
snprintf (post, sizeof (post),
"action=stream_auth&mount=%s&ip=%s&server=%s&port=%d&user=%s&pass=%s%s",
mount, ipaddr, host, port, user, pass, admin);
if (client->username) {
user = util_url_escape(client->username);
} else {
user = strdup("");
}
if (client->password) {
pass = util_url_escape(client->password);
} else {
pass = strdup("");
}
ret = snprintf(post, sizeof(post),
"action=stream_auth&mount=%s&ip=%s&server=%s&port=%d&user=%s&pass=%s%s",
mount, ipaddr, host, port, user, pass, admin);
free (ipaddr);
free (user);
free (pass);
......@@ -553,6 +618,12 @@ static void url_stream_auth (auth_client *auth_user)
free (host);
client->authenticated = 0;
if (ret <= 0 || ret >= sizeof(post)) {
ICECAST_LOG_ERROR("POST body too long for buffer on mount point \"%H\" client %p.", auth_user->mount, client);
return;
}
if (curl_easy_perform (url->handle))
ICECAST_LOG_WARN("auth to server %s failed with %s", url->stream_auth, url->errormsg);
}
......
......@@ -183,7 +183,7 @@ int client_read_bytes (client_t *client, void *buf, unsigned len)
return bytes;
}
static void client_send_error(client_t *client, int status, int plain, const char *message)
void client_send_error(client_t *client, int status, int plain, const char *message)
{
ssize_t ret;
......@@ -211,7 +211,9 @@ static void client_send_error(client_t *client, int status, int plain, const cha
void client_send_100(client_t *client)
{
/* On demand inject a HTTP/1.1 100 Continue to make sure clients are happy */
sock_write (client->con->sock, "HTTP/1.1 100 Continue\r\n\r\n");
static const char str[] = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n";
const size_t len = strlen(str);
client_send_bytes(client, str, len);
}
void client_send_400(client_t *client, const char *message)
......
......@@ -80,5 +80,6 @@ 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);
int client_check_source_auth (client_t *client, const char *mount);
void client_send_error(client_t *client, int status, int plain, const char *message);
#endif /* __CLIENT_H__ */
......@@ -194,7 +194,11 @@ static unsigned long _next_connection_id(void)
#ifdef HAVE_OPENSSL
static void get_ssl_certificate (ice_config_t *config)
{
#if OPENSSL_VERSION_NUMBER < 0x1000114fL
SSL_METHOD *method;
#else
const SSL_METHOD *method;
#endif
long ssl_opts;
ssl_ok = 0;
......@@ -1249,7 +1253,7 @@ static void _handle_shoutcast_compatible (client_queue_t *node)
client->respcode = 200;
/* send this non-blocking but if there is only a partial write
* then leave to header timeout */
sock_write (client->con->sock, "OK2\r\nicy-caps:11\r\n\r\n");
client_send_bytes(client, "OK2\r\nicy-caps:11\r\n\r\n", 20); /* TODO: Replace Magic Number! */
node->offset -= (headers - client->refbuf->data);
memmove (client->refbuf->data, headers, node->offset+1);
node->shoutcast = 2;
......
......@@ -300,7 +300,7 @@ static int format_prepare_headers (source_t *source, client_t *client)
client->respcode = 200;
bytes = util_http_build_header(ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source);
if (bytes == -1) {
if (bytes <= 0) {
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
client_send_500(client, "Header generation failed.");
return -1;
......@@ -311,7 +311,7 @@ static int format_prepare_headers (source_t *source, client_t *client)
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 ) {
if (bytes <= 0 || bytes >= remaining) {
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
client_send_500(client, "Header generation failed.");
return -1;
......@@ -392,6 +392,13 @@ static int format_prepare_headers (source_t *source, client_t *client)
}
}
if (bytes < 0 || bytes >= remaining) {
avl_tree_unlock(source->parser->vars);
ICECAST_LOG_ERROR("Can not allocate headers for client %p", client);
client_send_500(client, "Header generation failed.");
return -1;
}
remaining -= bytes;
ptr += bytes;
if (next)
......@@ -400,13 +407,22 @@ static int format_prepare_headers (source_t *source, client_t *client)
avl_tree_unlock(source->parser->vars);
bytes = snprintf (ptr, remaining, "\r\n");
if (bytes < 0 || bytes >= remaining) {
ICECAST_LOG_ERROR("Can not allocate headers for client %p", client);
client_send_500(client, "Header generation failed.");
return -1;
}
remaining -= bytes;
ptr += bytes;
client->refbuf->len -= remaining;
if (source->format->create_client_data)
if (source->format->create_client_data (source, client) < 0)
if (source->format->create_client_data (source, client) < 0) {
ICECAST_LOG_ERROR("Client format header generation failed. "
"(Likely not enough or wrong source data) Dropping client.");
client->respcode = 500;
return -1;
}
return 0;
}
......
......@@ -72,7 +72,7 @@ ogg_codec_t *initial_opus_page (format_plugin_t *plugin, ogg_page *page)
ogg_stream_packetout (&codec->os, &packet);
ICECAST_LOG_DEBUG("checking for opus codec");
if (strncmp((char *)packet.packet, "OpusHead", 8) != 0)
if (packet.bytes < 8 || strncmp((char *)packet.packet, "OpusHead", 8) != 0)
{
ogg_stream_clear (&codec->os);
free (codec);
......@@ -82,6 +82,8 @@ ogg_codec_t *initial_opus_page (format_plugin_t *plugin, ogg_page *page)
codec->process_page = process_opus_page;
codec->codec_free = opus_codec_free;
codec->headers = 1;
codec->name = "Opus";
ogg_info->log_metadata = 1;
format_ogg_attach_header (ogg_info, page);
return codec;
}
......
......@@ -73,6 +73,19 @@ ogg_codec_t *initial_speex_page (format_plugin_t *plugin, ogg_page *page)
ogg_stream_packetout (&codec->os, &packet);
/* Check for te first packet to be at least of the minimal size for a Speex header.
* The header size is 80 bytes as per specs. You can find the specs here:
* https://speex.org/docs/manual/speex-manual/node8.html#SECTION00830000000000000000
*
* speex_packet_to_header() will also check the header size for us. However
* that function generates noise on stderr in case the header is too short.
* This is dangerous as we may have closed stderr already and the handle may be use
* again for something else.
*/
if (packet.bytes < 80) {
return NULL;
}
ICECAST_LOG_DEBUG("checking for speex codec");
header = speex_packet_to_header ((char*)packet.packet, packet.bytes);
if (header == NULL)
......
......@@ -69,6 +69,8 @@
#define BUFSIZE 4096
static volatile int __inited = 0;
static fserve_t *active_list = NULL;
static fserve_t *pending_list = NULL;
......@@ -107,12 +109,17 @@ void fserve_initialize(void)
fserve_recheck_mime_types (config);
config_release_config();
__inited = 1;
stats_event (NULL, "file_connections", "0");
ICECAST_LOG_INFO("file serving started");
}
void fserve_shutdown(void)
{
if (!__inited)
return;
thread_spin_lock (&pending_lock);
run_fserv = 0;
while (pending_list)
......@@ -625,10 +632,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
fail:
fclose (file);
httpclient->respcode = 416;
sock_write (httpclient->con->sock,
"HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n");
client_destroy (httpclient);
client_send_error(httpclient, 416, 1, "Request Range Not Satisfiable\r\n");
return -1;
}
......
......@@ -38,7 +38,7 @@ void global_initialize(void)
global.server_sockets = 0;
global.relays = NULL;
global.master_relays = NULL;
global.running = 0;
global.running = ICECAST_BOOTING;
global.clients = 0;
global.sources = 0;
global.source_tree = avl_tree_new(source_compare_sources, NULL);
......
......@@ -15,8 +15,9 @@
#define ICECAST_LISTEN_QUEUE 5
#define ICECAST_RUNNING 1
#define ICECAST_HALTING 2
#define ICECAST_BOOTING 0 /* Still booting */
#define ICECAST_RUNNING 1 /* Up and running */
#define ICECAST_HALTING 2 /* Shutting down */
#define ICECAST_VERSION_STRING "Icecast " PACKAGE_VERSION
......
......@@ -343,6 +343,8 @@ static void _server_proc(void)
}
connection_accept_loop();
ICECAST_LOG_INFO("Caught halt request, shutting down...");
connection_setup_sockets (NULL);
}
......
......@@ -55,11 +55,7 @@ void _sig_ignore(int signo)
void _sig_hup(int signo)
{
ICECAST_LOG_INFO("Caught signal %d, scheduling config re-read...", signo);
global_lock();
global . schedule_config_reread = 1;
global_unlock();
/* some OSes require us to reattach the signal handler */
signal(SIGHUP, _sig_hup);
......@@ -67,8 +63,6 @@ void _sig_hup(int signo)
void _sig_die(int signo)
{
ICECAST_LOG_INFO("Caught signal %d, shutting down...", signo);
/* inform the server to start shutting down */