/** TODO: This is almost certainly buggy in some cases */ static void parse_query(http_parser_t *parser, char *query) { int len; int i=0; char *key = query; char *val=NULL; if(!query || !*query) return; len = strlen(query); while(i<len) { switch(query[i]) { case '&': query[i] = 0; if(val && key) httpp_set_query_param(parser, key, val); key = query+i+1; break; case '=': query[i] = 0; val = query+i+1; break; } i++; } if(val && key) { httpp_set_query_param(parser, key, val); } }
static int command_shoutcast_metadata (client_t *client, source_t *source) { const char *action; const char *value; int same_ip = 1; if (COMMAND_REQUIRE(client, "mode", action) < 0) { thread_mutex_unlock (&source->lock); return client_send_400 (client, "missing arg, mode"); } if ((source->flags & SOURCE_SHOUTCAST_COMPAT) == 0) { thread_mutex_unlock (&source->lock); ERROR0 ("illegal request on non-shoutcast compatible stream"); return client_send_400 (client, "Not a shoutcast compatible stream"); } if (strcmp (action, "updinfo") == 0) { DEBUG0("Got shoutcast metadata update request"); if (COMMAND_REQUIRE (client, "song", value) < 0) { thread_mutex_unlock (&source->lock); return client_send_400 (client, "missing arg, song"); } if (source->client && strcmp (client->connection.ip, source->client->connection.ip) != 0) if (connection_check_admin_pass (client->parser) == 0) same_ip = 0; if (same_ip && source->format && source->format->set_tag) { httpp_set_query_param (client->parser, "mount", client->server_conn->shoutcast_mount); source->format->set_tag (source->format, "title", value, NULL); source->format->set_tag (source->format, NULL, NULL, NULL); DEBUG2("Metadata on mountpoint %s changed to \"%s\"", source->mount, value); thread_mutex_unlock (&source->lock); return html_success(client, "Metadata update successful"); } thread_mutex_unlock (&source->lock); return client_send_400 (client, "mountpoint will not accept URL updates"); } if (strcmp (action, "viewxml") == 0) { xmlDocPtr doc; DEBUG0("Got shoutcast viewxml request"); thread_mutex_unlock (&source->lock); doc = stats_get_xml (STATS_ALL, source->mount); return admin_send_response (doc, client, XSLT, "viewxml.xsl"); } thread_mutex_unlock (&source->lock); return client_send_400 (client, "No such action"); }
void admin_handle_request(client_t *client, const char *uri) { const char *mount, *command_string; int command; DEBUG1("Admin request (%s)", uri); if (!((strcmp(uri, "/admin.cgi") == 0) || (strncmp("/admin/", uri, 7) == 0))) { ERROR0("Internal error: admin request isn't"); client_send_401(client); return; } if (strcmp(uri, "/admin.cgi") == 0) { command_string = uri + 1; } else { command_string = uri + 7; } DEBUG1("Got command (%s)", command_string); command = admin_get_command(command_string); if(command < 0) { ERROR1("Error parsing command string or unrecognised command: %s", command_string); client_send_400(client, "Unrecognised command"); return; } if (command == COMMAND_SHOUTCAST_METADATA_UPDATE) { ice_config_t *config; const char *sc_mount; const char *pass = httpp_get_query_param (client->parser, "pass"); listener_t *listener; if (pass == NULL) { client_send_400 (client, "missing pass parameter"); return; } config = config_get_config (); sc_mount = config->shoutcast_mount; listener = config_get_listen_sock (config, client->con); if (listener && listener->shoutcast_mount) sc_mount = listener->shoutcast_mount; httpp_set_query_param (client->parser, "mount", sc_mount); httpp_setvar (client->parser, HTTPP_VAR_PROTOCOL, "ICY"); httpp_setvar (client->parser, HTTPP_VAR_ICYPASSWORD, pass); config_release_config (); } mount = httpp_get_query_param(client->parser, "mount"); if(mount != NULL) { source_t *source; /* this request does not require auth but can apply to files on webroot */ if (command == COMMAND_BUILDM3U) { command_buildm3u (client, mount); return; } /* This is a mount request, handle it as such */ if (!connection_check_admin_pass(client->parser)) { if (!connection_check_source_pass(client->parser, mount)) { INFO1("Bad or missing password on mount modification admin " "request (command: %s)", command_string); client_send_401(client); return; } } avl_tree_rlock(global.source_tree); source = source_find_mount_raw(mount); if (source == NULL) { WARN2("Admin command %s on non-existent source %s", command_string, mount); avl_tree_unlock(global.source_tree); client_send_400(client, "Source does not exist"); } else { if (source->running == 0 && source->on_demand == 0) { avl_tree_unlock (global.source_tree); INFO2("Received admin command %s on unavailable mount \"%s\"", command_string, mount); client_send_400 (client, "Source is not available"); return; } if (command == COMMAND_SHOUTCAST_METADATA_UPDATE && source->shoutcast_compat == 0) { avl_tree_unlock (global.source_tree); ERROR0 ("illegal change of metadata on non-shoutcast " "compatible stream"); client_send_400 (client, "illegal metadata call"); return; } INFO2("Received admin command %s on mount \"%s\"", command_string, mount); admin_handle_mount_request(client, source, command); avl_tree_unlock(global.source_tree); } } else { if (command == COMMAND_PLAINTEXT_LISTSTREAM) { /* this request is used by a slave relay to retrieve mounts from the master, so handle this request validating against the relay password */ if(!connection_check_relay_pass(client->parser)) { INFO1("Bad or missing password on admin command " "request (command: %s)", command_string); client_send_401(client); return; } } else { if(!connection_check_admin_pass(client->parser)) { INFO1("Bad or missing password on admin command " "request (command: %s)", command_string); client_send_401(client); return; } } admin_handle_general_request(client, command); } }
/* Connection thread. Here we take clients off the connection queue and check * the contents provided. We set up the parser then hand off to the specific * request handler. */ static void _handle_connection(void) { http_parser_t *parser; const char *rawuri; client_queue_t *node; while (1) { node = _get_connection(); if (node) { client_t *client = node->client; /* Check for special shoutcast compatability processing */ if (node->shoutcast) { _handle_shoutcast_compatible (node); continue; } /* process normal HTTP headers */ parser = httpp_create_parser(); httpp_initialize(parser, NULL); client->parser = parser; if (httpp_parse (parser, client->refbuf->data, node->offset)) { char *uri; /* we may have more than just headers, so prepare for it */ if (node->stream_offset == node->offset) client->refbuf->len = 0; else { char *ptr = client->refbuf->data; client->refbuf->len = node->offset - node->stream_offset; memmove (ptr, ptr + node->stream_offset, client->refbuf->len); } rawuri = httpp_getvar(parser, HTTPP_VAR_URI); /* assign a port-based shoutcast mountpoint if required */ if (node->shoutcast_mount && strcmp (rawuri, "/admin.cgi") == 0) httpp_set_query_param (client->parser, "mount", node->shoutcast_mount); free (node->shoutcast_mount); free (node); if (strcmp("ICE", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) && strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL))) { ERROR0("Bad HTTP protocol detected"); client_destroy (client); continue; } uri = util_normalise_uri(rawuri); if (uri == NULL) { client_destroy (client); continue; } if (parser->req_type == httpp_req_source || parser->req_type == httpp_req_put) { _handle_source_request (client, uri); } else if (parser->req_type == httpp_req_stats) { _handle_stats_request (client, uri); } else if (parser->req_type == httpp_req_get) { _handle_get_request (client, uri); } else { ERROR0("Wrong request type from client"); client_send_400 (client, "unknown request"); } free(uri); } else { free (node); ERROR0("HTTP request parsing failed"); client_destroy (client); } continue; } break; } }
int admin_handle_request (client_t *client, const char *uri) { const char *mount = httpp_get_query_param(client->parser, "mount"); if (strcmp (uri, "/admin.cgi") == 0) { const char *pass = httpp_get_query_param (client->parser, "pass"); if (pass == NULL) return client_send_400 (client, "missing pass parameter"); uri++; if (mount == NULL) { if (client->server_conn && client->server_conn->shoutcast_mount) httpp_set_query_param (client->parser, "mount", client->server_conn->shoutcast_mount); mount = httpp_get_query_param (client->parser, "mount"); } httpp_setvar (client->parser, HTTPP_VAR_PROTOCOL, "ICY"); httpp_setvar (client->parser, HTTPP_VAR_ICYPASSWORD, pass); client->username = strdup ("source"); client->password = strdup (pass); } else uri += 7; if (connection_check_admin_pass (client->parser)) client->flags |= CLIENT_AUTHENTICATED; else { /* special case for slaves requesting a streamlist for authenticated relaying */ if (strcmp (uri, "streams") == 0 || strcmp (uri, "streamlist.txt") == 0) { if (connection_check_relay_pass (client->parser)) client->flags |= CLIENT_AUTHENTICATED; } } if (mount) { /* no auth/stream required for this */ if (strcmp (uri, "buildm3u") == 0) return command_buildm3u (client, mount); if (strcmp (uri, "showimage") == 0) return command_show_image (client, mount); /* This is a mount request, but admin user is allowed */ if ((client->flags & CLIENT_AUTHENTICATED) == 0) { switch (auth_check_source (client, mount)) { case 0: break; default: INFO1("Bad or missing password on mount modification " "admin request (%s)", uri); return client_send_401 (client, NULL); /* fall through */ case 1: return 0; } } if (strcmp (uri, "streams") == 0) return auth_add_listener ("/admin/streams", client); return admin_mount_request (client, uri); } return admin_handle_general_request (client, uri); }