1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-12-04 14:46:30 -05:00

Refactor admin.c handlers

This commit is contained in:
Marvin Scholz 2017-03-04 02:39:47 +01:00
parent e99ebfae3a
commit cf21756035
2 changed files with 133 additions and 278 deletions

View File

@ -62,46 +62,6 @@
#define COMMAND_ERROR ADMIN_COMMAND_ERROR #define COMMAND_ERROR ADMIN_COMMAND_ERROR
#define COMMAND_ANY ADMIN_COMMAND_ANY #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_RAW_REQUEST "fallbacks"
#define FALLBACK_TRANSFORMED_REQUEST "fallbacks.xsl" #define FALLBACK_TRANSFORMED_REQUEST "fallbacks.xsl"
#define SHOUTCAST_METADATA_REQUEST "admin.cgi" #define SHOUTCAST_METADATA_REQUEST "admin.cgi"
@ -133,98 +93,99 @@
#define DEFAULT_TRANSFORMED_REQUEST "" #define DEFAULT_TRANSFORMED_REQUEST ""
#define BUILDM3U_RAW_REQUEST "buildm3u" #define BUILDM3U_RAW_REQUEST "buildm3u"
typedef struct admin_command_tag { typedef void (*request_function_ptr)(client_t *, source_t *, int);
const int id;
const char *name; typedef struct admin_command_handler {
const char *route;
const int type; const int type;
const int format; const int format;
} admin_command_t; const request_function_ptr function;
} admin_command_handler_t;
/* static void command_fallback (client_t *client, source_t *source, int response);
COMMAND_TRANSFORMED_METADATA_UPDATE -> METADATA_TRANSFORMED_REQUEST static void command_metadata (client_t *client, source_t *source, int response);
COMMAND_TRANSFORMED_UPDATEMETADATA -> UPDATEMETADATA_TRANSFORMED_REQUEST 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_t commands[] = { static const admin_command_handler_t handlers[] = {
{COMMAND_RAW_FALLBACK, FALLBACK_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, { "*", ADMINTYPE_GENERAL, TRANSFORMED, NULL }, /* for ACL framework */
{COMMAND_TRANSFORMED_FALLBACK, FALLBACK_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, { FALLBACK_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_fallback },
{COMMAND_RAW_METADATA_UPDATE, METADATA_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, { FALLBACK_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_fallback },
{COMMAND_SHOUTCAST_METADATA_UPDATE, SHOUTCAST_METADATA_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, { METADATA_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_metadata },
{COMMAND_TRANSFORMED_METADATA_UPDATE, METADATA_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, { METADATA_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_metadata },
{COMMAND_RAW_SHOW_LISTENERS, LISTCLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, { SHOUTCAST_METADATA_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_shoutcast_metadata },
{COMMAND_TRANSFORMED_SHOW_LISTENERS, LISTCLIENTS_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, { LISTCLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_show_listeners },
{COMMAND_RAW_STATS, STATS_RAW_REQUEST, ADMINTYPE_HYBRID, RAW}, { LISTCLIENTS_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_show_listeners },
{COMMAND_TRANSFORMED_STATS, STATS_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED}, { STATS_RAW_REQUEST, ADMINTYPE_HYBRID, RAW, command_stats },
{COMMAND_RAW_STATS, "stats.xml", ADMINTYPE_HYBRID, RAW}, /* The old way */ { STATS_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED, command_stats },
{COMMAND_RAW_QUEUE_RELOAD, QUEUE_RELOAD_RAW_REQUEST, ADMINTYPE_GENERAL, RAW}, { "stats.xml", ADMINTYPE_HYBRID, RAW, command_stats },
{COMMAND_TRANSFORMED_QUEUE_RELOAD, QUEUE_RELOAD_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED}, { QUEUE_RELOAD_RAW_REQUEST, ADMINTYPE_GENERAL, RAW, command_queue_reload },
{COMMAND_RAW_LIST_MOUNTS, LISTMOUNTS_RAW_REQUEST, ADMINTYPE_GENERAL, RAW}, { QUEUE_RELOAD_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED, command_queue_reload },
{COMMAND_TRANSFORMED_LIST_MOUNTS, LISTMOUNTS_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED}, { LISTMOUNTS_RAW_REQUEST, ADMINTYPE_GENERAL, RAW, command_list_mounts },
{COMMAND_RAW_LISTSTREAM, STREAMLIST_RAW_REQUEST, ADMINTYPE_GENERAL, RAW}, { LISTMOUNTS_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED, command_list_mounts },
{COMMAND_PLAINTEXT_LISTSTREAM, STREAMLIST_PLAINTEXT_REQUEST, ADMINTYPE_GENERAL, PLAINTEXT}, { STREAMLIST_RAW_REQUEST, ADMINTYPE_GENERAL, RAW, command_list_mounts },
{COMMAND_TRANSFORMED_LISTSTREAM, STREAMLIST_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED}, { STREAMLIST_PLAINTEXT_REQUEST, ADMINTYPE_GENERAL, PLAINTEXT, command_list_mounts },
{COMMAND_RAW_MOVE_CLIENTS, MOVECLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, { STREAMLIST_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED, command_list_mounts },
{COMMAND_TRANSFORMED_MOVE_CLIENTS, MOVECLIENTS_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED}, { MOVECLIENTS_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_move_clients },
{COMMAND_RAW_KILL_CLIENT, KILLCLIENT_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, { MOVECLIENTS_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED, command_move_clients },
{COMMAND_TRANSFORMED_KILL_CLIENT, KILLCLIENT_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, { KILLCLIENT_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_kill_client },
{COMMAND_RAW_KILL_SOURCE, KILLSOURCE_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, { KILLCLIENT_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_kill_client },
{COMMAND_TRANSFORMED_KILL_SOURCE, KILLSOURCE_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, { KILLSOURCE_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_kill_source },
{COMMAND_RAW_MANAGEAUTH, MANAGEAUTH_RAW_REQUEST, ADMINTYPE_GENERAL, RAW}, { KILLSOURCE_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_kill_source },
{COMMAND_TRANSFORMED_MANAGEAUTH, MANAGEAUTH_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED}, { MANAGEAUTH_RAW_REQUEST, ADMINTYPE_GENERAL, RAW, command_manageauth },
{COMMAND_RAW_UPDATEMETADATA, UPDATEMETADATA_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, { MANAGEAUTH_TRANSFORMED_REQUEST, ADMINTYPE_GENERAL, TRANSFORMED, command_manageauth },
{COMMAND_TRANSFORMED_UPDATEMETADATA, UPDATEMETADATA_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED}, { UPDATEMETADATA_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_updatemetadata },
{COMMAND_BUILDM3U, BUILDM3U_RAW_REQUEST, ADMINTYPE_MOUNT, RAW}, { UPDATEMETADATA_TRANSFORMED_REQUEST, ADMINTYPE_MOUNT, TRANSFORMED, command_updatemetadata },
{COMMAND_TRANSFORMED_STATS, DEFAULT_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED}, { BUILDM3U_RAW_REQUEST, ADMINTYPE_MOUNT, RAW, command_buildm3u },
{COMMAND_TRANSFORMED_STATS, DEFAULT_RAW_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED}, { DEFAULT_TRANSFORMED_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED, command_stats },
{COMMAND_ANY, "*", ADMINTYPE_GENERAL, TRANSFORMED} /* for ACL framework */ { DEFAULT_RAW_REQUEST, ADMINTYPE_HYBRID, TRANSFORMED, command_stats }
}; };
#define HANDLERS_COUNT (sizeof(handlers)/sizeof(*handlers))
int admin_get_command(const char *command) int admin_get_command(const char *command)
{ {
size_t i; size_t i;
for (i = 0; i < (sizeof(commands)/sizeof(*commands)); i++) for (i = 0; i < HANDLERS_COUNT; i++)
if (strcmp(commands[i].name, command) == 0) if (strcmp(handlers[i].route, command) == 0)
return commands[i].id; return i;
return COMMAND_ERROR; 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) 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) if (handler != NULL)
return ADMINTYPE_ERROR; return handler->type;
for (i = 0; i < (sizeof(commands)/sizeof(*commands)); i++)
if (commands[i].id == command)
return commands[i].type;
return ADMINTYPE_ERROR; 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. /* 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 * If a mountpoint is passed then that source will not be added to the XML
* doc even if the source is running */ * 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) 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); ICECAST_LOG_DEBUG("Got 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;
}
if (strcmp(uri, "/admin.cgi") == 0) { handler = admin_get_handler(client->admin_command);
command_string = uri + 1;
}
else {
command_string = uri + 7;
}
ICECAST_LOG_DEBUG("Got command (%s)", command_string); /* Check if admin command is valid */
if (handler == NULL) {
if (client->admin_command <= 0) { ICECAST_LOG_ERROR("Error parsing command string or unrecognised command: %H",
ICECAST_LOG_ERROR("Error parsing command string or unrecognised command: %s", uri);
command_string);
client_send_error(client, 400, 0, "Unrecognised command"); client_send_error(client, 400, 0, "Unrecognised command");
return; return;
} }
/* Check ACL */
if (acl_test_admin(client->acl, client->admin_command) != ACL_POLICY_ALLOW) { 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_source) == ACL_POLICY_ALLOW ||
acl_test_method(client->acl, httpp_req_put) == 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 " 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"); mount = httpp_get_query_param(client->parser, "mount");
/* Find mountpoint source */
if(mount != NULL) { 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 */ /* This is a mount request, handle it as such */
avl_tree_rlock(global.source_tree); avl_tree_rlock(global.source_tree);
source = source_find_mount_raw(mount); source = source_find_mount_raw(mount);
/* No Source found */
if (source == NULL) { if (source == NULL) {
ICECAST_LOG_WARN("Admin command %s on non-existent source %s",
command_string, mount);
avl_tree_unlock(global.source_tree); 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"); client_send_error(client, 400, 0, "Source does not exist");
} else { return;
if (source->running == 0 && source->on_demand == 0) { } /* No Source running */
else if (source->running == 0 && source->on_demand == 0) {
avl_tree_unlock(global.source_tree); avl_tree_unlock(global.source_tree);
ICECAST_LOG_INFO("Received admin command %s on unavailable mount \"%s\"", ICECAST_LOG_INFO("Received admin command \"%H\" on unavailable mount \"%H\"",
command_string, mount); uri, mount);
client_send_error(client, 400, 0, "Source is not available"); client_send_error(client, 400, 0, "Source is not available");
return; return;
} }
if (client->admin_command == COMMAND_SHOUTCAST_METADATA_UPDATE && ICECAST_LOG_INFO("Received admin command %H on mount '%s'",
source->shoutcast_compat == 0) { uri, mount);
avl_tree_unlock(global.source_tree); }
ICECAST_LOG_ERROR("illegal change of metadata on non-shoutcast "
"compatible stream"); if (handler->type == ADMINTYPE_MOUNT && !source) {
client_send_error(client, 400, 0, "illegal metadata call"); client_send_error(client, 400, 0, "Mount parameter mandatory");
return; return;
} }
ICECAST_LOG_INFO("Received admin command %s on mount \"%s\"",
command_string, mount); handler->function(client, source, handler->format);
admin_handle_mount_request(client, source); if (source) {
avl_tree_unlock(global.source_tree); avl_tree_unlock(global.source_tree);
} }
} else {
admin_handle_general_request(client);
}
}
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");
return; 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;
}
} }
static void html_success(client_t *client, char *message) static void html_success(client_t *client, char *message)
@ -752,8 +592,9 @@ static void command_show_listeners(client_t *client,
xmlFreeDoc(doc); 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 *username = NULL;
const char *password = NULL; const char *password = NULL;
ice_config_t *config; ice_config_t *config;
@ -814,7 +655,7 @@ xmlNodePtr admin_add_role_to_authentication(auth_t *auth, xmlNodePtr parent)
return rolenode; 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; xmlDocPtr doc;
xmlNodePtr node, rolenode, usersnode, msgnode; xmlNodePtr node, rolenode, usersnode, msgnode;
@ -1057,7 +898,7 @@ static void command_metadata(client_t *client,
plugin = source->format; plugin = source->format;
if (source->client && strcmp(client->con->ip, source->client->con->ip) != 0) 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; same_ip = 0;
if (same_ip && plugin && plugin->set_tag) { if (same_ip && plugin && plugin->set_tag) {
@ -1090,7 +931,9 @@ static void command_metadata(client_t *client,
xmlFreeDoc(doc); 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 *action;
const char *value; 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"); 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) { if (source->parser->req_type == httpp_req_put) {
ICECAST_LOG_ERROR("Got legacy shoutcast-style metadata update command " ICECAST_LOG_ERROR("Got legacy shoutcast-style metadata update command "
"on source connected with PUT at mountpoint %s", source->mount); "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; return;
} }
if (source->client && strcmp (client->con->ip, source->client->con->ip) != 0) 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; same_ip = 0;
if (same_ip && source->format && source->format->set_tag) { 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; xmlDocPtr doc;
ICECAST_LOG_DEBUG("Stats request, sending xml stats"); 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; 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; xmlDocPtr doc;
xmlNodePtr node; 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"); ICECAST_LOG_DEBUG("List mounts request");

View File

@ -914,11 +914,15 @@ static void _handle_get_request(client_t *client, char *uri) {
stats_event_inc(NULL, "client_connections"); stats_event_inc(NULL, "client_connections");
/* Dispatch all admin requests */ /* Dispatch legacy admin.cgi requests */
if ((strcmp(uri, "/admin.cgi") == 0) || if (strcmp(uri, "/admin.cgi") == 0) {
(strncmp(uri, "/admin/", 7) == 0)) {
ICECAST_LOG_DEBUG("Client %p requesting admin interface.", client); 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; return;
} }