mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2025-01-03 14:56:34 -05:00
Merge branch 'feature-auth-redirect'
This commit is contained in:
commit
b98aebe388
@ -470,7 +470,7 @@ void admin_send_response(xmlDocPtr doc,
|
||||
config_release_config();
|
||||
|
||||
ICECAST_LOG_DEBUG("Sending XSLT (%s)", fullpath_xslt_template);
|
||||
xslt_transform(doc, fullpath_xslt_template, client, 200);
|
||||
xslt_transform(doc, fullpath_xslt_template, client, 200, NULL);
|
||||
free(fullpath_xslt_template);
|
||||
}
|
||||
}
|
||||
|
219
src/auth.c
219
src/auth.c
@ -62,40 +62,43 @@ static unsigned long _next_auth_id(void) {
|
||||
return id;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
auth_result result;
|
||||
const char *string;
|
||||
} __auth_results[] = {
|
||||
{.result = AUTH_UNDEFINED, .string = "undefined"},
|
||||
{.result = AUTH_OK, .string = "ok"},
|
||||
{.result = AUTH_FAILED, .string = "failed"},
|
||||
{.result = AUTH_RELEASED, .string = "released"},
|
||||
{.result = AUTH_FORBIDDEN, .string = "forbidden"},
|
||||
{.result = AUTH_NOMATCH, .string = "no match"},
|
||||
{.result = AUTH_USERADDED, .string = "user added"},
|
||||
{.result = AUTH_USEREXISTS, .string = "user exists"},
|
||||
{.result = AUTH_USERDELETED, .string = "user deleted"}
|
||||
};
|
||||
|
||||
static const char *auth_result2str(auth_result res)
|
||||
{
|
||||
switch (res) {
|
||||
case AUTH_UNDEFINED:
|
||||
return "undefined";
|
||||
break;
|
||||
case AUTH_OK:
|
||||
return "ok";
|
||||
break;
|
||||
case AUTH_FAILED:
|
||||
return "failed";
|
||||
break;
|
||||
case AUTH_RELEASED:
|
||||
return "released";
|
||||
break;
|
||||
case AUTH_FORBIDDEN:
|
||||
return "forbidden";
|
||||
break;
|
||||
case AUTH_NOMATCH:
|
||||
return "no match";
|
||||
break;
|
||||
case AUTH_USERADDED:
|
||||
return "user added";
|
||||
break;
|
||||
case AUTH_USEREXISTS:
|
||||
return "user exists";
|
||||
break;
|
||||
case AUTH_USERDELETED:
|
||||
return "user deleted";
|
||||
break;
|
||||
default:
|
||||
return "(unknown)";
|
||||
break;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < (sizeof(__auth_results)/sizeof(*__auth_results)); i++) {
|
||||
if (__auth_results[i].result == res)
|
||||
return __auth_results[i].string;
|
||||
}
|
||||
|
||||
return "(unknown)";
|
||||
}
|
||||
|
||||
auth_result auth_str2result(const char *str)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < (sizeof(__auth_results)/sizeof(*__auth_results)); i++) {
|
||||
if (strcasecmp(__auth_results[i].string, str) == 0)
|
||||
return __auth_results[i].result;
|
||||
}
|
||||
|
||||
return AUTH_FAILED;
|
||||
}
|
||||
|
||||
static auth_client *auth_client_setup (client_t *client)
|
||||
@ -227,9 +230,11 @@ void auth_addref (auth_t *authenticator) {
|
||||
|
||||
static void auth_client_free (auth_client *auth_user)
|
||||
{
|
||||
if (auth_user == NULL)
|
||||
if (!auth_user)
|
||||
return;
|
||||
free (auth_user);
|
||||
|
||||
free(auth_user->alter_client_arg);
|
||||
free(auth_user);
|
||||
}
|
||||
|
||||
|
||||
@ -295,6 +300,55 @@ static auth_result auth_remove_client(auth_t *auth, auth_client *auth_user)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int __handle_auth_client_alter(auth_t *auth, auth_client *auth_user)
|
||||
{
|
||||
client_t *client = auth_user->client;
|
||||
const char *uuid = NULL;
|
||||
const char *location = NULL;
|
||||
int http_status = 0;
|
||||
|
||||
void client_send_redirect(client_t *client, const char *uuid, int status, const char *location);
|
||||
|
||||
switch (auth_user->alter_client_action) {
|
||||
case AUTH_ALTER_NOOP:
|
||||
return 0;
|
||||
break;
|
||||
case AUTH_ALTER_REWRITE:
|
||||
free(client->uri);
|
||||
client->uri = auth_user->alter_client_arg;
|
||||
auth_user->alter_client_arg = NULL;
|
||||
return 0;
|
||||
break;
|
||||
case AUTH_ALTER_REDIRECT:
|
||||
/* fall through */
|
||||
case AUTH_ALTER_REDIRECT_SEE_OTHER:
|
||||
uuid = "be7fac90-54fb-4673-9e0d-d15d6a4963a2";
|
||||
http_status = 303;
|
||||
location = auth_user->alter_client_arg;
|
||||
break;
|
||||
case AUTH_ALTER_REDIRECT_TEMPORARY:
|
||||
uuid = "4b08a03a-ecce-4981-badf-26b0bb6c9d9c";
|
||||
http_status = 307;
|
||||
location = auth_user->alter_client_arg;
|
||||
break;
|
||||
case AUTH_ALTER_REDIRECT_PERMANENT:
|
||||
uuid = "36bf6815-95cb-4cc8-a7b0-6b4b0c82ac5d";
|
||||
http_status = 308;
|
||||
location = auth_user->alter_client_arg;
|
||||
break;
|
||||
case AUTH_ALTER_SEND_ERROR:
|
||||
client_send_error_by_uuid(client, auth_user->alter_client_arg);
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (uuid && location && http_status) {
|
||||
client_send_redirect(client, uuid, http_status, location);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
static void __handle_auth_client (auth_t *auth, auth_client *auth_user) {
|
||||
auth_result result;
|
||||
|
||||
@ -315,6 +369,11 @@ static void __handle_auth_client (auth_t *auth, auth_client *auth_user) {
|
||||
auth_user->client->role = strdup(auth->role);
|
||||
}
|
||||
|
||||
if (result != AUTH_NOMATCH) {
|
||||
if (__handle_auth_client_alter(auth, auth_user) == 1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (result == AUTH_NOMATCH && auth_user->on_no_match) {
|
||||
auth_user->on_no_match(auth_user->client, auth_user->on_result, auth_user->userdata);
|
||||
} else if (auth_user->on_result) {
|
||||
@ -582,6 +641,52 @@ static inline int auth_get_authenticator__filter_method(auth_t *auth, xmlNodePtr
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int auth_get_authenticator__permission_alter(auth_t *auth, xmlNodePtr node, const char *name, auth_matchtype_t matchtype)
|
||||
{
|
||||
char * tmp = (char*)xmlGetProp(node, XMLSTR(name));
|
||||
|
||||
if (tmp) {
|
||||
char *cur = tmp;
|
||||
|
||||
while (cur) {
|
||||
char *next = strstr(cur, ",");
|
||||
auth_alter_t idx;
|
||||
|
||||
if (next) {
|
||||
*next = 0;
|
||||
next++;
|
||||
for (; *next == ' '; next++);
|
||||
}
|
||||
|
||||
if (strcmp(cur, "*") == 0) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < (sizeof(auth->permission_alter)/sizeof(*(auth->permission_alter))); i++)
|
||||
auth->permission_alter[i] = matchtype;
|
||||
break;
|
||||
}
|
||||
|
||||
idx = auth_str2alter(cur);
|
||||
if (idx == AUTH_ALTER_NOOP) {
|
||||
ICECAST_LOG_ERROR("Can not add unknown alter action \"%H\" to role's %s", cur, name);
|
||||
return -1;
|
||||
} else if (idx == AUTH_ALTER_REDIRECT) {
|
||||
auth->permission_alter[AUTH_ALTER_REDIRECT] = matchtype;
|
||||
auth->permission_alter[AUTH_ALTER_REDIRECT_SEE_OTHER] = matchtype;
|
||||
auth->permission_alter[AUTH_ALTER_REDIRECT_TEMPORARY] = matchtype;
|
||||
auth->permission_alter[AUTH_ALTER_REDIRECT_PERMANENT] = matchtype;
|
||||
} else {
|
||||
auth->permission_alter[idx] = matchtype;
|
||||
}
|
||||
|
||||
cur = next;
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
auth_t *auth_get_authenticator(xmlNodePtr node)
|
||||
{
|
||||
auth_t *auth = calloc(1, sizeof(auth_t));
|
||||
@ -609,6 +714,9 @@ auth_t *auth_get_authenticator(xmlNodePtr node)
|
||||
auth->filter_admin[i].command = ADMIN_COMMAND_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < (sizeof(auth->permission_alter)/sizeof(*(auth->permission_alter))); i++)
|
||||
auth->permission_alter[i] = AUTH_MATCHTYPE_NOMATCH;
|
||||
|
||||
if (!auth->type) {
|
||||
auth_release(auth);
|
||||
return NULL;
|
||||
@ -680,6 +788,9 @@ auth_t *auth_get_authenticator(xmlNodePtr node)
|
||||
auth_get_authenticator__filter_admin(auth, node, &filter_admin_index, "match-admin", AUTH_MATCHTYPE_MATCH);
|
||||
auth_get_authenticator__filter_admin(auth, node, &filter_admin_index, "nomatch-admin", AUTH_MATCHTYPE_NOMATCH);
|
||||
|
||||
auth_get_authenticator__permission_alter(auth, node, "may-alter", AUTH_MATCHTYPE_MATCH);
|
||||
auth_get_authenticator__permission_alter(auth, node, "may-not-alter", AUTH_MATCHTYPE_NOMATCH);
|
||||
|
||||
/* BEFORE RELEASE 2.5.0 TODO: Migrate this to config_parse_options(). */
|
||||
option = node->xmlChildrenNode;
|
||||
while (option)
|
||||
@ -743,6 +854,48 @@ auth_t *auth_get_authenticator(xmlNodePtr node)
|
||||
return auth;
|
||||
}
|
||||
|
||||
int auth_alter_client(auth_t *auth, auth_client *auth_user, auth_alter_t action, const char *arg)
|
||||
{
|
||||
if (!auth || !auth_user || !arg)
|
||||
return -1;
|
||||
|
||||
if (action < 0 || action >= (sizeof(auth->permission_alter)/sizeof(*(auth->permission_alter))))
|
||||
return -1;
|
||||
|
||||
if (auth->permission_alter[action] != AUTH_MATCHTYPE_MATCH)
|
||||
return -1;
|
||||
|
||||
if (replace_string(&(auth_user->alter_client_arg), arg) != 0)
|
||||
return -1;
|
||||
|
||||
auth_user->alter_client_action = action;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auth_alter_t auth_str2alter(const char *str)
|
||||
{
|
||||
if (!str)
|
||||
return AUTH_ALTER_NOOP;
|
||||
|
||||
if (strcasecmp(str, "noop") == 0) {
|
||||
return AUTH_ALTER_NOOP;
|
||||
} else if (strcasecmp(str, "rewrite") == 0) {
|
||||
return AUTH_ALTER_REWRITE;
|
||||
} else if (strcasecmp(str, "redirect") == 0) {
|
||||
return AUTH_ALTER_REDIRECT;
|
||||
} else if (strcasecmp(str, "redirect_see_other") == 0) {
|
||||
return AUTH_ALTER_REDIRECT_SEE_OTHER;
|
||||
} else if (strcasecmp(str, "redirect_temporary") == 0) {
|
||||
return AUTH_ALTER_REDIRECT_TEMPORARY;
|
||||
} else if (strcasecmp(str, "redirect_permanent") == 0) {
|
||||
return AUTH_ALTER_REDIRECT_PERMANENT;
|
||||
} else if (strcasecmp(str, "send_error") == 0) {
|
||||
return AUTH_ALTER_SEND_ERROR;
|
||||
} else {
|
||||
return AUTH_ALTER_NOOP;
|
||||
}
|
||||
}
|
||||
|
||||
/* these are called at server start and termination */
|
||||
|
||||
|
28
src/auth.h
28
src/auth.h
@ -65,6 +65,23 @@ typedef enum {
|
||||
AUTH_MATCHTYPE_NOMATCH
|
||||
} auth_matchtype_t;
|
||||
|
||||
typedef enum {
|
||||
/* Used internally by auth system. */
|
||||
AUTH_ALTER_NOOP = 0,
|
||||
/* Internal rewrite of URI */
|
||||
AUTH_ALTER_REWRITE,
|
||||
/* Redirect to another location. */
|
||||
AUTH_ALTER_REDIRECT,
|
||||
/* See some other resource */
|
||||
AUTH_ALTER_REDIRECT_SEE_OTHER,
|
||||
/* This resource is currently located elsewhere */
|
||||
AUTH_ALTER_REDIRECT_TEMPORARY,
|
||||
/* This resource is now located at new location */
|
||||
AUTH_ALTER_REDIRECT_PERMANENT,
|
||||
/* Send an error report to the client */
|
||||
AUTH_ALTER_SEND_ERROR
|
||||
} auth_alter_t;
|
||||
|
||||
typedef struct auth_client_tag auth_client;
|
||||
struct auth_client_tag {
|
||||
client_t *client;
|
||||
@ -72,6 +89,9 @@ struct auth_client_tag {
|
||||
void (*on_no_match)(client_t *client, void (*on_result)(client_t *client, void *userdata, auth_result result), void *userdata);
|
||||
void (*on_result)(client_t *client, void *userdata, auth_result result);
|
||||
void *userdata;
|
||||
void *authbackend_userdata;
|
||||
auth_alter_t alter_client_action;
|
||||
char *alter_client_arg;
|
||||
auth_client *next;
|
||||
};
|
||||
|
||||
@ -95,6 +115,9 @@ struct auth_tag
|
||||
admin_command_id_t command;
|
||||
} filter_admin[MAX_ADMIN_COMMANDS];
|
||||
|
||||
/* permissions */
|
||||
auth_matchtype_t permission_alter[AUTH_ALTER_SEND_ERROR+1];
|
||||
|
||||
/* whether authenticate_client() and release_client() will return immediate.
|
||||
* Setting this will result in no thread being started for this.
|
||||
*/
|
||||
@ -141,6 +164,8 @@ int auth_get_htpasswd_auth(auth_t *auth, config_options_t *options);
|
||||
void auth_initialise(void);
|
||||
void auth_shutdown(void);
|
||||
|
||||
auth_result auth_str2result(const char *str);
|
||||
|
||||
auth_t *auth_get_authenticator(xmlNodePtr node);
|
||||
void auth_release(auth_t *authenticator);
|
||||
void auth_addref(auth_t *authenticator);
|
||||
@ -154,6 +179,9 @@ void auth_stack_add_client(auth_stack_t *stack,
|
||||
auth_result result),
|
||||
void *userdata);
|
||||
|
||||
int auth_alter_client(auth_t *auth, auth_client *auth_user, auth_alter_t action, const char *arg);
|
||||
auth_alter_t auth_str2alter(const char *str);
|
||||
|
||||
void auth_stack_release(auth_stack_t *stack);
|
||||
void auth_stack_addref(auth_stack_t *stack);
|
||||
int auth_stack_next(auth_stack_t **stack); /* returns -1 on error, 0 on success, +1 if no next element is present */
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "auth.h"
|
||||
#include "cfgfile.h"
|
||||
#include "client.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "logging.h"
|
||||
#define CATMODULE "auth_static"
|
||||
@ -27,6 +28,8 @@
|
||||
typedef struct auth_static {
|
||||
char *username;
|
||||
char *password;
|
||||
auth_alter_t action;
|
||||
char *arg;
|
||||
} auth_static_t;
|
||||
|
||||
static auth_result static_auth(auth_client *auth_user)
|
||||
@ -45,19 +48,28 @@ static auth_result static_auth(auth_client *auth_user)
|
||||
if (!client->password)
|
||||
return AUTH_NOMATCH;
|
||||
|
||||
if (strcmp(auth_info->password, client->password) == 0)
|
||||
return AUTH_OK;
|
||||
if (strcmp(auth_info->password, client->password) != 0)
|
||||
return AUTH_FAILED;
|
||||
|
||||
return AUTH_FAILED;
|
||||
|
||||
if (auth_info->action != AUTH_ALTER_NOOP) {
|
||||
if (auth_alter_client(auth, auth_user, auth_info->action, auth_info->arg) != 0) {
|
||||
ICECAST_LOG_ERROR("Can not alter client.");
|
||||
}
|
||||
}
|
||||
|
||||
return AUTH_OK;
|
||||
}
|
||||
|
||||
static void clear_auth (auth_t *auth)
|
||||
{
|
||||
auth_static_t *auth_info = auth->state;
|
||||
if (auth_info->username)
|
||||
free(auth_info->username);
|
||||
if (auth_info->password)
|
||||
free(auth_info->password);
|
||||
if (!auth_info)
|
||||
return;
|
||||
|
||||
free(auth_info->username);
|
||||
free(auth_info->password);
|
||||
free(auth_info->arg);
|
||||
free(auth_info);
|
||||
auth->state = NULL;
|
||||
}
|
||||
@ -106,6 +118,15 @@ int auth_get_static_auth (auth_t *authenticator, config_options_t *options)
|
||||
if (auth_info->password)
|
||||
free(auth_info->password);
|
||||
auth_info->password = strdup(options->value);
|
||||
} else if (strcmp(options->name, "action") == 0) {
|
||||
auth_info->action = auth_str2alter(options->value);
|
||||
if (auth_info->action == AUTH_ALTER_NOOP) {
|
||||
ICECAST_LOG_ERROR("Invalid action given.");
|
||||
clear_auth(authenticator);
|
||||
return -1;
|
||||
}
|
||||
} else if (strcmp(options->name, "argument") == 0) {
|
||||
replace_string(&(auth_info->arg), options->value);
|
||||
} else {
|
||||
ICECAST_LOG_ERROR("Unknown option: %s", options->name);
|
||||
}
|
||||
|
276
src/auth_url.c
276
src/auth_url.c
@ -67,6 +67,7 @@
|
||||
# define strncasecmp strnicmp
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "curl.h"
|
||||
#include "auth.h"
|
||||
#include "source.h"
|
||||
@ -78,6 +79,16 @@
|
||||
#include "logging.h"
|
||||
#define CATMODULE "auth_url"
|
||||
|
||||
/* Default headers */
|
||||
#define DEFAULT_HEADER_OLD_RESULT "icecast-auth-user: 1\r\n"
|
||||
#define DEFAULT_HEADER_OLD_TIMELIMIT "icecast-auth-timelimit:"
|
||||
#define DEFAULT_HEADER_OLD_MESSAGE "icecast-auth-message"
|
||||
#define DEFAULT_HEADER_NEW_RESULT "x-icecast-auth-result"
|
||||
#define DEFAULT_HEADER_NEW_TIMELIMIT "x-icecast-auth-timelimit"
|
||||
#define DEFAULT_HEADER_NEW_MESSAGE "x-icecast-auth-message"
|
||||
#define DEFAULT_HEADER_NEW_ALTER_ACTION "x-icecast-auth-alter-action"
|
||||
#define DEFAULT_HEADER_NEW_ALTER_ARGUMENT "x-icecast-auth-alter-argument"
|
||||
|
||||
typedef struct {
|
||||
char *pass_headers; // headers passed from client to addurl.
|
||||
char *prefix_headers; // prefix for passed headers.
|
||||
@ -87,16 +98,37 @@ typedef struct {
|
||||
char *removeaction;
|
||||
char *username;
|
||||
char *password;
|
||||
|
||||
/* old style */
|
||||
char *auth_header;
|
||||
int auth_header_len;
|
||||
size_t auth_header_len;
|
||||
char *timelimit_header;
|
||||
int timelimit_header_len;
|
||||
size_t timelimit_header_len;
|
||||
/* new style */
|
||||
char *header_auth;
|
||||
char *header_timelimit;
|
||||
char *header_message;
|
||||
char *header_alter_action;
|
||||
char *header_alter_argument;
|
||||
|
||||
char *userpwd;
|
||||
CURL *handle;
|
||||
char errormsg[CURL_ERROR_SIZE];
|
||||
auth_result result;
|
||||
} auth_url;
|
||||
|
||||
typedef struct {
|
||||
char *all_headers;
|
||||
size_t all_headers_len;
|
||||
http_parser_t *parser;
|
||||
} auth_user_url_t;
|
||||
|
||||
static inline const char * __str_or_default(const char *str, const char *def)
|
||||
{
|
||||
if (str)
|
||||
return str;
|
||||
return def;
|
||||
}
|
||||
|
||||
static void auth_url_clear(auth_t *self)
|
||||
{
|
||||
@ -116,42 +148,181 @@ static void auth_url_clear(auth_t *self)
|
||||
free(url->removeaction);
|
||||
free(url->auth_header);
|
||||
free(url->timelimit_header);
|
||||
free(url->header_auth);
|
||||
free(url->header_timelimit);
|
||||
free(url->header_message);
|
||||
free(url->header_alter_action);
|
||||
free(url->header_alter_argument);
|
||||
free(url->userpwd);
|
||||
free(url);
|
||||
}
|
||||
|
||||
static void auth_user_url_clear(auth_client *auth_user)
|
||||
{
|
||||
auth_user_url_t *au_url = auth_user->authbackend_userdata;
|
||||
|
||||
if (!au_url)
|
||||
return;
|
||||
|
||||
free(au_url->all_headers);
|
||||
if (au_url->parser)
|
||||
httpp_destroy(au_url->parser);
|
||||
|
||||
free(au_url);
|
||||
auth_user->authbackend_userdata = NULL;
|
||||
}
|
||||
|
||||
static void handle_returned_header__complete(auth_client *auth_user)
|
||||
{
|
||||
auth_user_url_t *au_url = auth_user->authbackend_userdata;
|
||||
const char *tmp;
|
||||
const char *action;
|
||||
const char *argument;
|
||||
auth_url *url = auth_user->client->auth->state;
|
||||
|
||||
if (!au_url)
|
||||
return;
|
||||
|
||||
if (au_url->parser)
|
||||
return;
|
||||
|
||||
au_url->parser = httpp_create_parser();
|
||||
httpp_initialize(au_url->parser, NULL);
|
||||
|
||||
if (!httpp_parse_response(au_url->parser, au_url->all_headers, au_url->all_headers_len, NULL)) {
|
||||
ICECAST_LOG_ERROR("Can not parse auth backend reply.");
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = httpp_getvar(au_url->parser, HTTPP_VAR_ERROR_CODE);
|
||||
if (tmp[0] == '2') {
|
||||
ICECAST_LOG_DEBUG("Got final status: %#H", tmp);
|
||||
} else {
|
||||
ICECAST_LOG_DEBUG("Got non-final status: %#H", tmp);
|
||||
httpp_destroy(au_url->parser);
|
||||
au_url->parser = NULL;
|
||||
au_url->all_headers_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (url->header_auth) {
|
||||
tmp = httpp_getvar(au_url->parser, url->header_auth);
|
||||
if (tmp) {
|
||||
url->result = auth_str2result(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (url->header_timelimit) {
|
||||
tmp = httpp_getvar(au_url->parser, url->header_timelimit);
|
||||
if (tmp) {
|
||||
long long int ret;
|
||||
char *endptr;
|
||||
|
||||
errno = 0;
|
||||
ret = strtoll(tmp, &endptr, 0);
|
||||
if (endptr != tmp && errno == 0) {
|
||||
auth_user->client->con->discon_time = time(NULL) + (time_t)ret;
|
||||
} else {
|
||||
ICECAST_LOG_ERROR("Auth backend returned invalid new style timelimit header: % #H", tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action = httpp_getvar(au_url->parser, __str_or_default(url->header_alter_action, DEFAULT_HEADER_NEW_ALTER_ACTION));
|
||||
argument = httpp_getvar(au_url->parser, __str_or_default(url->header_alter_argument, DEFAULT_HEADER_NEW_ALTER_ARGUMENT));
|
||||
|
||||
if (action && argument) {
|
||||
if (auth_alter_client(auth_user->client->auth, auth_user, auth_str2alter(action), argument) != 0) {
|
||||
ICECAST_LOG_ERROR("Auth backend returned invalid alter action/argument.");
|
||||
}
|
||||
} else if (action || argument) {
|
||||
ICECAST_LOG_ERROR("Auth backend returned incomplete alter action/argument.");
|
||||
}
|
||||
|
||||
if (url->header_message) {
|
||||
tmp = httpp_getvar(au_url->parser, url->header_message);
|
||||
} else {
|
||||
tmp = httpp_getvar(au_url->parser, DEFAULT_HEADER_NEW_MESSAGE);
|
||||
if (!tmp)
|
||||
tmp = httpp_getvar(au_url->parser, DEFAULT_HEADER_OLD_MESSAGE);
|
||||
}
|
||||
if (tmp) {
|
||||
snprintf(url->errormsg, sizeof(url->errormsg), "%s", tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t handle_returned_header(void *ptr,
|
||||
size_t size,
|
||||
size_t nmemb,
|
||||
void *stream)
|
||||
{
|
||||
size_t len = size * nmemb;
|
||||
auth_client *auth_user = stream;
|
||||
unsigned bytes = size * nmemb;
|
||||
client_t *client = auth_user->client;
|
||||
auth_t *auth;
|
||||
auth_url *url;
|
||||
|
||||
if (client) {
|
||||
auth_t *auth = client->auth;
|
||||
auth_url *url = auth->state;
|
||||
if (strncasecmp(ptr, url->auth_header, url->auth_header_len) == 0)
|
||||
url->result = AUTH_OK;
|
||||
if (strncasecmp(ptr, url->timelimit_header,
|
||||
url->timelimit_header_len) == 0) {
|
||||
unsigned int limit = 0;
|
||||
sscanf ((char *)ptr+url->timelimit_header_len, "%u\r\n", &limit);
|
||||
client->con->discon_time = time(NULL) + limit;
|
||||
if (!client)
|
||||
return len;
|
||||
|
||||
auth = client->auth;
|
||||
url = auth->state;
|
||||
|
||||
if (!auth_user->authbackend_userdata) {
|
||||
auth_user->authbackend_userdata = calloc(1, sizeof(auth_user_url_t));
|
||||
}
|
||||
|
||||
if (auth_user->authbackend_userdata) {
|
||||
auth_user_url_t *au_url = auth_user->authbackend_userdata;
|
||||
char *n = realloc(au_url->all_headers, au_url->all_headers_len + len);
|
||||
if (n) {
|
||||
au_url->all_headers = n;
|
||||
memcpy(n + au_url->all_headers_len, ptr, len);
|
||||
au_url->all_headers_len += len;
|
||||
} else {
|
||||
ICECAST_LOG_ERROR("Can not allocate buffer for auth backend reply headers. BAD.");
|
||||
}
|
||||
if (strncasecmp (ptr, "icecast-auth-message: ", 22) == 0) {
|
||||
char *eol;
|
||||
snprintf(url->errormsg, sizeof(url->errormsg), "%s", (char*)ptr+22);
|
||||
eol = strchr(url->errormsg, '\r');
|
||||
if (eol == NULL)
|
||||
eol = strchr(url->errormsg, '\n');
|
||||
if (eol)
|
||||
*eol = '\0';
|
||||
} else {
|
||||
ICECAST_LOG_ERROR("Can not allocate authbackend_userdata. BAD.");
|
||||
}
|
||||
|
||||
ICECAST_LOG_DEBUG("Got header: %* #H", (int)(size * nmemb + 2), ptr);
|
||||
|
||||
if (url->auth_header && len >= url->auth_header_len && strncasecmp(ptr, url->auth_header, url->auth_header_len) == 0) {
|
||||
url->result = AUTH_OK;
|
||||
}
|
||||
|
||||
if (url->timelimit_header && len > url->timelimit_header_len && strncasecmp(ptr, url->timelimit_header, url->timelimit_header_len) == 0) {
|
||||
const char *input = ptr;
|
||||
unsigned int limit = 0;
|
||||
|
||||
if (len >= 2 && input[len - 2] == '\r' && input[len - 1] == '\n') {
|
||||
input += url->timelimit_header_len;
|
||||
|
||||
if (sscanf(input, "%u\r\n", &limit) == 1) {
|
||||
client->con->discon_time = time(NULL) + limit;
|
||||
} else {
|
||||
ICECAST_LOG_ERROR("Auth backend returned invalid timeline header: Can not parse limit");
|
||||
}
|
||||
} else {
|
||||
ICECAST_LOG_ERROR("Auth backend returned invalid timelimit header.");
|
||||
}
|
||||
}
|
||||
|
||||
return (int)bytes;
|
||||
if (len == 1) {
|
||||
const char *c = ptr;
|
||||
if (c[0] == '\r' || c[0] == '\n') {
|
||||
handle_returned_header__complete(auth_user);
|
||||
}
|
||||
} else if (len == 2) {
|
||||
const char *c = ptr;
|
||||
if ((c[0] == '\r' || c[0] == '\n') && (c[1] == '\r' || c[1] == '\n')) {
|
||||
handle_returned_header__complete(auth_user);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static auth_result url_remove_client(auth_client *auth_user)
|
||||
@ -250,6 +421,7 @@ static auth_result url_remove_client(auth_client *auth_user)
|
||||
url->removeurl, url->errormsg);
|
||||
|
||||
free(userpwd);
|
||||
auth_user_url_clear(auth_user);
|
||||
|
||||
return AUTH_OK;
|
||||
}
|
||||
@ -382,6 +554,7 @@ static auth_result url_add_client(auth_client *auth_user)
|
||||
res = curl_easy_perform(url->handle);
|
||||
|
||||
free(userpwd);
|
||||
auth_user_url_clear(auth_user);
|
||||
|
||||
if (res) {
|
||||
ICECAST_LOG_WARN("auth to server %s failed with %s",
|
||||
@ -427,43 +600,46 @@ int auth_get_url_auth(auth_t *authenticator, config_options_t *options)
|
||||
url_info = calloc(1, sizeof(auth_url));
|
||||
authenticator->state = url_info;
|
||||
|
||||
/* default headers */
|
||||
url_info->auth_header = strdup("icecast-auth-user: 1\r\n");
|
||||
url_info->timelimit_header = strdup("icecast-auth-timelimit:");
|
||||
|
||||
/* force auth thread to call function. this makes sure the auth_t is attached to client */
|
||||
authenticator->authenticate_client = url_add_client;
|
||||
|
||||
while(options) {
|
||||
if(strcmp(options->name, "username") == 0) {
|
||||
free(url_info->username);
|
||||
url_info->username = strdup(options->value);
|
||||
replace_string(&(url_info->username), options->value);
|
||||
} else if(strcmp(options->name, "password") == 0) {
|
||||
free(url_info->password);
|
||||
url_info->password = strdup(options->value);
|
||||
replace_string(&(url_info->password), options->value);
|
||||
} else if(strcmp(options->name, "headers") == 0) {
|
||||
free(url_info->pass_headers);
|
||||
url_info->pass_headers = strdup(options->value);
|
||||
replace_string(&(url_info->pass_headers), options->value);
|
||||
} else if(strcmp(options->name, "header_prefix") == 0) {
|
||||
free(url_info->prefix_headers);
|
||||
url_info->prefix_headers = strdup(options->value);
|
||||
replace_string(&(url_info->prefix_headers), options->value);
|
||||
} else if(strcmp(options->name, "client_add") == 0) {
|
||||
free(url_info->addurl);
|
||||
url_info->addurl = strdup(options->value);
|
||||
replace_string(&(url_info->addurl), options->value);
|
||||
} else if(strcmp(options->name, "client_remove") == 0) {
|
||||
authenticator->release_client = url_remove_client;
|
||||
free(url_info->removeurl);
|
||||
url_info->removeurl = strdup(options->value);
|
||||
replace_string(&(url_info->removeurl), options->value);
|
||||
} else if(strcmp(options->name, "action_add") == 0) {
|
||||
addaction = options->value;
|
||||
} else if(strcmp(options->name, "action_remove") == 0) {
|
||||
removeaction = options->value;
|
||||
} else if(strcmp(options->name, "auth_header") == 0) {
|
||||
free(url_info->auth_header);
|
||||
url_info->auth_header = strdup(options->value);
|
||||
replace_string(&(url_info->auth_header), options->value);
|
||||
} else if (strcmp(options->name, "timelimit_header") == 0) {
|
||||
free(url_info->timelimit_header);
|
||||
url_info->timelimit_header = strdup(options->value);
|
||||
replace_string(&(url_info->timelimit_header), options->value);
|
||||
} else if (strcmp(options->name, "header_auth") == 0) {
|
||||
replace_string(&(url_info->header_auth), options->value);
|
||||
util_strtolower(url_info->header_message);
|
||||
} else if (strcmp(options->name, "header_timelimit") == 0) {
|
||||
replace_string(&(url_info->header_timelimit), options->value);
|
||||
util_strtolower(url_info->header_message);
|
||||
} else if (strcmp(options->name, "header_message") == 0) {
|
||||
replace_string(&(url_info->header_message), options->value);
|
||||
util_strtolower(url_info->header_message);
|
||||
} else if (strcmp(options->name, "header_alter_action") == 0) {
|
||||
replace_string(&(url_info->header_alter_action), options->value);
|
||||
util_strtolower(url_info->header_alter_action);
|
||||
} else if (strcmp(options->name, "header_alter_argument") == 0) {
|
||||
replace_string(&(url_info->header_alter_argument), options->value);
|
||||
util_strtolower(url_info->header_alter_argument);
|
||||
} else {
|
||||
ICECAST_LOG_ERROR("Unknown option: %s", options->name);
|
||||
}
|
||||
@ -479,6 +655,22 @@ int auth_get_url_auth(auth_t *authenticator, config_options_t *options)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* default headers */
|
||||
if (url_info->auth_header) {
|
||||
ICECAST_LOG_WARN("You use old style auth option \"auth_header\". Please switch to new style option \"header_auth\".");
|
||||
} else if (!url_info->header_auth && !url_info->auth_header) {
|
||||
ICECAST_LOG_WARN("You do not have enabled old or new style auth option for auth status header. I will enable both. Please set \"header_auth\".");
|
||||
url_info->auth_header = strdup(DEFAULT_HEADER_OLD_RESULT);
|
||||
url_info->header_auth = strdup(DEFAULT_HEADER_NEW_RESULT);
|
||||
}
|
||||
if (url_info->timelimit_header) {
|
||||
ICECAST_LOG_WARN("You use old style auth option \"timelimit_header\". Please switch to new style option \"header_timelimit\".");
|
||||
} else if (!url_info->header_timelimit && !url_info->timelimit_header) {
|
||||
ICECAST_LOG_WARN("You do not have enabled old or new style auth option for auth timelimit header. I will enable both. Please set \"header_timelimit\".");
|
||||
url_info->timelimit_header = strdup(DEFAULT_HEADER_OLD_TIMELIMIT);
|
||||
url_info->timelimit_header = strdup(DEFAULT_HEADER_NEW_TIMELIMIT);
|
||||
}
|
||||
|
||||
if (url_info->auth_header)
|
||||
url_info->auth_header_len = strlen (url_info->auth_header);
|
||||
if (url_info->timelimit_header)
|
||||
|
45
src/client.c
45
src/client.c
@ -302,7 +302,7 @@ int client_read_bytes(client_t *client, void *buf, unsigned len)
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static inline void _client_send_error(client_t *client, const icecast_error_t *error)
|
||||
static inline void _client_send_report(client_t *client, const char *uuid, const char *message, int http_status, const char *location)
|
||||
{
|
||||
reportxml_t *report;
|
||||
admin_format_t admin_format;
|
||||
@ -325,17 +325,15 @@ static inline void _client_send_error(client_t *client, const icecast_error_t *e
|
||||
break;
|
||||
}
|
||||
|
||||
report = client_get_reportxml(uuid, NULL, message);
|
||||
|
||||
report = client_get_reportxml(error->uuid, NULL, error->message);
|
||||
|
||||
client_send_reportxml(client, report, DOCUMENT_DOMAIN_ADMIN, xslt, admin_format, error->http_status);
|
||||
client_send_reportxml(client, report, DOCUMENT_DOMAIN_ADMIN, xslt, admin_format, http_status, location);
|
||||
|
||||
refobject_unref(report);
|
||||
}
|
||||
|
||||
void client_send_error_by_id(client_t *client, icecast_error_id_t id)
|
||||
void client_send_error_by_error(client_t *client, const icecast_error_t *error)
|
||||
{
|
||||
const icecast_error_t *error = error_get_by_id(id);
|
||||
|
||||
if (!error) {
|
||||
client_send_500(client, "Unknown error ID");
|
||||
@ -347,7 +345,15 @@ void client_send_error_by_id(client_t *client, icecast_error_id_t id)
|
||||
return;
|
||||
}
|
||||
|
||||
_client_send_error(client, error);
|
||||
_client_send_report(client, error->uuid, error->message, error->http_status, NULL);
|
||||
}
|
||||
void client_send_error_by_uuid(client_t *client, const char *uuid)
|
||||
{
|
||||
client_send_error_by_error(client, error_get_by_uuid(uuid));
|
||||
}
|
||||
void client_send_error_by_id(client_t *client, icecast_error_id_t id)
|
||||
{
|
||||
client_send_error_by_error(client, error_get_by_id(id));
|
||||
}
|
||||
|
||||
void client_send_101(client_t *client, reuse_t reuse)
|
||||
@ -458,8 +464,13 @@ static inline void client_send_500(client_t *client, const char *message)
|
||||
client_destroy(client);
|
||||
}
|
||||
|
||||
void client_send_redirect(client_t *client, const char *uuid, int status, const char *location)
|
||||
{
|
||||
_client_send_report(client, uuid, "Redirecting", status, location);
|
||||
}
|
||||
|
||||
/* this function sends a reportxml file to the client in the prefered format. */
|
||||
void client_send_reportxml(client_t *client, reportxml_t *report, document_domain_t domain, const char *xsl, admin_format_t admin_format_hint, int status)
|
||||
void client_send_reportxml(client_t *client, reportxml_t *report, document_domain_t domain, const char *xsl, admin_format_t admin_format_hint, int status, const char *location)
|
||||
{
|
||||
admin_format_t admin_format;
|
||||
xmlDocPtr doc;
|
||||
@ -514,13 +525,18 @@ void client_send_reportxml(client_t *client, reportxml_t *report, document_domai
|
||||
|
||||
if (admin_format == ADMIN_FORMAT_RAW) {
|
||||
xmlChar *buff = NULL;
|
||||
size_t location_length = 0;
|
||||
int len = 0;
|
||||
size_t buf_len;
|
||||
ssize_t ret;
|
||||
|
||||
xmlDocDumpMemory(doc, &buff, &len);
|
||||
|
||||
buf_len = len + 1024;
|
||||
if (location) {
|
||||
location_length = strlen(location);
|
||||
}
|
||||
|
||||
buf_len = len + location_length + 1024;
|
||||
if (buf_len < 4096)
|
||||
buf_len = 4096;
|
||||
|
||||
@ -536,9 +552,9 @@ void client_send_reportxml(client_t *client, reportxml_t *report, document_domai
|
||||
client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED);
|
||||
xmlFree(buff);
|
||||
return;
|
||||
} else if (buf_len < (size_t)(len + ret + 64)) {
|
||||
} else if (buf_len < (size_t)(len + location_length + ret + 128)) {
|
||||
void *new_data;
|
||||
buf_len = ret + len + 64;
|
||||
buf_len = ret + len + 128;
|
||||
new_data = realloc(client->refbuf->data, buf_len);
|
||||
if (new_data) {
|
||||
ICECAST_LOG_DEBUG("Client buffer reallocation succeeded.");
|
||||
@ -563,7 +579,10 @@ void client_send_reportxml(client_t *client, reportxml_t *report, document_domai
|
||||
}
|
||||
|
||||
/* FIXME: in this section we hope no function will ever return -1 */
|
||||
ret += snprintf (client->refbuf->data + ret, buf_len - ret, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff);
|
||||
if (location) {
|
||||
ret += snprintf(client->refbuf->data + ret, buf_len - ret, "Location: %s\r\n", location);
|
||||
}
|
||||
ret += snprintf(client->refbuf->data + ret, buf_len - ret, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff);
|
||||
|
||||
client->refbuf->len = ret;
|
||||
xmlFree(buff);
|
||||
@ -598,7 +617,7 @@ void client_send_reportxml(client_t *client, reportxml_t *report, document_domai
|
||||
|
||||
ICECAST_LOG_DEBUG("Sending XSLT (%s)", fullpath_xslt_template);
|
||||
fastevent_emit(FASTEVENT_TYPE_CLIENT_SEND_RESPONSE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
|
||||
xslt_transform(doc, fullpath_xslt_template, client, status);
|
||||
xslt_transform(doc, fullpath_xslt_template, client, status, location);
|
||||
free(fullpath_xslt_template);
|
||||
}
|
||||
|
||||
|
@ -143,10 +143,12 @@ int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser);
|
||||
void client_complete(client_t *client);
|
||||
void client_destroy(client_t *client);
|
||||
void client_send_error_by_id(client_t *client, icecast_error_id_t id);
|
||||
void client_send_error_by_uuid(client_t *client, const char *uuid);
|
||||
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);
|
||||
void client_send_reportxml(client_t *client, reportxml_t *report, document_domain_t domain, const char *xsl, admin_format_t admin_format_hint, int status);
|
||||
void client_send_redirect(client_t *client, const char *uuid, int status, const char *location);
|
||||
void client_send_reportxml(client_t *client, reportxml_t *report, document_domain_t domain, const char *xsl, admin_format_t admin_format_hint, int status, const char *location);
|
||||
reportxml_t *client_get_reportxml(const char *state_definition, const char *state_akindof, const char *state_text);
|
||||
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);
|
||||
|
@ -105,6 +105,7 @@ static matchfile_t *banned_ip, *allowed_ip;
|
||||
|
||||
rwlock_t _source_shutdown_rwlock;
|
||||
|
||||
static int _update_admin_command(client_t *client);
|
||||
static void _handle_connection(void);
|
||||
static void get_tls_certificate(ice_config_t *config);
|
||||
|
||||
@ -1277,6 +1278,10 @@ static void _handle_authed_client(client_t *client, void *userdata, auth_result
|
||||
auth_stack_release(client->authstack);
|
||||
client->authstack = NULL;
|
||||
|
||||
/* Update admin parameters just in case auth changed our URI */
|
||||
if (_update_admin_command(client) == -1)
|
||||
return;
|
||||
|
||||
fastevent_emit(FASTEVENT_TYPE_CLIENT_AUTHED, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
|
||||
|
||||
if (result != AUTH_OK) {
|
||||
|
14
src/errors.c
14
src/errors.c
@ -10,6 +10,8 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
#include "errors.h"
|
||||
#include "logging.h"
|
||||
#define CATMODULE "errors"
|
||||
@ -150,3 +152,15 @@ const icecast_error_t * error_get_by_id(icecast_error_id_t id) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const icecast_error_t * error_get_by_uuid(const char *uuid)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < (sizeof(__errors)/sizeof(*__errors)); i++) {
|
||||
if (strcasecmp(__errors[i].uuid, uuid) == 0) {
|
||||
return &(__errors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -62,5 +62,6 @@ struct icecast_error_tag {
|
||||
typedef struct icecast_error_tag icecast_error_t;
|
||||
|
||||
const icecast_error_t * error_get_by_id(icecast_error_id_t id);
|
||||
const icecast_error_t * error_get_by_uuid(const char *uuid);
|
||||
|
||||
#endif /* __ERRORS_H__ */
|
||||
|
@ -1030,7 +1030,7 @@ void stats_transform_xslt(client_t *client)
|
||||
|
||||
doc = stats_get_xml(0, mount, client);
|
||||
|
||||
xslt_transform(doc, xslpath, client, 200);
|
||||
xslt_transform(doc, xslpath, client, 200, NULL);
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
free(xslpath);
|
||||
|
33
src/util.c
33
src/util.c
@ -17,6 +17,7 @@
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@ -1429,3 +1430,35 @@ int get_line(FILE *file, char *buf, size_t siz)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int replace_string(char **dst, const char *src)
|
||||
{
|
||||
char *n;
|
||||
|
||||
if (!dst)
|
||||
return -1;
|
||||
|
||||
if (src) {
|
||||
n = strdup(src);
|
||||
if (!n)
|
||||
return -1;
|
||||
} else {
|
||||
n = NULL;
|
||||
}
|
||||
|
||||
free(*dst);
|
||||
*dst = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int util_strtolower(char *str)
|
||||
{
|
||||
if (!str)
|
||||
return -1;
|
||||
|
||||
for (; *str; str++)
|
||||
*str = tolower(*str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -128,4 +128,7 @@ struct tm *localtime_r(const time_t *timep, struct tm *result);
|
||||
char *util_conv_string (const char *string, const char *in_charset, const char *out_charset);
|
||||
|
||||
int get_line(FILE *file, char *buf, size_t siz);
|
||||
|
||||
int replace_string(char **dst, const char *src);
|
||||
int util_strtolower(char *str);
|
||||
#endif /* __UTIL_H__ */
|
||||
|
19
src/xslt.c
19
src/xslt.c
@ -320,7 +320,7 @@ static inline void _send_error(client_t *client, icecast_error_id_t id, int old_
|
||||
client_send_error_by_id(client, id);
|
||||
}
|
||||
|
||||
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, int status)
|
||||
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, int status, const char *location)
|
||||
{
|
||||
xmlDocPtr res;
|
||||
xsltStylesheetPtr cur;
|
||||
@ -374,7 +374,14 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, in
|
||||
ssize_t ret;
|
||||
int failed = 0;
|
||||
refbuf_t *refbuf;
|
||||
size_t location_length = 0;
|
||||
ssize_t full_len = strlen(mediatype) + (ssize_t)len + (ssize_t)1024;
|
||||
|
||||
if (location) {
|
||||
location_length = strlen(location);
|
||||
full_len += location_length;
|
||||
}
|
||||
|
||||
if (full_len < 4096)
|
||||
full_len = 4096;
|
||||
refbuf = refbuf_new (full_len);
|
||||
@ -386,9 +393,9 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, in
|
||||
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
|
||||
_send_error(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED, status);
|
||||
} else {
|
||||
if ( full_len < (ret + (ssize_t)len + (ssize_t)64) ) {
|
||||
if ( full_len < (ret + (ssize_t)len + (ssize_t)128) ) {
|
||||
void *new_data;
|
||||
full_len = ret + (ssize_t)len + (ssize_t)64;
|
||||
full_len = ret + (ssize_t)len + (ssize_t)128;
|
||||
new_data = realloc(refbuf->data, full_len);
|
||||
if (new_data) {
|
||||
ICECAST_LOG_DEBUG("Client buffer reallocation succeeded.");
|
||||
@ -408,7 +415,11 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, in
|
||||
}
|
||||
|
||||
if (!failed) {
|
||||
snprintf(refbuf->data + ret, full_len - ret, "Content-Length: %d\r\n\r\n%s", len, string);
|
||||
/* FIXME: in this section we hope no function will ever return -1 */
|
||||
if (location) {
|
||||
ret += snprintf(refbuf->data + ret, full_len - ret, "Location: %s\r\n", location);
|
||||
}
|
||||
ret += snprintf(refbuf->data + ret, full_len - ret, "Content-Length: %d\r\n\r\n%s", len, string);
|
||||
|
||||
client->respcode = status;
|
||||
client_set_queue (client, NULL);
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
#include "icecasttypes.h"
|
||||
|
||||
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, int status);
|
||||
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, int status, const char *location);
|
||||
void xslt_initialize(void);
|
||||
void xslt_shutdown(void);
|
||||
void xslt_clear_cache(void);
|
||||
|
Loading…
Reference in New Issue
Block a user