diff --git a/src/admin.c b/src/admin.c index 9c072697..bfc57cc6 100644 --- a/src/admin.c +++ b/src/admin.c @@ -594,7 +594,7 @@ void admin_handle_request(client_t *client, const char *uri) "client because it is allowed to do SOURCE or PUT."); } else { ICECAST_LOG_DEBUG("Client needs to authenticate."); - client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE); + auth_reject_client_on_deny(client); return; } } diff --git a/src/auth.c b/src/auth.c index 5fb57d6c..5a550ac0 100644 --- a/src/auth.c +++ b/src/auth.c @@ -212,6 +212,10 @@ void auth_release (auth_t *authenticator) { xmlFree (authenticator->role); if (authenticator->management_url) xmlFree (authenticator->management_url); + if (authenticator->failed_arg) + xmlFree (authenticator->failed_arg); + if (authenticator->deny_arg) + xmlFree (authenticator->deny_arg); thread_mutex_unlock(&authenticator->lock); thread_mutex_destroy(&authenticator->lock); if (authenticator->mount) @@ -311,23 +315,18 @@ 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) +static inline int __handle_auth_client_alter(client_t *client, auth_alter_t action, const char *arg) { - 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) { + switch (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; + util_replace_string(&(client->uri), arg); return 0; break; case AUTH_ALTER_REDIRECT: @@ -335,20 +334,20 @@ static inline int __handle_auth_client_alter(auth_t *auth, auth_client *auth_use case AUTH_ALTER_REDIRECT_SEE_OTHER: uuid = "be7fac90-54fb-4673-9e0d-d15d6a4963a2"; http_status = 303; - location = auth_user->alter_client_arg; + location = arg; break; case AUTH_ALTER_REDIRECT_TEMPORARY: uuid = "4b08a03a-ecce-4981-badf-26b0bb6c9d9c"; http_status = 307; - location = auth_user->alter_client_arg; + location = arg; break; case AUTH_ALTER_REDIRECT_PERMANENT: uuid = "36bf6815-95cb-4cc8-a7b0-6b4b0c82ac5d"; http_status = 308; - location = auth_user->alter_client_arg; + location = arg; break; case AUTH_ALTER_SEND_ERROR: - client_send_error_by_uuid(client, auth_user->alter_client_arg); + client_send_error_by_uuid(client, arg); return 1; break; } @@ -360,6 +359,7 @@ static inline int __handle_auth_client_alter(auth_t *auth, auth_client *auth_use return -1; } + static void __handle_auth_client (auth_t *auth, auth_client *auth_user) { auth_result result; @@ -381,7 +381,7 @@ static void __handle_auth_client (auth_t *auth, auth_client *auth_user) { } if (result != AUTH_NOMATCH) { - if (__handle_auth_client_alter(auth, auth_user) == 1) + if (__handle_auth_client_alter(auth_user->client, auth_user->alter_client_action, auth_user->alter_client_arg) == 1) return; } @@ -817,6 +817,8 @@ auth_t *auth_get_authenticator(xmlNodePtr node) auth->management_url = (char*)xmlGetProp(node, XMLSTR("management-url")); auth->filter_web_policy = AUTH_MATCHTYPE_MATCH; auth->filter_admin_policy = AUTH_MATCHTYPE_MATCH; + auth->failed_arg = AUTH_ALTER_NOOP; + auth->deny_arg = AUTH_ALTER_NOOP; for (i = 0; i < (sizeof(auth->filter_admin)/sizeof(*(auth->filter_admin))); i++) { auth->filter_admin[i].type = AUTH_MATCHTYPE_UNUSED; @@ -936,6 +938,32 @@ auth_t *auth_get_authenticator(xmlNodePtr node) } else { ICECAST_LOG_ERROR("More than one ACL defined in role! Not supported (yet)."); } + } else if (xmlStrcmp (child->name, XMLSTR("on-failed-action")) == 0) { + tmp = (char *)xmlNodeListGetString(child->doc, child->xmlChildrenNode, 1); + if (tmp) { + auth->failed_action = auth_str2alter(tmp); + if (auth->failed_action == AUTH_ALTER_NOOP) { + ICECAST_LOG_WARN("Can not parse with value: %s", tmp); + } + xmlFree(tmp); + } + } else if (xmlStrcmp (child->name, XMLSTR("on-failed-argument")) == 0) { + if (auth->failed_arg) + xmlFree(auth->failed_arg); + auth->failed_arg = (char *)xmlNodeListGetString(child->doc, child->xmlChildrenNode, 1); + } else if (xmlStrcmp (child->name, XMLSTR("on-deny-action")) == 0) { + tmp = (char *)xmlNodeListGetString(child->doc, child->xmlChildrenNode, 1); + if (tmp) { + auth->deny_action = auth_str2alter(tmp); + if (auth->deny_action == AUTH_ALTER_NOOP) { + ICECAST_LOG_WARN("Can not parse with value: %s", tmp); + } + xmlFree(tmp); + } + } else if (xmlStrcmp (child->name, XMLSTR("on-deny-argument")) == 0) { + if (auth->deny_arg) + xmlFree(auth->deny_arg); + auth->deny_arg = (char *)xmlNodeListGetString(child->doc, child->xmlChildrenNode, 1); } else { ICECAST_LOG_WARN("unknown auth setting (%H)", child->name); } @@ -1213,3 +1241,39 @@ acl_t *auth_stack_get_anonymous_acl(auth_stack_t *stack, httpp_request_ty return ret; } + + +static void auth_reject_client(client_t *client, int fail) +{ + auth_t *auth; + + if (!client) + return; + + auth = client->auth; + if (auth) { + if (fail) { + if (__handle_auth_client_alter(client, auth->failed_action, auth->failed_arg) == 1) + return; + } else { + if (__handle_auth_client_alter(client, auth->deny_action, auth->deny_arg) == 1) + return; + } + } + + if (client->protocol == ICECAST_PROTOCOL_SHOUTCAST) { + client_destroy(client); + } else { + client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE); + } +} + +void auth_reject_client_on_fail(client_t *client) +{ + auth_reject_client(client, 1); +} + +void auth_reject_client_on_deny(client_t *client) +{ + auth_reject_client(client, 0); +} diff --git a/src/auth.h b/src/auth.h index c6f1463c..cacd9e99 100644 --- a/src/auth.h +++ b/src/auth.h @@ -124,6 +124,14 @@ struct auth_tag size_t filter_origin_len; auth_matchtype_t filter_origin_policy; + /* Action on failed if any */ + auth_alter_t failed_action; + char *failed_arg; + + /* Action on deny if any */ + auth_alter_t deny_action; + char *deny_arg; + /* permissions */ auth_matchtype_t permission_alter[AUTH_ALTER_SEND_ERROR+1]; @@ -203,4 +211,8 @@ auth_t *auth_stack_get(auth_stack_t *stack); auth_t *auth_stack_getbyid(auth_stack_t *stack, unsigned long id); acl_t *auth_stack_get_anonymous_acl(auth_stack_t *stack, httpp_request_type_e method); +/* Rejects a client based on auth results. */ +void auth_reject_client_on_fail(client_t *client); +void auth_reject_client_on_deny(client_t *client); + #endif diff --git a/src/connection.c b/src/connection.c index d825e249..373e5cd1 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1030,11 +1030,7 @@ static void _handle_get_request(client_t *client) { /* 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 :( */ - if (client->protocol == ICECAST_PROTOCOL_SHOUTCAST) { - client_destroy(client); - } else { - client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE); - } + auth_reject_client_on_deny(client); return; } @@ -1334,13 +1330,13 @@ static void _handle_authed_client(client_t *client, void *userdata, auth_result fastevent_emit(FASTEVENT_TYPE_CLIENT_AUTHED, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client); if (result != AUTH_OK) { - client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE); + auth_reject_client_on_fail(client); return; } if (acl_test_method(client->acl, client->parser->req_type) != ACL_POLICY_ALLOW) { ICECAST_LOG_ERROR("Client (role=%s, acl=%s, username=%s) not allowed to use this request method on %H", client->role, acl_get_name(client->acl), client->username, client->uri); - client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE); + auth_reject_client_on_deny(client); return; }