[xiph-commits] r15621 - icecast/trunk/icecast/src
karl at svn.xiph.org
karl at svn.xiph.org
Tue Jan 13 17:18:23 PST 2009
Author: karl
Date: 2009-01-13 17:18:22 -0800 (Tue, 13 Jan 2009)
New Revision: 15621
Modified:
icecast/trunk/icecast/src/admin.c
icecast/trunk/icecast/src/auth.c
icecast/trunk/icecast/src/auth.h
icecast/trunk/icecast/src/auth_url.c
icecast/trunk/icecast/src/client.c
icecast/trunk/icecast/src/client.h
icecast/trunk/icecast/src/connection.c
icecast/trunk/icecast/src/connection.h
icecast/trunk/icecast/src/source.h
Log:
Allow source client authentication via auth handler. Here the URL handler can
issue requests (using ithe stream_auth option) to allow external engines to
determine whether a client can stream or not. Admin requests using source auth
are able to use this mechanism however source clients using the icy protocol
cannot yet.
Modified: icecast/trunk/icecast/src/admin.c
===================================================================
--- icecast/trunk/icecast/src/admin.c 2009-01-12 21:36:29 UTC (rev 15620)
+++ icecast/trunk/icecast/src/admin.c 2009-01-14 01:18:22 UTC (rev 15621)
@@ -371,17 +371,22 @@
return;
}
/* This is a mount request, handle it as such */
- if (!connection_check_admin_pass(client->parser))
+ if (client->authenticated == 0 && !connection_check_admin_pass(client->parser))
{
- if (!connection_check_source_pass(client->parser, mount))
+ switch (client_check_source_auth (client, mount))
{
- INFO1("Bad or missing password on mount modification admin "
- "request (command: %s)", command_string);
- client_send_401(client);
- return;
+ case 0:
+ break;
+ default:
+ INFO1("Bad or missing password on mount modification admin "
+ "request (command: %s)", command_string);
+ client_send_401(client);
+ /* fall through */
+ case 1:
+ return;
}
}
-
+
avl_tree_rlock(global.source_tree);
source = source_find_mount_raw(mount);
Modified: icecast/trunk/icecast/src/auth.c
===================================================================
--- icecast/trunk/icecast/src/auth.c 2009-01-12 21:36:29 UTC (rev 15620)
+++ icecast/trunk/icecast/src/auth.c 2009-01-14 01:18:22 UTC (rev 15621)
@@ -32,12 +32,13 @@
#include "stats.h"
#include "httpp/httpp.h"
#include "fserve.h"
+#include "admin.h"
#include "logging.h"
#define CATMODULE "auth"
-static mutex_t auth_lock;
+static void auth_postprocess_source (auth_client *auth_user);
static auth_client *auth_client_setup (const char *mount, client_t *client)
@@ -236,6 +237,25 @@
}
+/* Called from auth thread to process any request for source client
+ * authentication. Only applies to source clients, not relays.
+ */
+static void stream_auth_callback (auth_t *auth, auth_client *auth_user)
+{
+ client_t *client = auth_user->client;
+
+ if (auth->stream_auth)
+ auth->stream_auth (auth_user);
+
+ auth_release (auth);
+ client->auth = NULL;
+ if (client->authenticated)
+ auth_postprocess_source (auth_user);
+ else
+ WARN1 ("Failed auth for source \"%s\"", auth_user->mount);
+}
+
+
/* Callback from auth thread to handle a stream start event, this applies
* to both source clients and relays.
*/
@@ -478,6 +498,30 @@
}
+/* Decide whether we need to start a source or just process a source
+ * admin request.
+ */
+void auth_postprocess_source (auth_client *auth_user)
+{
+ client_t *client = auth_user->client;
+ const char *mount = auth_user->mount;
+ const char *req = httpp_getvar (client->parser, HTTPP_VAR_URI);
+
+ auth_user->client = NULL;
+ client->authenticated = 1;
+ if (strcmp (req, "/admin.cgi") == 0 || strncmp ("/admin/metadata", req, 15) == 0)
+ {
+ DEBUG2 ("metadata request (%s, %s)", req, mount);
+ admin_handle_request (client, "/admin/metadata");
+ }
+ else
+ {
+ DEBUG1 ("on mountpoint %s", mount);
+ source_startup (client, mount, 0);
+ }
+}
+
+
/* Add a listener. Check for any mount information that states any
* authentication to be used.
*/
@@ -654,6 +698,25 @@
}
+/* Called when a source client connects and requires authentication via the
+ * authenticator. This is called for both source clients and admin requests
+ * that work on a specified mountpoint.
+ */
+int auth_stream_authenticate (client_t *client, const char *mount, mount_proxy *mountinfo)
+{
+ if (mountinfo && mountinfo->auth && mountinfo->auth->stream_auth)
+ {
+ auth_client *auth_user = auth_client_setup (mount, client);
+
+ auth_user->process = stream_auth_callback;
+ INFO1 ("request source auth for \"%s\"", mount);
+ queue_auth_client (auth_user, mountinfo);
+ return 1;
+ }
+ return 0;
+}
+
+
/* called when the stream starts, so that authentication engine can do any
* cleanup/initialisation.
*/
@@ -696,12 +759,10 @@
void auth_initialise (void)
{
- thread_mutex_create (&auth_lock);
}
void auth_shutdown (void)
{
- thread_mutex_destroy (&auth_lock);
INFO0 ("Auth shutdown");
}
Modified: icecast/trunk/icecast/src/auth.h
===================================================================
--- icecast/trunk/icecast/src/auth.h 2009-01-12 21:36:29 UTC (rev 15620)
+++ icecast/trunk/icecast/src/auth.h 2009-01-14 01:18:22 UTC (rev 15621)
@@ -55,6 +55,9 @@
auth_result (*authenticate)(auth_client *aclient);
auth_result (*release_listener)(auth_client *auth_user);
+ /* auth handler for authenicating a connecting source client */
+ void (*stream_auth)(auth_client *auth_user);
+
/* auth handler for source startup, no client passed as it may disappear */
void (*stream_start)(auth_client *auth_user);
@@ -92,12 +95,15 @@
auth_t *auth_get_authenticator (xmlNodePtr node);
void auth_release (auth_t *authenticator);
-/* call to send a url request when source starts */
+/* call to trigger an event when a stream starts */
void auth_stream_start (struct _mount_proxy *mountinfo, const char *mount);
-/* call to send a url request when source ends */
+/* call to trigger an event when a stream ends */
void auth_stream_end (struct _mount_proxy *mountinfo, const char *mount);
+/* call to trigger an event to authenticate a source client */
+int auth_stream_authenticate (client_t *client, const char *mount, struct _mount_proxy *mountinfo);
+
/* called from auth thread, after the client has successfully authenticated
* and requires adding to source or fserve. */
int auth_postprocess_listener (auth_client *auth_user);
Modified: icecast/trunk/icecast/src/auth_url.c
===================================================================
--- icecast/trunk/icecast/src/auth_url.c 2009-01-12 21:36:29 UTC (rev 15620)
+++ icecast/trunk/icecast/src/auth_url.c 2009-01-14 01:18:22 UTC (rev 15621)
@@ -46,6 +46,15 @@
*
* action=mount_add&mount=/live&server=myserver.com&port=8000
* action=mount_remove&mount=/live&server=myserver.com&port=8000
+ *
+ * On source client connection, a request can be made to trigger a URL request
+ * to verify the details externally. Post info is
+ *
+ * action=stream_auth&mount=/stream&ip=IP&server=SERVER&port=8000&user=fred&pass=pass
+ *
+ * As admin requests can come in for a stream (eg metadata update) these requests
+ * can be issued while stream is active. For these &admin=1 is added to the POST
+ * details.
*/
#ifdef HAVE_CONFIG_H
@@ -80,6 +89,7 @@
char *removeurl;
char *stream_start;
char *stream_end;
+ char *stream_auth;
char *username;
char *password;
char *auth_header;
@@ -447,7 +457,53 @@
return;
}
+static void url_stream_auth (auth_client *auth_user)
+{
+ ice_config_t *config;
+ int port;
+ client_t *client = auth_user->client;
+ auth_url *url = client->auth->state;
+ char *mount, *host, *user, *pass, *ipaddr, *admin="";
+ char post [4096];
+ if (strchr (url->stream_auth, '@') == NULL)
+ {
+ if (url->userpwd)
+ curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd);
+ else
+ curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
+ }
+ else
+ curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
+ curl_easy_setopt (url->handle, CURLOPT_URL, url->stream_auth);
+ curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post);
+ curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user);
+ if (strcmp (auth_user->mount, httpp_getvar (client->parser, HTTPP_VAR_URI)) != 0)
+ admin = "&admin=1";
+ mount = util_url_escape (auth_user->mount);
+ config = config_get_config ();
+ 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);
+ free (ipaddr);
+ free (user);
+ free (pass);
+ free (mount);
+ free (host);
+
+ client->authenticated = 0;
+ if (curl_easy_perform (url->handle))
+ WARN2 ("auth to server %s failed with %s", url->stream_auth, url->errormsg);
+}
+
+
static auth_result auth_url_adduser(auth_t *auth, const char *username, const char *password)
{
return AUTH_FAILED;
@@ -516,6 +572,12 @@
free (url_info->stream_end);
url_info->stream_end = strdup (options->value);
}
+ if(!strcmp(options->name, "stream_auth"))
+ {
+ authenticator->stream_auth = url_stream_auth;
+ free (url_info->stream_auth);
+ url_info->stream_auth = strdup (options->value);
+ }
if(!strcmp(options->name, "auth_header"))
{
free (url_info->auth_header);
Modified: icecast/trunk/icecast/src/client.c
===================================================================
--- icecast/trunk/icecast/src/client.c 2009-01-12 21:36:29 UTC (rev 15620)
+++ icecast/trunk/icecast/src/client.c 2009-01-14 01:18:22 UTC (rev 15621)
@@ -122,7 +122,37 @@
free(client);
}
+/* return -1 for failed, 0 for authenticated, 1 for pending
+ */
+int client_check_source_auth (client_t *client, const char *mount)
+{
+ ice_config_t *config = config_get_config();
+ char *pass = config->source_password;
+ char *user = "source";
+ int ret = -1;
+ mount_proxy *mountinfo = config_find_mount (config, mount);
+ do
+ {
+ if (mountinfo)
+ {
+ ret = 1;
+ if (auth_stream_authenticate (client, mount, mountinfo) > 0)
+ break;
+ ret = -1;
+ if (mountinfo->password)
+ pass = mountinfo->password;
+ if (mountinfo->username)
+ user = mountinfo->username;
+ }
+ if (connection_check_pass (client->parser, user, pass) > 0)
+ ret = 0;
+ } while (0);
+ config_release_config();
+ return ret;
+}
+
+
/* helper function for reading data from a client */
int client_read_bytes (client_t *client, void *buf, unsigned len)
{
Modified: icecast/trunk/icecast/src/client.h
===================================================================
--- icecast/trunk/icecast/src/client.h 2009-01-12 21:36:29 UTC (rev 15620)
+++ icecast/trunk/icecast/src/client.h 2009-01-14 01:18:22 UTC (rev 15621)
@@ -77,5 +77,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);
#endif /* __CLIENT_H__ */
Modified: icecast/trunk/icecast/src/connection.c
===================================================================
--- icecast/trunk/icecast/src/connection.c 2009-01-12 21:36:29 UTC (rev 15620)
+++ icecast/trunk/icecast/src/connection.c 2009-01-14 01:18:22 UTC (rev 15621)
@@ -968,29 +968,17 @@
return ret;
}
-int connection_check_source_pass(http_parser_t *parser, const char *mount)
+
+/* return 0 for failed, 1 for ok
+ */
+int connection_check_pass (http_parser_t *parser, const char *user, const char *pass)
{
- ice_config_t *config = config_get_config();
- char *pass = config->source_password;
- char *user = "source";
int ret;
- int ice_login = config->ice_login;
const char *protocol;
- mount_proxy *mountinfo = config_find_mount (config, mount);
-
- if (mountinfo)
- {
- if (mountinfo->password)
- pass = mountinfo->password;
- if (mountinfo->username)
- user = mountinfo->username;
- }
-
if(!pass) {
WARN0("No source password set, rejecting source");
- config_release_config();
- return 0;
+ return -1;
}
protocol = httpp_getvar(parser, HTTPP_VAR_PROTOCOL);
@@ -999,22 +987,24 @@
}
else {
ret = _check_pass_http(parser, user, pass);
- if(!ret && ice_login)
+ if (!ret)
{
- ret = _check_pass_ice(parser, pass);
- if(ret)
- WARN0("Source is using deprecated icecast login");
+ ice_config_t *config = config_get_config_unlocked();
+ if (config->ice_login)
+ {
+ ret = _check_pass_ice(parser, pass);
+ if(ret)
+ WARN0("Source is using deprecated icecast login");
+ }
}
}
- config_release_config();
return ret;
}
-static void _handle_source_request (client_t *client, char *uri, int auth_style)
+/* only called for native icecast source clients */
+static void _handle_source_request (client_t *client, const char *uri)
{
- source_t *source;
-
INFO1("Source logging in at mountpoint \"%s\"", uri);
if (uri[0] != '/')
@@ -1023,24 +1013,30 @@
client_send_401 (client);
return;
}
- if (auth_style == ICECAST_SOURCE_AUTH) {
- if (connection_check_source_pass (client->parser, uri) == 0)
- {
- /* We commonly get this if the source client is using the wrong
- * protocol: attempt to diagnose this and return an error
- */
- /* TODO: Do what the above comment says */
+ switch (client_check_source_auth (client, uri))
+ {
+ case 0: /* authenticated from config file */
+ source_startup (client, uri, ICECAST_SOURCE_AUTH);
+ break;
+
+ case 1: /* auth pending */
+ break;
+
+ default: /* failed */
INFO1("Source (%s) attempted to login with invalid or missing password", uri);
client_send_401(client);
- return;
- }
+ break;
}
+}
+
+
+void source_startup (client_t *client, const char *uri, int auth_style)
+{
+ source_t *source;
source = source_reserve (uri);
+
if (source)
{
- if (auth_style == SHOUTCAST_SOURCE_AUTH) {
- source->shoutcast_compat = 1;
- }
source->client = client;
source->parser = client->parser;
source->con = client->con;
@@ -1048,7 +1044,14 @@
{
source_clear_source (source);
source_free_source (source);
+ return;
}
+ client->respcode = 200;
+ if (auth_style == SHOUTCAST_SOURCE_AUTH)
+ {
+ source->shoutcast_compat = 1;
+ source_client_callback (client, source);
+ }
else
{
refbuf_t *ok = refbuf_new (PER_CLIENT_REFBUF_SIZE);
@@ -1241,7 +1244,7 @@
memmove (ptr, ptr + node->stream_offset, client->refbuf->len);
}
client->parser = parser;
- _handle_source_request (client, shoutcast_mount, SHOUTCAST_SOURCE_AUTH);
+ source_startup (client, shoutcast_mount, SHOUTCAST_SOURCE_AUTH);
}
else {
httpp_destroy (parser);
@@ -1322,7 +1325,7 @@
}
if (parser->req_type == httpp_req_source) {
- _handle_source_request (client, uri, ICECAST_SOURCE_AUTH);
+ _handle_source_request (client, uri);
}
else if (parser->req_type == httpp_req_stats) {
_handle_stats_request (client, uri);
Modified: icecast/trunk/icecast/src/connection.h
===================================================================
--- icecast/trunk/icecast/src/connection.h 2009-01-12 21:36:29 UTC (rev 15620)
+++ icecast/trunk/icecast/src/connection.h 2009-01-14 01:18:22 UTC (rev 15621)
@@ -60,7 +60,7 @@
connection_t *connection_create (sock_t sock, sock_t serversock, char *ip);
int connection_complete_source (struct source_tag *source, int response);
-int connection_check_source_pass(http_parser_t *parser, const char *mount);
+int connection_check_pass (http_parser_t *parser, const char *user, const char *pass);
int connection_check_relay_pass(http_parser_t *parser);
int connection_check_admin_pass(http_parser_t *parser);
Modified: icecast/trunk/icecast/src/source.h
===================================================================
--- icecast/trunk/icecast/src/source.h 2009-01-12 21:36:29 UTC (rev 15620)
+++ icecast/trunk/icecast/src/source.h 2009-01-14 01:18:22 UTC (rev 15621)
@@ -80,6 +80,7 @@
source_t *source_reserve (const char *mount);
void *source_client_thread (void *arg);
+void source_startup (client_t *client, const char *uri, int auth_style);
void source_client_callback (client_t *client, void *source);
void source_update_settings (ice_config_t *config, source_t *source, mount_proxy *mountinfo);
void source_clear_source (source_t *source);
More information about the commits
mailing list