From e99ebfae3af0e24dbb992025b978beb897a8bb8c Mon Sep 17 00:00:00 2001 From: Marvin Scholz Date: Sun, 21 May 2017 19:16:09 +0200 Subject: [PATCH 1/2] Move helper macros in admin.c to the top --- src/admin.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/admin.c b/src/admin.c index fee735e9..a14dfa9c 100644 --- a/src/admin.c +++ b/src/admin.c @@ -45,6 +45,19 @@ #define CATMODULE "admin" +/* Helper macros */ +#define COMMAND_REQUIRE(client,name,var) \ + do { \ + (var) = httpp_get_query_param((client)->parser, (name)); \ + if((var) == NULL) { \ + client_send_error((client), 400, 0, "Missing parameter"); \ + return; \ + } \ + } while(0); + +#define COMMAND_OPTIONAL(client,name,var) \ +(var) = httpp_get_query_param((client)->parser, (name)) + /* special commands */ #define COMMAND_ERROR ADMIN_COMMAND_ERROR #define COMMAND_ANY ADMIN_COMMAND_ANY @@ -558,18 +571,6 @@ static void admin_handle_mount_request(client_t *client, source_t *source) } } -#define COMMAND_REQUIRE(client,name,var) \ - do { \ - (var) = httpp_get_query_param((client)->parser, (name)); \ - if((var) == NULL) { \ - client_send_error((client), 400, 0, "Missing parameter"); \ - return; \ - } \ - } while(0); - -#define COMMAND_OPTIONAL(client,name,var) \ - (var) = httpp_get_query_param((client)->parser, (name)) - static void html_success(client_t *client, char *message) { ssize_t ret; From cf21756035f1a5c4d59c5582f3429c26bcb10137 Mon Sep 17 00:00:00 2001 From: Marvin Scholz Date: Sat, 4 Mar 2017 02:39:47 +0100 Subject: [PATCH 2/2] Refactor admin.c handlers --- src/admin.c | 399 +++++++++++++++-------------------------------- src/connection.c | 12 +- 2 files changed, 133 insertions(+), 278 deletions(-) diff --git a/src/admin.c b/src/admin.c index a14dfa9c..a1ea26cd 100644 --- a/src/admin.c +++ b/src/admin.c @@ -62,46 +62,6 @@ #define COMMAND_ERROR ADMIN_COMMAND_ERROR #define COMMAND_ANY ADMIN_COMMAND_ANY -/* Mount-specific commands (block 1-49 and 50-99) */ -#define COMMAND_RAW_FALLBACK 1 -#define COMMAND_RAW_METADATA_UPDATE 2 -#define COMMAND_RAW_SHOW_LISTENERS 3 -#define COMMAND_RAW_MOVE_CLIENTS 4 -#define COMMAND_RAW_MANAGEAUTH 5 -#define COMMAND_SHOUTCAST_METADATA_UPDATE 6 -#define COMMAND_RAW_UPDATEMETADATA 7 - -#define COMMAND_TRANSFORMED_FALLBACK 50 -#define COMMAND_TRANSFORMED_SHOW_LISTENERS 53 -#define COMMAND_TRANSFORMED_MOVE_CLIENTS 54 -#define COMMAND_TRANSFORMED_MANAGEAUTH 55 -#define COMMAND_TRANSFORMED_UPDATEMETADATA 56 -#define COMMAND_TRANSFORMED_METADATA_UPDATE 57 - -/* Global commands (block 101-199 and 201-299) */ -#define COMMAND_RAW_LIST_MOUNTS 101 -#define COMMAND_RAW_STATS 102 -#define COMMAND_RAW_LISTSTREAM 103 -#define COMMAND_PLAINTEXT_LISTSTREAM 104 -#define COMMAND_RAW_QUEUE_RELOAD 105 -#define COMMAND_TRANSFORMED_LIST_MOUNTS 201 -#define COMMAND_TRANSFORMED_STATS 202 -#define COMMAND_TRANSFORMED_LISTSTREAM 203 -#define COMMAND_TRANSFORMED_QUEUE_RELOAD 205 - -/* Client management commands (block 301-399 and 401-499) */ -#define COMMAND_RAW_KILL_CLIENT 301 -#define COMMAND_RAW_KILL_SOURCE 302 -#define COMMAND_TRANSFORMED_KILL_CLIENT 401 -#define COMMAND_TRANSFORMED_KILL_SOURCE 402 - -/* Admin commands requiring no auth (block 501-599) */ -#define COMMAND_BUILDM3U 501 - -/* Experimental features (e.g. in feature branches) (block 801-899) */ - -/* Private features (in branches not for merge with master) (block 901-999) */ - #define FALLBACK_RAW_REQUEST "fallbacks" #define FALLBACK_TRANSFORMED_REQUEST "fallbacks.xsl" #define SHOUTCAST_METADATA_REQUEST "admin.cgi" @@ -133,98 +93,99 @@ #define DEFAULT_TRANSFORMED_REQUEST "" #define BUILDM3U_RAW_REQUEST "buildm3u" -typedef struct admin_command_tag { - const int id; - const char *name; - const int type; - const int format; -} admin_command_t; +typedef void (*request_function_ptr)(client_t *, source_t *, int); -/* -COMMAND_TRANSFORMED_METADATA_UPDATE -> METADATA_TRANSFORMED_REQUEST -COMMAND_TRANSFORMED_UPDATEMETADATA -> UPDATEMETADATA_TRANSFORMED_REQUEST -*/ +typedef struct admin_command_handler { + const char *route; + const int type; + const int format; + const request_function_ptr function; +} admin_command_handler_t; -static const admin_command_t commands[] = { - {COMMAND_RAW_FALLBACK, FALLBACK_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, - {COMMAND_TRANSFORMED_FALLBACK, FALLBACK_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, - {COMMAND_RAW_METADATA_UPDATE, METADATA_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, - {COMMAND_SHOUTCAST_METADATA_UPDATE, SHOUTCAST_METADATA_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, - {COMMAND_TRANSFORMED_METADATA_UPDATE, METADATA_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, - {COMMAND_RAW_SHOW_LISTENERS, LISTCLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, - {COMMAND_TRANSFORMED_SHOW_LISTENERS, LISTCLIENTS_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, - {COMMAND_RAW_STATS, STATS_RAW_REQUEST, ADMINTYPE_HYBRID, RAW}, - {COMMAND_TRANSFORMED_STATS, STATS_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED}, - {COMMAND_RAW_STATS, "stats.xml", ADMINTYPE_HYBRID, RAW}, /* The old way */ - {COMMAND_RAW_QUEUE_RELOAD, QUEUE_RELOAD_RAW_REQUEST, ADMINTYPE_GENERAL, RAW}, - {COMMAND_TRANSFORMED_QUEUE_RELOAD, QUEUE_RELOAD_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED}, - {COMMAND_RAW_LIST_MOUNTS, LISTMOUNTS_RAW_REQUEST, ADMINTYPE_GENERAL, RAW}, - {COMMAND_TRANSFORMED_LIST_MOUNTS, LISTMOUNTS_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED}, - {COMMAND_RAW_LISTSTREAM, STREAMLIST_RAW_REQUEST, ADMINTYPE_GENERAL, RAW}, - {COMMAND_PLAINTEXT_LISTSTREAM, STREAMLIST_PLAINTEXT_REQUEST, ADMINTYPE_GENERAL, PLAINTEXT}, - {COMMAND_TRANSFORMED_LISTSTREAM, STREAMLIST_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED}, - {COMMAND_RAW_MOVE_CLIENTS, MOVECLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, - {COMMAND_TRANSFORMED_MOVE_CLIENTS, MOVECLIENTS_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED}, - {COMMAND_RAW_KILL_CLIENT, KILLCLIENT_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, - {COMMAND_TRANSFORMED_KILL_CLIENT, KILLCLIENT_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, - {COMMAND_RAW_KILL_SOURCE, KILLSOURCE_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, - {COMMAND_TRANSFORMED_KILL_SOURCE, KILLSOURCE_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, - {COMMAND_RAW_MANAGEAUTH, MANAGEAUTH_RAW_REQUEST, ADMINTYPE_GENERAL, RAW}, - {COMMAND_TRANSFORMED_MANAGEAUTH, MANAGEAUTH_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED}, - {COMMAND_RAW_UPDATEMETADATA, UPDATEMETADATA_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, - {COMMAND_TRANSFORMED_UPDATEMETADATA, UPDATEMETADATA_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, - {COMMAND_BUILDM3U, BUILDM3U_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, - {COMMAND_TRANSFORMED_STATS, DEFAULT_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED}, - {COMMAND_TRANSFORMED_STATS, DEFAULT_RAW_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED}, - {COMMAND_ANY, "*", ADMINTYPE_GENERAL, TRANSFORMED} /* for ACL framework */ +static void command_fallback (client_t *client, source_t *source, int response); +static void command_metadata (client_t *client, source_t *source, int response); +static void command_shoutcast_metadata (client_t *client, source_t *source, int response); +static void command_show_listeners (client_t *client, source_t *source, int response); +static void command_stats (client_t *client, source_t *source, int response); +static void command_queue_reload (client_t *client, source_t *source, int response); +static void command_list_mounts (client_t *client, source_t *source, int response); +static void command_move_clients (client_t *client, source_t *source, int response); +static void command_kill_client (client_t *client, source_t *source, int response); +static void command_kill_source (client_t *client, source_t *source, int response); +static void command_manageauth (client_t *client, source_t *source, int response); +static void command_updatemetadata (client_t *client, source_t *source, int response); +static void command_buildm3u (client_t *client, source_t *source, int response); + +static const admin_command_handler_t handlers[] = { + { "*", ADMINTYPE_GENERAL, TRANSFORMED, NULL }, /* for ACL framework */ + { FALLBACK_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_fallback }, + { FALLBACK_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_fallback }, + { METADATA_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_metadata }, + { METADATA_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_metadata }, + { SHOUTCAST_METADATA_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_shoutcast_metadata }, + { LISTCLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_show_listeners }, + { LISTCLIENTS_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_show_listeners }, + { STATS_RAW_REQUEST, ADMINTYPE_HYBRID, RAW, command_stats }, + { STATS_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED, command_stats }, + { "stats.xml", ADMINTYPE_HYBRID, RAW, command_stats }, + { QUEUE_RELOAD_RAW_REQUEST, ADMINTYPE_GENERAL, RAW, command_queue_reload }, + { QUEUE_RELOAD_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED, command_queue_reload }, + { LISTMOUNTS_RAW_REQUEST, ADMINTYPE_GENERAL, RAW, command_list_mounts }, + { LISTMOUNTS_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED, command_list_mounts }, + { STREAMLIST_RAW_REQUEST, ADMINTYPE_GENERAL, RAW, command_list_mounts }, + { STREAMLIST_PLAINTEXT_REQUEST, ADMINTYPE_GENERAL, PLAINTEXT, command_list_mounts }, + { STREAMLIST_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED, command_list_mounts }, + { MOVECLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_move_clients }, + { MOVECLIENTS_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED, command_move_clients }, + { KILLCLIENT_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_kill_client }, + { KILLCLIENT_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_kill_client }, + { KILLSOURCE_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_kill_source }, + { KILLSOURCE_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_kill_source }, + { MANAGEAUTH_RAW_REQUEST, ADMINTYPE_GENERAL, RAW, command_manageauth }, + { MANAGEAUTH_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED, command_manageauth }, + { UPDATEMETADATA_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_updatemetadata }, + { UPDATEMETADATA_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_updatemetadata }, + { BUILDM3U_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_buildm3u }, + { DEFAULT_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED, command_stats }, + { DEFAULT_RAW_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED, command_stats } }; +#define HANDLERS_COUNT (sizeof(handlers)/sizeof(*handlers)) + int admin_get_command(const char *command) { size_t i; - for (i = 0; i < (sizeof(commands)/sizeof(*commands)); i++) - if (strcmp(commands[i].name, command) == 0) - return commands[i].id; + for (i = 0; i < HANDLERS_COUNT; i++) + if (strcmp(handlers[i].route, command) == 0) + return i; return COMMAND_ERROR; } +/* Get the command handler for command or NULL + */ +const admin_command_handler_t* admin_get_handler(int command) +{ + if (command > 0 && command < HANDLERS_COUNT) + return &handlers[command]; + + return NULL; +} + +/* Get the command type for command + * If the command is invalid, ADMINTYPE_ERROR is returned. + */ int admin_get_command_type(int command) { - size_t i; + const admin_command_handler_t* handler = admin_get_handler(command); - if (command == ADMIN_COMMAND_ERROR || command == COMMAND_ANY) - return ADMINTYPE_ERROR; - - for (i = 0; i < (sizeof(commands)/sizeof(*commands)); i++) - if (commands[i].id == command) - return commands[i].type; + if (handler != NULL) + return handler->type; return ADMINTYPE_ERROR; } -static void command_fallback(client_t *client, source_t *source, int response); -static void command_metadata(client_t *client, source_t *source, int response); -static void command_shoutcast_metadata(client_t *client, source_t *source); -static void command_show_listeners(client_t *client, source_t *source, - int response); -static void command_move_clients(client_t *client, source_t *source, - int response); -static void command_stats(client_t *client, const char *mount, int response); -static void command_queue_reload(client_t *client, int response); -static void command_list_mounts(client_t *client, int response); -static void command_kill_client(client_t *client, source_t *source, - int response); -static void command_manageauth(client_t *client, int response); -static void command_buildm3u(client_t *client, const char *mount); -static void command_kill_source(client_t *client, source_t *source, - int response); -static void command_updatemetadata(client_t *client, source_t *source, - int response); -static void admin_handle_mount_request(client_t *client, source_t *source); -static void admin_handle_general_request(client_t *client); - /* build an XML doc containing information about currently running sources. * If a mountpoint is passed then that source will not be added to the XML * doc even if the source is running */ @@ -377,37 +338,29 @@ void admin_send_response(xmlDocPtr doc, } } - void admin_handle_request(client_t *client, const char *uri) { - const char *mount, *command_string; + const char *mount; + const admin_command_handler_t* handler; + source_t *source = NULL; - ICECAST_LOG_DEBUG("Admin request (%s)", uri); - if (!((strcmp(uri, "/admin.cgi") == 0) || - (strncmp("/admin/", uri, 7) == 0))) { - ICECAST_LOG_ERROR("Internal error: admin request isn't"); - client_send_error(client, 401, 1, "You need to authenticate\r\n"); - return; - } + ICECAST_LOG_DEBUG("Got admin request '%s'", uri); - if (strcmp(uri, "/admin.cgi") == 0) { - command_string = uri + 1; - } - else { - command_string = uri + 7; - } + handler = admin_get_handler(client->admin_command); - ICECAST_LOG_DEBUG("Got command (%s)", command_string); - - if (client->admin_command <= 0) { - ICECAST_LOG_ERROR("Error parsing command string or unrecognised command: %s", - command_string); + /* Check if admin command is valid */ + if (handler == NULL) { + ICECAST_LOG_ERROR("Error parsing command string or unrecognised command: %H", + uri); client_send_error(client, 400, 0, "Unrecognised command"); return; } + /* Check ACL */ if (acl_test_admin(client->acl, client->admin_command) != ACL_POLICY_ALLOW) { - if (client->admin_command == COMMAND_RAW_METADATA_UPDATE && + + /* ACL disallows, check exceptions */ + if ((handler->function == command_metadata && handler->format == RAW) && (acl_test_method(client->acl, httpp_req_source) == ACL_POLICY_ALLOW || acl_test_method(client->acl, httpp_req_put) == ACL_POLICY_ALLOW)) { ICECAST_LOG_DEBUG("Granted right to call COMMAND_RAW_METADATA_UPDATE to " @@ -420,155 +373,42 @@ void admin_handle_request(client_t *client, const char *uri) mount = httpp_get_query_param(client->parser, "mount"); + /* Find mountpoint source */ if(mount != NULL) { - source_t *source; - - /* this request does not require auth but can apply to files on webroot */ - if (client->admin_command == COMMAND_BUILDM3U) { - command_buildm3u(client, mount); - return; - } /* This is a mount request, handle it as such */ avl_tree_rlock(global.source_tree); source = source_find_mount_raw(mount); + /* No Source found */ if (source == NULL) { - ICECAST_LOG_WARN("Admin command %s on non-existent source %s", - command_string, mount); avl_tree_unlock(global.source_tree); + ICECAST_LOG_WARN("Admin command \"%H\" on non-existent source \"%H\"", + uri, mount); client_send_error(client, 400, 0, "Source does not exist"); - } else { - if (source->running == 0 && source->on_demand == 0) { - avl_tree_unlock(global.source_tree); - ICECAST_LOG_INFO("Received admin command %s on unavailable mount \"%s\"", - command_string, mount); - client_send_error(client, 400, 0, "Source is not available"); - return; - } - if (client->admin_command == COMMAND_SHOUTCAST_METADATA_UPDATE && - source->shoutcast_compat == 0) { - avl_tree_unlock(global.source_tree); - ICECAST_LOG_ERROR("illegal change of metadata on non-shoutcast " - "compatible stream"); - client_send_error(client, 400, 0, "illegal metadata call"); - return; - } - ICECAST_LOG_INFO("Received admin command %s on mount \"%s\"", - command_string, mount); - admin_handle_mount_request(client, source); + return; + } /* No Source running */ + else if (source->running == 0 && source->on_demand == 0) { avl_tree_unlock(global.source_tree); + ICECAST_LOG_INFO("Received admin command \"%H\" on unavailable mount \"%H\"", + uri, mount); + client_send_error(client, 400, 0, "Source is not available"); + return; } - } else { - admin_handle_general_request(client); + ICECAST_LOG_INFO("Received admin command %H on mount '%s'", + uri, mount); } -} -static void admin_handle_general_request(client_t *client) -{ - switch(client->admin_command) { - case COMMAND_RAW_STATS: - command_stats(client, NULL, RAW); - break; - case COMMAND_RAW_QUEUE_RELOAD: - command_queue_reload(client, RAW); - break; - case COMMAND_RAW_LIST_MOUNTS: - command_list_mounts(client, RAW); - break; - case COMMAND_RAW_LISTSTREAM: - command_list_mounts(client, RAW); - break; - case COMMAND_PLAINTEXT_LISTSTREAM: - command_list_mounts(client, PLAINTEXT); - break; - case COMMAND_TRANSFORMED_STATS: - command_stats(client, NULL, TRANSFORMED); - break; - case COMMAND_TRANSFORMED_QUEUE_RELOAD: - command_queue_reload(client, TRANSFORMED); - break; - case COMMAND_TRANSFORMED_LIST_MOUNTS: - command_list_mounts(client, TRANSFORMED); - break; - case COMMAND_TRANSFORMED_LISTSTREAM: - command_list_mounts(client, TRANSFORMED); - break; - case COMMAND_TRANSFORMED_MOVE_CLIENTS: - command_list_mounts(client, TRANSFORMED); - break; - case COMMAND_TRANSFORMED_MANAGEAUTH: - command_manageauth(client, TRANSFORMED); - break; - case COMMAND_RAW_MANAGEAUTH: - command_manageauth(client, RAW); - break; - default: - ICECAST_LOG_WARN("General admin request not recognised"); - client_send_error(client, 400, 0, "Unknown admin request"); + if (handler->type == ADMINTYPE_MOUNT && !source) { + client_send_error(client, 400, 0, "Mount parameter mandatory"); return; } -} -static void admin_handle_mount_request(client_t *client, source_t *source) -{ - switch(client->admin_command) { - case COMMAND_RAW_STATS: - command_stats(client, source->mount, RAW); - break; - case COMMAND_RAW_FALLBACK: - command_fallback(client, source, RAW); - break; - case COMMAND_RAW_METADATA_UPDATE: - command_metadata(client, source, RAW); - break; - case COMMAND_TRANSFORMED_METADATA_UPDATE: - command_metadata(client, source, TRANSFORMED); - break; - case COMMAND_SHOUTCAST_METADATA_UPDATE: - command_shoutcast_metadata(client, source); - break; - case COMMAND_RAW_SHOW_LISTENERS: - command_show_listeners(client, source, RAW); - break; - case COMMAND_RAW_MOVE_CLIENTS: - command_move_clients(client, source, RAW); - break; - case COMMAND_RAW_KILL_CLIENT: - command_kill_client(client, source, RAW); - break; - case COMMAND_RAW_KILL_SOURCE: - command_kill_source(client, source, RAW); - break; - case COMMAND_TRANSFORMED_STATS: - command_stats(client, source->mount, TRANSFORMED); - break; - case COMMAND_TRANSFORMED_FALLBACK: - command_fallback(client, source, RAW); - break; - case COMMAND_TRANSFORMED_SHOW_LISTENERS: - command_show_listeners(client, source, TRANSFORMED); - break; - case COMMAND_TRANSFORMED_MOVE_CLIENTS: - command_move_clients(client, source, TRANSFORMED); - break; - case COMMAND_TRANSFORMED_KILL_CLIENT: - command_kill_client(client, source, TRANSFORMED); - break; - case COMMAND_TRANSFORMED_KILL_SOURCE: - command_kill_source(client, source, TRANSFORMED); - break; - case COMMAND_TRANSFORMED_UPDATEMETADATA: - command_updatemetadata(client, source, TRANSFORMED); - break; - case COMMAND_RAW_UPDATEMETADATA: - command_updatemetadata(client, source, RAW); - break; - default: - ICECAST_LOG_WARN("Mount request not recognised"); - client_send_error(client, 400, 0, "Mount request unknown"); - break; + handler->function(client, source, handler->format); + if (source) { + avl_tree_unlock(global.source_tree); } + return; } static void html_success(client_t *client, char *message) @@ -752,8 +592,9 @@ static void command_show_listeners(client_t *client, xmlFreeDoc(doc); } -static void command_buildm3u(client_t *client, const char *mount) +static void command_buildm3u(client_t *client, source_t *source, int format) { + const char *mount = source->mount; const char *username = NULL; const char *password = NULL; ice_config_t *config; @@ -814,7 +655,7 @@ xmlNodePtr admin_add_role_to_authentication(auth_t *auth, xmlNodePtr parent) return rolenode; } -static void command_manageauth(client_t *client, int response) +static void command_manageauth(client_t *client, source_t *source, int response) { xmlDocPtr doc; xmlNodePtr node, rolenode, usersnode, msgnode; @@ -1057,7 +898,7 @@ static void command_metadata(client_t *client, plugin = source->format; if (source->client && strcmp(client->con->ip, source->client->con->ip) != 0) - if (response == RAW && acl_test_admin(client->acl, COMMAND_RAW_METADATA_UPDATE) != ACL_POLICY_ALLOW) + if (response == RAW && acl_test_admin(client->acl, client->admin_command) != ACL_POLICY_ALLOW) same_ip = 0; if (same_ip && plugin && plugin->set_tag) { @@ -1090,7 +931,9 @@ static void command_metadata(client_t *client, xmlFreeDoc(doc); } -static void command_shoutcast_metadata(client_t *client, source_t *source) +static void command_shoutcast_metadata(client_t *client, + source_t *source, + int format) { const char *action; const char *value; @@ -1098,6 +941,13 @@ static void command_shoutcast_metadata(client_t *client, source_t *source) ICECAST_LOG_DEBUG("Got shoutcast metadata update request"); + if (source->shoutcast_compat == 0) { + ICECAST_LOG_ERROR("illegal change of metadata on non-shoutcast " + "compatible stream"); + client_send_error(client, 400, 0, "illegal metadata call"); + return; + } + if (source->parser->req_type == httpp_req_put) { ICECAST_LOG_ERROR("Got legacy shoutcast-style metadata update command " "on source connected with PUT at mountpoint %s", source->mount); @@ -1111,7 +961,7 @@ static void command_shoutcast_metadata(client_t *client, source_t *source) return; } if (source->client && strcmp (client->con->ip, source->client->con->ip) != 0) - if (acl_test_admin(client->acl, COMMAND_RAW_METADATA_UPDATE) != ACL_POLICY_ALLOW) + if (acl_test_admin(client->acl, client->admin_command) != ACL_POLICY_ALLOW) same_ip = 0; if (same_ip && source->format && source->format->set_tag) { @@ -1126,8 +976,9 @@ static void command_shoutcast_metadata(client_t *client, source_t *source) } } -static void command_stats(client_t *client, const char *mount, int response) +static void command_stats(client_t *client, source_t *source, int response) { + const char *mount = (source) ? source->mount : NULL; xmlDocPtr doc; ICECAST_LOG_DEBUG("Stats request, sending xml stats"); @@ -1138,7 +989,7 @@ static void command_stats(client_t *client, const char *mount, int response) return; } -static void command_queue_reload(client_t *client, int response) +static void command_queue_reload(client_t *client, source_t *source, int response) { xmlDocPtr doc; xmlNodePtr node; @@ -1158,7 +1009,7 @@ static void command_queue_reload(client_t *client, int response) } -static void command_list_mounts(client_t *client, int response) +static void command_list_mounts(client_t *client, source_t *source, int response) { ICECAST_LOG_DEBUG("List mounts request"); diff --git a/src/connection.c b/src/connection.c index 1c50dd8c..98a96b72 100644 --- a/src/connection.c +++ b/src/connection.c @@ -914,11 +914,15 @@ static void _handle_get_request(client_t *client, char *uri) { stats_event_inc(NULL, "client_connections"); - /* Dispatch all admin requests */ - if ((strcmp(uri, "/admin.cgi") == 0) || - (strncmp(uri, "/admin/", 7) == 0)) { + /* Dispatch legacy admin.cgi requests */ + if (strcmp(uri, "/admin.cgi") == 0) { ICECAST_LOG_DEBUG("Client %p requesting admin interface.", client); - admin_handle_request(client, uri); + admin_handle_request(client, uri + 1); + return; + } /* Dispatch all admin requests */ + else if (strncmp(uri, "/admin/", 7) == 0) { + ICECAST_LOG_DEBUG("Client %p requesting admin interface.", client); + admin_handle_request(client, uri + 7); return; }