diff --git a/src/auth.c b/src/auth.c index a08fc063..7ffd7d20 100644 --- a/src/auth.c +++ b/src/auth.c @@ -368,6 +368,7 @@ static void *auth_run_thread (void *arg) */ static void auth_add_client(auth_t *auth, client_t *client, 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_client *auth_user; + auth_matchtype_t matchtype; ICECAST_LOG_DEBUG("Trying to add client %p to auth %p's (role %s) queue.", client, auth, auth->role); @@ -387,6 +388,34 @@ static void auth_add_client(auth_t *auth, client_t *client, void (*on_no_match)( return; } + if (client->admin_command == ADMIN_COMMAND_ERROR) { + /* this is a web/ client */ + matchtype = auth->filter_web_policy; + } else { + /* this is a admin/ client */ + size_t i; + + matchtype = AUTH_MATCHTYPE_UNUSED; + + for (i = 0; i < (sizeof(auth->filter_admin)/sizeof(*(auth->filter_admin))); i++) { + if (auth->filter_admin[i].type != AUTH_MATCHTYPE_UNUSED && auth->filter_admin[i].command == client->admin_command) { + matchtype = auth->filter_admin[i].type; + break; + } + } + + if (matchtype == AUTH_MATCHTYPE_UNUSED) + matchtype = auth->filter_admin_policy; + } + if (matchtype == AUTH_MATCHTYPE_NOMATCH) { + if (on_no_match) { + on_no_match(client, on_result, userdata); + } else if (on_result) { + on_result(client, userdata, AUTH_NOMATCH); + } + return; + } + auth_release(client->auth); auth_addref(client->auth = auth); auth_user = auth_client_setup(client); @@ -472,13 +501,56 @@ static int get_authenticator (auth_t *auth, config_options_t *options) } +static inline void auth_get_authenticator__filter_admin(auth_t *auth, xmlNodePtr node, size_t *filter_admin_index, const char *name, auth_matchtype_t matchtype) +{ + char * tmp = (char*)xmlGetProp(node, XMLSTR(name)); + + if (tmp) { + char *cur = tmp; + char *next; + + while (cur) { + next = strstr(cur, ","); + if (next) { + *next = 0; + next++; + for (; *next == ' '; next++); + } + + if (*filter_admin_index < (sizeof(auth->filter_admin)/sizeof(*(auth->filter_admin)))) { + auth->filter_admin[*filter_admin_index].command = admin_get_command(cur); + switch (auth->filter_admin[*filter_admin_index].command) { + case ADMIN_COMMAND_ERROR: + ICECAST_LOG_ERROR("Can not add unknown %s command to role.", name); + break; + case ADMIN_COMMAND_ANY: + auth->filter_admin_policy = matchtype; + break; + default: + auth->filter_admin[*filter_admin_index].type = matchtype; + (*filter_admin_index)++; + break; + } + } else { + ICECAST_LOG_ERROR("Can not add more %s commands to role.", name); + } + + cur = next; + } + + free(tmp); + } +} + auth_t *auth_get_authenticator(xmlNodePtr node) { auth_t *auth = calloc(1, sizeof(auth_t)); config_options_t *options = NULL, **next_option = &options; xmlNodePtr option; char *method; + char *tmp; size_t i; + size_t filter_admin_index = 0; if (auth == NULL) return NULL; @@ -489,6 +561,13 @@ auth_t *auth_get_authenticator(xmlNodePtr node) auth->type = (char*)xmlGetProp(node, XMLSTR("type")); auth->role = (char*)xmlGetProp(node, XMLSTR("name")); auth->management_url = (char*)xmlGetProp(node, XMLSTR("management-url")); + auth->filter_web_policy = AUTH_MATCHTYPE_MATCH; + auth->filter_admin_policy = AUTH_MATCHTYPE_MATCH; + + for (i = 0; i < (sizeof(auth->filter_admin)/sizeof(*(auth->filter_admin))); i++) { + auth->filter_admin[i].type = AUTH_MATCHTYPE_UNUSED; + auth->filter_admin[i].command = ADMIN_COMMAND_ERROR; + } if (!auth->type) { auth_release(auth); @@ -535,6 +614,29 @@ auth_t *auth_get_authenticator(xmlNodePtr node) auth->method[i] = 1; } + tmp = (char*)xmlGetProp(node, XMLSTR("match-web")); + if (tmp) { + if (strcmp(tmp, "*") == 0) { + auth->filter_web_policy = AUTH_MATCHTYPE_MATCH; + } else { + auth->filter_web_policy = AUTH_MATCHTYPE_NOMATCH; + } + free(tmp); + } + + tmp = (char*)xmlGetProp(node, XMLSTR("nomatch-web")); + if (tmp) { + if (strcmp(tmp, "*") == 0) { + auth->filter_web_policy = AUTH_MATCHTYPE_NOMATCH; + } else { + auth->filter_web_policy = AUTH_MATCHTYPE_MATCH; + } + free(tmp); + } + + 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); + /* BEFORE RELEASE 2.5.0 TODO: Migrate this to config_parse_options(). */ option = node->xmlChildrenNode; while (option) diff --git a/src/auth.h b/src/auth.h index 12a0b17c..dd4d87f3 100644 --- a/src/auth.h +++ b/src/auth.h @@ -34,6 +34,8 @@ #define AUTH_TYPE_URL "url" #define AUTH_TYPE_HTPASSWD "htpasswd" +#define MAX_ADMIN_COMMANDS 32 + typedef enum { /* XXX: ??? */ @@ -54,6 +56,15 @@ typedef enum AUTH_USERDELETED } auth_result; +typedef enum { + /* The slot is not used */ + AUTH_MATCHTYPE_UNUSED, + /* Match on this slot */ + AUTH_MATCHTYPE_MATCH, + /* Do not match on this slot */ + AUTH_MATCHTYPE_NOMATCH +} auth_matchtype_t; + typedef struct auth_client_tag { client_t *client; @@ -77,6 +88,12 @@ struct auth_tag /* filters */ int method[httpp_req_unknown+1]; + auth_matchtype_t filter_web_policy; + auth_matchtype_t filter_admin_policy; + struct { + auth_matchtype_t type; + admin_command_id_t command; + } filter_admin[MAX_ADMIN_COMMANDS]; /* whether authenticate_client() and release_client() will return immediate. * Setting this will result in no thread being started for this.