1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2025-02-02 15:07:36 -05:00

Feature: Added basic support for auth backends to manipulate the client

This commit is contained in:
Philipp Schafft 2018-09-14 13:39:50 +00:00
parent dabf9337a6
commit 4d7a60d588
11 changed files with 166 additions and 23 deletions

View File

@ -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);
}
}

View File

@ -227,9 +227,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 +297,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 +366,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) {
@ -743,6 +799,20 @@ 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;
/* TODO: check if auth backend has the permission for this operation */
if (replace_string(&(auth_user->alter_client_arg), arg) != 0)
return -1;
auth_user->alter_client_action = action;
return 0;
}
/* these are called at server start and termination */

View File

@ -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,8 @@ 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;
auth_alter_t alter_client_action;
char *alter_client_arg;
auth_client *next;
};
@ -154,6 +173,8 @@ 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);
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 */

View File

@ -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);
}

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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);

View File

@ -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);

View File

@ -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);