...
 
Commits (24)
......@@ -13,14 +13,14 @@ noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \
acl.h auth.h \
format.h format_ogg.h format_mp3.h format_ebml.h \
format_vorbis.h format_theora.h format_flac.h format_speex.h format_midi.h \
format_kate.h format_skeleton.h format_opus.h
format_kate.h format_skeleton.h format_opus.h cors.h
icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \
util.c errors.c slave.c source.c stats.c refbuf.c client.c playlist.c \
xslt.c fserve.c admin.c md5.c matchfile.c tls.c \
format.c format_ogg.c format_mp3.c format_midi.c format_flac.c format_ebml.c \
format_kate.c format_skeleton.c format_opus.c \
event.c event_log.c event_exec.c \
acl.c auth.c auth_htpasswd.c auth_anonymous.c auth_static.c
acl.c auth.c auth_htpasswd.c auth_anonymous.c auth_static.c cors.c
EXTRA_icecast_SOURCES = curl.c yp.c \
auth_url.c event_url.c \
format_vorbis.c format_theora.c format_speex.c
......
......@@ -3,7 +3,7 @@
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2014, Philipp Schafft <lion@lion.leolix.org>
* Copyright 2014-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */
......
......@@ -3,7 +3,7 @@
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2014, Philipp Schafft <lion@lion.leolix.org>
* Copyright 2014-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifndef __ACL_H__
......
......@@ -8,6 +8,7 @@
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
* and others (see AUTHORS for details).
* Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifndef __ADMIN_H__
......@@ -16,6 +17,14 @@
#include <libxml/parser.h>
#include <libxml/tree.h>
/* formats */
typedef enum {
ADMIN_FORMAT_AUTO,
ADMIN_FORMAT_RAW,
ADMIN_FORMAT_TRANSFORMED,
ADMIN_FORMAT_PLAINTEXT
} admin_format_t;
#include "refbuf.h"
#include "client.h"
#include "source.h"
......@@ -27,21 +36,16 @@
#define ADMINTYPE_MOUNT 2
#define ADMINTYPE_HYBRID (ADMINTYPE_GENERAL|ADMINTYPE_MOUNT)
/* formats */
#define RAW 1
#define TRANSFORMED 2
#define PLAINTEXT 3
/* special commands */
#define ADMIN_COMMAND_ERROR (-1)
#define ADMIN_COMMAND_ANY 0 /* for ACL framework */
void admin_handle_request(client_t *client, const char *uri);
void admin_send_response(xmlDocPtr doc,
client_t *client,
int response,
const char *xslt_template);
void admin_send_response(xmlDocPtr doc,
client_t *client,
admin_format_t response,
const char *xslt_template);
void admin_add_listeners_to_mount(source_t *source,
xmlNodePtr parent,
......
......@@ -394,7 +394,7 @@ static void auth_add_client(auth_t *auth, client_t *client, void (*on_no_match)(
auth_user->on_no_match = on_no_match;
auth_user->on_result = on_result;
auth_user->userdata = userdata;
ICECAST_LOG_INFO("adding client %p for authentication on %p", client, auth);
ICECAST_LOG_DEBUG("adding client %p for authentication on %p", client, auth);
queue_auth_client(auth_user);
}
......
......@@ -8,7 +8,7 @@
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
* and others (see AUTHORS for details).
* Copyright 2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
* Copyright 2014-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifndef __AUTH_H__
......@@ -19,7 +19,7 @@
#endif
struct source_tag;
struct auth_tag;
typedef struct auth_tag auth_t;
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
......@@ -66,7 +66,7 @@ typedef struct auth_client_tag
} auth_client;
typedef struct auth_tag
struct auth_tag
{
/* unique ID */
unsigned long id;
......@@ -113,7 +113,7 @@ typedef struct auth_tag
acl_t *acl;
/* role name for later matching, may be NULL if no role name was given in config */
char *role;
} auth_t;
};
typedef struct auth_stack_tag auth_stack_t;
......
......@@ -191,6 +191,11 @@ static auth_result htpasswd_auth (auth_client *auth_user)
}
htpasswd_recheckfile (htpasswd);
if (htpasswd->users) {
ICECAST_LOG_ERROR("No user list.");
return AUTH_NOMATCH;
}
thread_rwlock_rlock (&htpasswd->file_rwlock);
entry.name = client->username;
if (avl_get_by_key (htpasswd->users, &entry, &result) == 0) {
......@@ -257,8 +262,18 @@ static auth_result htpasswd_adduser (auth_t *auth, const char *username, const c
htpasswd_user entry;
void *result;
if (!state->filename) {
ICECAST_LOG_ERROR("No filename given in options for authenticator.");
return AUTH_FAILED;
}
htpasswd_recheckfile (state);
if (state->users) {
ICECAST_LOG_ERROR("No user list.");
return AUTH_FAILED;
}
thread_rwlock_wlock (&state->file_rwlock);
entry.name = (char*)username;
......@@ -301,6 +316,17 @@ static auth_result htpasswd_deleteuser(auth_t *auth, const char *username)
struct stat file_info;
state = auth->state;
if (!state->filename) {
ICECAST_LOG_ERROR("No filename given in options for authenticator.");
return AUTH_FAILED;
}
if (state->users) {
ICECAST_LOG_ERROR("No user list.");
return AUTH_FAILED;
}
thread_rwlock_wlock (&state->file_rwlock);
passwdfile = fopen(state->filename, "rb");
......@@ -383,8 +409,18 @@ static auth_result htpasswd_userlist(auth_t *auth, xmlNodePtr srcnode)
state = auth->state;
if (!state->filename) {
ICECAST_LOG_ERROR("No filename given in options for authenticator.");
return AUTH_FAILED;
}
htpasswd_recheckfile(state);
if (state->users) {
ICECAST_LOG_ERROR("No user list.");
return AUTH_FAILED;
}
thread_rwlock_rlock(&state->file_rwlock);
node = avl_get_first(state->users);
while (node) {
......
......@@ -3,7 +3,7 @@
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2000-2004, Jack Moffitt <jack@xiph.org>,
* Copyright 2000-2004, Jack Moffitt <jack@xiph.org>,
* Michael Smith <msmith@xiph.org>,
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
......@@ -27,10 +27,10 @@ struct _mount_proxy;
#include <libxml/tree.h>
#include "common/thread/thread.h"
#include "common/avl/avl.h"
#include "global.h"
#include "slave.h"
#include "connection.h"
#define XMLSTR(str) ((xmlChar *)(str))
#define XMLSTR(str) ((xmlChar *)(str))
typedef enum _operation_mode {
/* Default operation mode. may depend on context */
......@@ -155,15 +155,18 @@ typedef struct _mount_proxy {
struct _mount_proxy *next;
} mount_proxy;
typedef struct _aliases {
#define ALIAS_FLAG_PREFIXMATCH 0x0001
typedef struct _resource {
char *source;
char *destination;
int port;
char *bind_address;
char *vhost;
operation_mode omode;
struct _aliases *next;
} aliases;
unsigned int flags;
struct _resource *next;
} resource_t;
typedef struct _listener_t {
struct _listener_t *next;
......@@ -175,6 +178,21 @@ typedef struct _listener_t {
tlsmode_t tls;
} listener_t;
typedef struct ice_config_cors_path {
/* base path */
char *base;
/* no-cors path */
int no_cors;
/* allowed origins */
char **allowed;
/* forbidden origins */
char **forbidden;
/* exposed headers */
char *exposed_headers;
/* link to the next list element */
struct ice_config_cors_path *next;
} ice_config_cors_path_t;
typedef struct _config_tls_context {
char *cert_file;
char *key_file;
......@@ -221,6 +239,7 @@ typedef struct ice_config_tag {
char *master_password;
ice_config_http_header_t *http_headers;
ice_config_cors_path_t *cors_paths;
/* is TLS supported by the server? */
int tls_ok;
......@@ -238,7 +257,7 @@ typedef struct ice_config_tag {
char *allowfile;
char *webroot_dir;
char *adminroot_dir;
aliases *aliases;
resource_t *resources;
char *access_log;
char *error_log;
......
......@@ -28,6 +28,7 @@
#include "common/avl/avl.h"
#include "common/httpp/httpp.h"
#include "global.h"
#include "cfgfile.h"
#include "connection.h"
#include "refbuf.h"
......@@ -45,6 +46,8 @@
/* for ADMIN_COMMAND_ERROR */
#include "admin.h"
#include "cors.h"
#ifdef _WIN32
#define snprintf _snprintf
#endif
......@@ -266,7 +269,7 @@ static inline void _client_send_error(client_t *client, int plain, const icecast
fserve_add_client (client, NULL);
}
void client_send_error_by_id(client_t *client, int id)
void client_send_error_by_id(client_t *client, icecast_error_id_t id)
{
const icecast_error_t *error = error_get_by_id(id);
const char *pref;
......@@ -318,6 +321,42 @@ void client_send_101(client_t *client, reuse_t reuse)
fserve_add_client(client, NULL);
}
/* Sends an empty 204 response (for OPTIONS) */
void client_send_204(client_t *client)
{
ssize_t ret;
char *message;
message = calloc(PER_CLIENT_REFBUF_SIZE, sizeof(char));
if (!message) {
client_send_500(client, "Unable to allocate memory for response");
return;
}
ret = util_http_build_header(message, // Response buffer
PER_CLIENT_REFBUF_SIZE, // Buffer size
0, // Offset
0, // Prevent cache
204, // Status code
"No Content", // Status message
NULL, // Content-Type
NULL, // Charset
NULL, // Data
NULL, // Source
client);
if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) {
free(message);
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
client_send_500(client, "Header generation failed.");
return;
}
client_send_bytes(client, message, strlen(message));
client_destroy(client);
free(message);
}
void client_send_426(client_t *client, reuse_t reuse)
{
ssize_t ret;
......@@ -365,6 +404,26 @@ static inline void client_send_500(client_t *client, const char *message)
client_destroy(client);
}
admin_format_t client_get_admin_format_by_content_negotiation(client_t *client)
{
const char *pref;
if (!client || !client->parser)
return CLIENT_DEFAULT_ADMIN_FORMAT;
pref = util_http_select_best(httpp_getvar(client->parser, "accept"), "text/xml", "text/html", "text/plain", (const char*)NULL);
if (strcmp(pref, "text/xml") == 0) {
return ADMIN_FORMAT_RAW;
} else if (strcmp(pref, "text/html") == 0) {
return ADMIN_FORMAT_TRANSFORMED;
} else if (strcmp(pref, "text/plain") == 0) {
return ADMIN_FORMAT_PLAINTEXT;
} else {
return CLIENT_DEFAULT_ADMIN_FORMAT;
}
}
/* helper function for sending the data to a client */
int client_send_bytes(client_t *client, const void *buf, unsigned len)
{
......
......@@ -19,13 +19,19 @@
#ifndef __CLIENT_H__
#define __CLIENT_H__
typedef struct _client_tag client_t;
#include "errors.h"
#include "connection.h"
#include "refbuf.h"
#include "acl.h"
#include "cfgfile.h"
#include "admin.h"
#include "common/httpp/httpp.h"
#include "common/httpp/encoding.h"
#define CLIENT_DEFAULT_ADMIN_FORMAT ADMIN_FORMAT_TRANSFORMED
typedef enum _protocol_tag {
ICECAST_PROTOCOL_HTTP = 0,
ICECAST_PROTOCOL_SHOUTCAST
......@@ -40,7 +46,7 @@ typedef enum _reuse_tag {
ICECAST_REUSE_UPGRADETLS
} reuse_t;
typedef struct _client_tag
struct _client_tag
{
/* mode of operation for this client */
operation_mode mode;
......@@ -105,13 +111,15 @@ typedef struct _client_tag
/* function to check if refbuf needs updating */
int (*check_buffer)(struct source_tag *source, struct _client_tag *client);
} client_t;
};
int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser);
void client_destroy(client_t *client);
void client_send_error_by_id(client_t *client, int id);
void client_send_error_by_id(client_t *client, icecast_error_id_t id);
void client_send_101(client_t *client, reuse_t reuse);
void client_send_204(client_t *client);
void client_send_426(client_t *client, reuse_t reuse);
admin_format_t client_get_admin_format_by_content_negotiation(client_t *client);
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);
......
......@@ -135,7 +135,7 @@ void connection_shutdown(void)
tls_ctx_unref(tls_ctx);
matchfile_release(banned_ip);
matchfile_release(allowed_ip);
thread_cond_destroy(&global.shutdown_cond);
thread_rwlock_destroy(&_source_shutdown_rwlock);
thread_spin_destroy (&_connection_lock);
......@@ -915,18 +915,6 @@ static void _handle_get_request(client_t *client, char *uri) {
stats_event_inc(NULL, "client_connections");
/* 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 + 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;
}
/* this is a web/ request. let's check if we are allowed to do that. */
if (acl_test_web(client->acl) != ACL_POLICY_ALLOW) {
/* doesn't seem so, sad client :( */
......@@ -1074,10 +1062,10 @@ static void _handle_shoutcast_compatible(client_queue_t *node)
return;
}
/* Handle <alias> lookups here.
/* Handle <resource> lookups here.
*/
static int _handle_aliases(client_t *client, char **uri)
static int _handle_resources(client_t *client, char **uri)
{
const char *http_host = httpp_getvar(client->parser, "host");
char *serverhost = NULL;
......@@ -1087,7 +1075,7 @@ static int _handle_aliases(client_t *client, char **uri)
char *new_uri = NULL;
ice_config_t *config;
listener_t *listen_sock;
aliases *alias;
resource_t *resource;
if (http_host) {
vhost = strdup(http_host);
......@@ -1105,21 +1093,49 @@ static int _handle_aliases(client_t *client, char **uri)
serverport = listen_sock->port;
}
alias = config->aliases;
while (alias) {
if (strcmp(*uri, alias->source) == 0 &&
(alias->port == -1 || alias->port == serverport) &&
(alias->bind_address == NULL || (serverhost != NULL && strcmp(alias->bind_address, serverhost) == 0)) &&
(alias->vhost == NULL || (vhost != NULL && strcmp(alias->vhost, vhost) == 0)) ) {
if (alias->destination)
new_uri = strdup(alias->destination);
if (alias->omode != OMODE_DEFAULT)
client->mode = alias->omode;
ICECAST_LOG_DEBUG("alias has made %s into %s", *uri, new_uri);
break;
resource = config->resources;
/* We now go thru all resources and see if any matches. */
for (; resource; resource = resource->next) {
/* We check for several aspects, if they DO NOT match, we continue with our search. */
/* Check for the URI to match. */
if (resource->flags & ALIAS_FLAG_PREFIXMATCH) {
size_t len = strlen(resource->source);
if (strncmp(*uri, resource->source, len) != 0)
continue;
ICECAST_LOG_DEBUG("Match: *uri='%s', resource->source='%s', len=%zu", *uri, resource->source, len);
} else {
if (strcmp(*uri, resource->source) != 0)
continue;
}
alias = alias->next;
/* Check for the server's port to match. */
if (resource->port != -1 && resource->port != serverport)
continue;
/* Check for the server's bind address to match. */
if (resource->bind_address != NULL && serverhost != NULL && strcmp(resource->bind_address, serverhost) != 0)
continue;
/* Check for the vhost to match. */
if (resource->vhost != NULL && vhost != NULL && strcmp(resource->vhost, vhost) != 0)
continue;
/* Ok, we found a matching entry. */
if (resource->destination) {
if (resource->flags & ALIAS_FLAG_PREFIXMATCH) {
size_t len = strlen(resource->source);
asprintf(&new_uri, "%s%s", resource->destination, (*uri) + len);
} else {
new_uri = strdup(resource->destination);
}
}
if (resource->omode != OMODE_DEFAULT)
client->mode = resource->omode;
ICECAST_LOG_DEBUG("resource has made %s into %s", *uri, new_uri);
break;
}
config_release_config();
......@@ -1135,10 +1151,28 @@ static int _handle_aliases(client_t *client, char **uri)
return 0;
}
static void _handle_admin_request(client_t *client, char *adminuri)
{
ICECAST_LOG_DEBUG("Client %p requesting admin interface.", client);
stats_event_inc(NULL, "client_connections");
switch (client->parser->req_type) {
case httpp_req_get:
admin_handle_request(client, adminuri);
break;
default:
ICECAST_LOG_ERROR("Wrong request type from client");
client_send_error_by_id(client, ICECAST_ERROR_CON_UNKNOWN_REQUEST);
break;
}
}
/* Handle any client that passed the authing process.
*/
static void _handle_authed_client(client_t *client, void *uri, auth_result result)
{
httpp_request_type_e req_type;
auth_stack_release(client->authstack);
client->authstack = NULL;
......@@ -1148,13 +1182,31 @@ static void _handle_authed_client(client_t *client, void *uri, auth_result resul
return;
}
if (acl_test_method(client->acl, client->parser->req_type) != ACL_POLICY_ALLOW) {
// If path is not /admin/ OPTIONS should respect the same acl as GET
// for preflighted request
req_type = client->parser->req_type;
if (strstr(client->parser->uri, "/admin/") != client->parser->uri) {
req_type = httpp_req_get;
}
if (acl_test_method(client->acl, req_type) != ACL_POLICY_ALLOW) {
ICECAST_LOG_ERROR("Client (role=%s, username=%s) not allowed to use this request method on %H", client->role, client->username, uri);
client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE);
free(uri);
return;
}
/* Dispatch legacy admin.cgi requests */
if (strcmp(uri, "/admin.cgi") == 0) {
_handle_admin_request(client, uri + 1);
free(uri);
return;
} /* Dispatch all admin requests */
else if (strncmp(uri, "/admin/", 7) == 0) {
_handle_admin_request(client, uri + 7);
free(uri);
return;
}
switch (client->parser->req_type) {
case httpp_req_source:
case httpp_req_put:
......@@ -1166,6 +1218,9 @@ static void _handle_authed_client(client_t *client, void *uri, auth_result resul
case httpp_req_get:
_handle_get_request(client, uri);
break;
case httpp_req_options:
client_send_204(client);
break;
default:
ICECAST_LOG_ERROR("Wrong request type from client");
client_send_error_by_id(client, ICECAST_ERROR_CON_UNKNOWN_REQUEST);
......@@ -1377,7 +1432,7 @@ static void _handle_connection(void)
client->mode = config_str_to_omode(httpp_get_query_param(client->parser, "omode"));
if (_handle_aliases(client, &uri) != 0) {
if (_handle_resources(client, &uri) != 0) {
client_destroy (client);
continue;
}
......
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2017, Julien CROUZET <contact@juliencrouzet.fr>
*/
/**
* Cors handling functions
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <ctype.h>
#include "cfgfile.h"
#include "client.h"
#include "logging.h"
#define CATMODULE "CORS"
static const char* cors_header_names[7] = {
"access-control-allow-origin",
"access-control-expose-headers",
"access-control-max-age",
"access-control-allow-credentials",
"access-control-allow-methods",
"access-control-allow-headers",
NULL
};
static const char *icy_headers = "icy-br, icy-caps, icy-description, icy-genre, icy-metaint, icy-metadata-interval, icy-name, icy-pub, icy-public, icy-url";
static ice_config_cors_path_t* _find_matching_path(ice_config_cors_path_t *paths, char *path)
{
ice_config_cors_path_t *matching_path = paths;
while(matching_path) {
if (strncmp(matching_path->base, path, strlen(matching_path->base)) == 0) {
return matching_path;
}
matching_path = matching_path->next;
}
return NULL;
}
static int _cors_valid_origin(ice_config_cors_path_t *path, const char *origin) {
if (path->forbidden) {
for (int i = 0; path->forbidden[i]; i++) {
if (strstr(origin, path->forbidden[i]) == origin) {
ICECAST_LOG_DEBUG(
"Declared origin \"%s\" matches forbidden origin \"%s\", not sending CORS",
origin,
path->forbidden[i]
);
return 0;
}
}
}
if (path->allowed) {
for (int i = 0; path->allowed[i]; i++) {
if ((strlen(path->allowed[i]) == 1) && path->allowed[i][0] == '*') {
ICECAST_LOG_DEBUG(
"All (\"*\") allowed origin for \"%s\", sending CORS",
origin
);
return 1;
}
if (strstr(origin, path->allowed[i]) == origin) {
ICECAST_LOG_DEBUG(
"Declared origin \"%s\" matches allowed origin \"%s\", sending CORS",
origin,
path->allowed[i]
);
return 1;
}
}
}
ICECAST_LOG_DEBUG(
"Declared origin \"%s\" does not matches any declared origin, not sending CORS",
origin
);
return 0;
}
static void _add_header(char **out,
size_t *len,
const char *header_name,
const char *header_value)
{
int new_length;
char *new_out;
if (!header_name || !header_value || !strlen(header_name)) {
return;
}
new_length = strlen(header_name) + strlen(header_value) + 4;
new_out = calloc(*len + new_length, sizeof(char));
if (!new_out) {
ICECAST_LOG_ERROR("Out of memory while setting CORS header.");
return;
}
snprintf(new_out,
*len + new_length,
"%s%s: %s\r\n",
*out,
header_name,
header_value);
free(*out);
*len += new_length;
*out = new_out;
}
/**
* Removes an header by its name in current headers list.
* Header removal is needed to remove any manually added headers
* added while a forbidden rule is active.
*/
static void _remove_header(char **out,
size_t *len,
const char *header_name)
{
int header_start[100];
int header_end[100];
int current_position = 0;
int found_count = 0;
char *new_out;
if (!*len)
return;
while((current_position < (*len -1)) && found_count < 100) {
char *substr = strcasestr((*out + current_position), header_name);
char *substr_end;
if (!substr) {
break;
}
substr_end = strstr(substr, "\r\n");
if (!substr_end) {
return;
}
header_start[found_count] = substr - *out;
header_end[found_count] = substr_end - *out + 2;
current_position = header_end[found_count];
found_count++;
}
if (!found_count) {
return;
}
current_position = 0;
new_out = calloc(*len + 1, sizeof(char));
if (!new_out) {
return;
}
free(*out);
for (int i = 0; i < found_count; i++) {
while (current_position < header_start[i]) {
new_out[current_position] = *out[current_position];
}
current_position = header_end[i];
}
while (current_position < *len) {
new_out[current_position] = 0;
current_position++;
}
*out = new_out;
for (int i = 0; i < found_count; i++) {
*len -= header_end[i] - header_start[i];
}
return;
}
static void _add_cors(char **out,
size_t *len,
ice_config_cors_path_t *path,
char *origin)
{
_add_header(out, len, "Access-Control-Allow-Origin", origin);
if (path->exposed_headers) {
_add_header(out, len, "Access-Control-Expose-Headers", path->exposed_headers);
} else {
_add_header(out, len, "Access-Control-Expose-Headers", icy_headers);
}
_add_header(out, len, "Access-Control-Max-Age", "3600");
_add_header(out, len, "Access-Control-Allow-Credentials", "true");
_add_header(out, len, "Access-Control-Allow-Methods", "GET");
_add_header(out, len, "Access-Control-Allow-Headers", "icy-metadata");
return;
}
static void _remove_cors(char **out, size_t *len) {
for(int i = 0; cors_header_names[i]; i++) {
_remove_header(out, len, cors_header_names[i]);
}
return;
}
void cors_set_headers(char **out,
size_t *len,
ice_config_cors_path_t *paths,
struct _client_tag *client)
{
char *origin = NULL;
char *path = (char *)client->parser->uri;
ice_config_cors_path_t *matching_path;
if (!paths)
return;
if (!(origin = (char *)httpp_getvar(client->parser, "origin")))
return;
if (!path)
return;
matching_path = _find_matching_path(paths, path);
if (!matching_path) {
ICECAST_LOG_DEBUG(
"Requested path \"%s\" does not matches any declared CORS configured path",
path
);
return;
}
ICECAST_LOG_DEBUG(
"Requested path \"%s\" matches the \"%s\" declared CORS path",
path,
matching_path->base
);
_remove_cors(out, len);
if (
!matching_path->no_cors &&
_cors_valid_origin(matching_path, origin)
) {
_add_cors(out, len, matching_path, origin);
}
return;
}
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2017, Julien CROUZET <contact@juliencrouzet.fr>
*/
#ifndef __CORS_H__
#define __CORS_H__
#include <sys/types.h>
#include "cfgfile.h"
#include "client.h"
void cors_set_headers(char **out,
size_t *len,
ice_config_cors_path_t *options,
struct _client_tag *client);
#endif /* __CORS_H__ */
......@@ -135,7 +135,7 @@ static const icecast_error_t __errors[] = {
.message = "XSLT problem"}
};
const icecast_error_t * error_get_by_id(int id) {
const icecast_error_t * error_get_by_id(icecast_error_id_t id) {
size_t i;
for (i = 0; i < (sizeof(__errors)/sizeof(*__errors)); i++) {
......
......@@ -9,48 +9,50 @@
#ifndef __ERRORS_H__
#define __ERRORS_H__
#define ICECAST_ERROR_ADMIN_DEST_NOT_RUNNING 1
#define ICECAST_ERROR_ADMIN_METADAT_BADCALL 2
#define ICECAST_ERROR_ADMIN_METADAT_NO_SUCH_ACTION 3
#define ICECAST_ERROR_ADMIN_MISSING_PARAMETER 4
#define ICECAST_ERROR_ADMIN_missing_parameter 5 /* what is this? */
#define ICECAST_ERROR_ADMIN_MOUNT_NOT_ACCEPT_URL_UPDATES 6
#define ICECAST_ERROR_ADMIN_NO_SUCH_DESTINATION 7
#define ICECAST_ERROR_ADMIN_ROLEMGN_ADD_NOSYS 8
#define ICECAST_ERROR_ADMIN_ROLEMGN_DELETE_NOSYS 9
#define ICECAST_ERROR_ADMIN_ROLEMGN_ROLE_NOT_FOUND 10
#define ICECAST_ERROR_ADMIN_SOURCE_DOES_NOT_EXIST 11
#define ICECAST_ERROR_ADMIN_SOURCE_IS_NOT_AVAILABLE 12
#define ICECAST_ERROR_ADMIN_SUPPLIED_MOUNTPOINTS_ARE_IDENTICAL 13
#define ICECAST_ERROR_ADMIN_UNRECOGNISED_COMMAND 14
#define ICECAST_ERROR_AUTH_BUSY 15
#define ICECAST_ERROR_CON_CONTENT_TYPE_NOSYS 16
#define ICECAST_ERROR_CON_INTERNAL_FORMAT_ALLOC_ERROR 17
#define ICECAST_ERROR_CON_MISSING_PASS_PARAMETER 18
#define ICECAST_ERROR_CON_MOUNT_IN_USE 19
#define ICECAST_ERROR_CON_MOUNTPOINT_NOT_STARTING_WITH_SLASH 20
#define ICECAST_ERROR_CON_NO_CONTENT_TYPE_GIVEN 21
#define ICECAST_ERROR_CON_PER_CRED_CLIENT_LIMIT 22
#define ICECAST_ERROR_CON_rejecting_client_for_whatever_reason 23 /* ??? */
#define ICECAST_ERROR_CON_SOURCE_CLIENT_LIMIT 24
#define ICECAST_ERROR_CON_UNIMPLEMENTED 25
#define ICECAST_ERROR_CON_UNKNOWN_REQUEST 26
#define ICECAST_ERROR_CON_UPGRADE_ERROR 27
#define ICECAST_ERROR_FSERV_FILE_NOT_FOUND 28
#define ICECAST_ERROR_FSERV_FILE_NOT_READABLE 29
#define ICECAST_ERROR_FSERV_REQUEST_RANGE_NOT_SATISFIABLE 30
#define ICECAST_ERROR_GEN_BUFFER_REALLOC 31
#define ICECAST_ERROR_GEN_CLIENT_LIMIT 32
#define ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE 33
#define ICECAST_ERROR_GEN_HEADER_GEN_FAILED 34
#define ICECAST_ERROR_GEN_MEMORY_EXHAUSTED 35
#define ICECAST_ERROR_SOURCE_MOUNT_UNAVAILABLE 36
#define ICECAST_ERROR_SOURCE_STREAM_PREPARATION_ERROR 37
#define ICECAST_ERROR_XSLT_PARSE 38
#define ICECAST_ERROR_XSLT_problem 39
typedef enum {
ICECAST_ERROR_ADMIN_DEST_NOT_RUNNING,
ICECAST_ERROR_ADMIN_METADAT_BADCALL,
ICECAST_ERROR_ADMIN_METADAT_NO_SUCH_ACTION,
ICECAST_ERROR_ADMIN_MISSING_PARAMETER,
ICECAST_ERROR_ADMIN_missing_parameter, /* what is this? */
ICECAST_ERROR_ADMIN_MOUNT_NOT_ACCEPT_URL_UPDATES,
ICECAST_ERROR_ADMIN_NO_SUCH_DESTINATION,
ICECAST_ERROR_ADMIN_ROLEMGN_ADD_NOSYS,
ICECAST_ERROR_ADMIN_ROLEMGN_DELETE_NOSYS,
ICECAST_ERROR_ADMIN_ROLEMGN_ROLE_NOT_FOUND,
ICECAST_ERROR_ADMIN_SOURCE_DOES_NOT_EXIST,
ICECAST_ERROR_ADMIN_SOURCE_IS_NOT_AVAILABLE,
ICECAST_ERROR_ADMIN_SUPPLIED_MOUNTPOINTS_ARE_IDENTICAL,
ICECAST_ERROR_ADMIN_UNRECOGNISED_COMMAND,
ICECAST_ERROR_AUTH_BUSY,
ICECAST_ERROR_CON_CONTENT_TYPE_NOSYS,
ICECAST_ERROR_CON_INTERNAL_FORMAT_ALLOC_ERROR,
ICECAST_ERROR_CON_MISSING_PASS_PARAMETER,
ICECAST_ERROR_CON_MOUNT_IN_USE,
ICECAST_ERROR_CON_MOUNTPOINT_NOT_STARTING_WITH_SLASH,
ICECAST_ERROR_CON_NO_CONTENT_TYPE_GIVEN,
ICECAST_ERROR_CON_PER_CRED_CLIENT_LIMIT,
ICECAST_ERROR_CON_rejecting_client_for_whatever_reason, /* ??? */
ICECAST_ERROR_CON_SOURCE_CLIENT_LIMIT,
ICECAST_ERROR_CON_UNIMPLEMENTED,
ICECAST_ERROR_CON_UNKNOWN_REQUEST,
ICECAST_ERROR_CON_UPGRADE_ERROR,
ICECAST_ERROR_FSERV_FILE_NOT_FOUND,
ICECAST_ERROR_FSERV_FILE_NOT_READABLE,
ICECAST_ERROR_FSERV_REQUEST_RANGE_NOT_SATISFIABLE,
ICECAST_ERROR_GEN_BUFFER_REALLOC,
ICECAST_ERROR_GEN_CLIENT_LIMIT,
ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE,
ICECAST_ERROR_GEN_HEADER_GEN_FAILED,
ICECAST_ERROR_GEN_MEMORY_EXHAUSTED,
ICECAST_ERROR_SOURCE_MOUNT_UNAVAILABLE,
ICECAST_ERROR_SOURCE_STREAM_PREPARATION_ERROR,
ICECAST_ERROR_XSLT_PARSE,
ICECAST_ERROR_XSLT_problem
} icecast_error_id_t;
struct icecast_error_tag {
const int id;
const icecast_error_id_t id;
const int http_status;
const char *uuid;
const char *message;
......@@ -58,6 +60,6 @@ struct icecast_error_tag {
typedef struct icecast_error_tag icecast_error_t;
const icecast_error_t * error_get_by_id(int id);
const icecast_error_t * error_get_by_id(icecast_error_id_t id);
#endif /* __ERRORS_H__ */
......@@ -3,7 +3,7 @@
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2014, Philipp Schafft <lion@lion.leolix.org>
* Copyright 2014-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifndef __EVENT_H__
......
......@@ -21,6 +21,7 @@
#endif
#include "event.h"
#include "global.h"
#include "logging.h"
#define CATMODULE "event_exec"
......
......@@ -507,7 +507,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
*eol = '\0';
doc = stats_get_xml (0, reference, httpclient->mode);
free (reference);
admin_send_response (doc, httpclient, TRANSFORMED, xslt_playlist_requested);
admin_send_response (doc, httpclient, ADMIN_FORMAT_TRANSFORMED, xslt_playlist_requested);
xmlFreeDoc(doc);
free (fullpath);
return 0;
......
......@@ -19,15 +19,9 @@
#include "common/thread/thread.h"
#include "common/avl/avl.h"
#include "common/httpp/httpp.h"
#include "connection.h"
#include "refbuf.h"
#include "client.h"
#include "source.h"
#include "format.h"
#include "global.h"
#include "source.h"
ice_global_t global;
......
......@@ -21,6 +21,7 @@
#define ICECAST_VERSION_STRING "Icecast " PACKAGE_VERSION
#include "common/thread/thread.h"
#include "common/avl/avl.h"
#include "slave.h"
#include "common/net/sock.h"
......
......@@ -8,12 +8,14 @@
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
* and others (see AUTHORS for details).
* Copyright 2012-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
* Copyright 2012-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifndef __SOURCE_H__
#define __SOURCE_H__
typedef struct source_tag source_t;
#include "cfgfile.h"
#include "yp.h"
#include "util.h"
......@@ -23,7 +25,7 @@
#include <stdio.h>
typedef struct source_tag
struct source_tag
{
mutex_t lock;
client_t *client;
......@@ -82,7 +84,7 @@ typedef struct source_tag
playlist_t *history;
} source_t;
};
source_t *source_reserve (const char *mount);
void *source_client_thread (void *arg);
......
......@@ -49,6 +49,7 @@
#include "util.h"
#include "source.h"
#include "admin.h"
#include "cors.h"
#define CATMODULE "util"
......@@ -641,7 +642,11 @@ static inline void _build_headers_loop(char **ret, size_t *len, ice_config_htt
} while ((header = header->next));
*ret = r;
}
static inline char * _build_headers(int status, ice_config_t *config, source_t *source) {
static inline char * _build_headers(int status,
ice_config_t *config,
source_t *source,
struct _client_tag *client)
{
mount_proxy *mountproxy = NULL;
char *ret = NULL;
size_t len = 1;
......@@ -656,6 +661,8 @@ static inline char * _build_headers(int status, ice_config_t *config, source_t *
if (mountproxy && mountproxy->http_headers)
_build_headers_loop(&ret, &len, mountproxy->http_headers, status);
cors_set_headers(&ret, &len, config->cors_paths, client);
return ret;
}
......@@ -760,13 +767,13 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
currenttime_buffer[0] = '\0';
config = config_get_config();
extra_headers = _build_headers(status, config, source);
extra_headers = _build_headers(status, config, source, client);
ret = snprintf (out, len, "%sServer: %s\r\nConnection: %s\r\nAccept-Encoding: identity\r\nAllow: %s\r\n%s%s%s%s%s%s%s%s",
status_buffer,
config->server_id,
connection_header,
(client && client->admin_command == ADMIN_COMMAND_ERROR ?
"GET, SOURCE" : "GET"),
"GET, OPTIONS, SOURCE" : "GET, OPTIONS"),
upgrade_header,
currenttime_buffer,
contenttype_buffer,
......
......@@ -21,6 +21,7 @@
#include "common/thread/thread.h"
#include "global.h"
#include "curl.h"
#include "connection.h"
#include "refbuf.h"
......