From: Jaroslav Kysela Date: Wed, 14 Dec 2016 15:36:37 +0000 (+0100) Subject: access: implement change flags per ACL entry and allow to reset individual parameters... X-Git-Tag: v4.2.1~164 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cb10625ec743c14f85b75bf10e2f9873cc8a9e30;p=thirdparty%2Ftvheadend.git access: implement change flags per ACL entry and allow to reset individual parameters, fixes #4044 ... see Help for more details --- diff --git a/docs/class/access_entry.md b/docs/class/access_entry.md index cd64fd151..933b3abf8 100644 --- a/docs/class/access_entry.md +++ b/docs/class/access_entry.md @@ -3,11 +3,20 @@ is initially wide open**. Tvheadend verifies access by scanning through all enabled access control entries in sequence, from the top of the list to the bottom. The permission -flags, streaming profiles, DVR config profiles, channel tags and so on are -combined for all matching access entries. An access entry is said to match -if the username matches and the IP source address of the requesting peer -is within the prefix. There is also anonymous access, if the user is set -to asterisk. Only network prefix is matched then. +flags, streaming profiles, DVR config profiles, channel tags, channel +number ranges are combined for all matching access entries if allowed using +the change flag. If the parameter is empty (permission +flags, all types of profiles, channel tags and ranges) in an access +control entry and the parameter change flag is turned on, +the parameter (value, list or range) is cleared (unset). + +An access entry is said to match if the username matches and the IP +source address of the requesting peer is within the prefix. There is also +anonymous access, if the user is set to asterisk. Only network prefix is +matched then. + +*The order of entries is really important!* It is recommended to put the +wildcards on top of the entries and the special permissions to the bottom. !['Access Entries Grid'](static/img/doc/accessentriesgrid.png) diff --git a/src/access.c b/src/access.c index 8f1f179d8..dca749d85 100644 --- a/src/access.c +++ b/src/access.c @@ -527,96 +527,133 @@ access_update(access_t *a, access_entry_t *ae) const char *s; char ubuf[UUID_HEX_SIZE]; - switch (ae->ae_conn_limit_type) { - case ACCESS_CONN_LIMIT_TYPE_ALL: - if (a->aa_conn_limit < ae->ae_conn_limit) + if (ae->ae_change_conn_limit) { + switch (ae->ae_conn_limit_type) { + case ACCESS_CONN_LIMIT_TYPE_ALL: a->aa_conn_limit = ae->ae_conn_limit; - break; - case ACCESS_CONN_LIMIT_TYPE_STREAMING: - if (a->aa_conn_limit_streaming < ae->ae_conn_limit) + case ACCESS_CONN_LIMIT_TYPE_STREAMING: a->aa_conn_limit_streaming = ae->ae_conn_limit; - break; - case ACCESS_CONN_LIMIT_TYPE_DVR: - if (a->aa_conn_limit_dvr < ae->ae_conn_limit) + break; + case ACCESS_CONN_LIMIT_TYPE_DVR: a->aa_conn_limit_dvr = ae->ae_conn_limit; - break; + break; + } } - if(ae->ae_uilevel > a->aa_uilevel) + if (ae->ae_change_uilevel) { a->aa_uilevel = ae->ae_uilevel; - - if(a->aa_uilevel_nochange < 0) a->aa_uilevel_nochange = ae->ae_uilevel_nochange; - else if(a->aa_uilevel_nochange && !ae->ae_uilevel_nochange) - a->aa_uilevel_nochange = 0; - - if(ae->ae_chmin || ae->ae_chmax) { - uint64_t *p = realloc(a->aa_chrange, (a->aa_chrange_count + 2) * sizeof(uint64_t)); - if (p) { - p[a->aa_chrange_count++] = ae->ae_chmin; - p[a->aa_chrange_count++] = ae->ae_chmax; - a->aa_chrange = p; + } + + if (ae->ae_change_chrange) { + if (ae->ae_chmin || ae->ae_chmax) { + uint64_t *p = realloc(a->aa_chrange, (a->aa_chrange_count + 2) * sizeof(uint64_t)); + if (p) { + p[a->aa_chrange_count++] = ae->ae_chmin; + p[a->aa_chrange_count++] = ae->ae_chmax; + a->aa_chrange = p; + } + } else { + free(a->aa_chrange); + a->aa_chrange = NULL; } } - LIST_FOREACH(ilm, &ae->ae_profiles, ilm_in1_link) { - profile_t *pro = (profile_t *)ilm->ilm_in2; - if(pro && pro->pro_name && pro->pro_name[0] != '\0') { - if (a->aa_profiles == NULL) - a->aa_profiles = htsmsg_create_list(); - htsmsg_add_str_exclusive(a->aa_profiles, idnode_uuid_as_str(&pro->pro_id, ubuf)); + if (ae->ae_change_profiles) { + if (LIST_EMPTY(&ae->ae_profiles)) { + idnode_list_destroy(&ae->ae_profiles, ae); + } else { + LIST_FOREACH(ilm, &ae->ae_profiles, ilm_in1_link) { + profile_t *pro = (profile_t *)ilm->ilm_in2; + if(pro && pro->pro_name && pro->pro_name[0] != '\0') { + if (a->aa_profiles == NULL) + a->aa_profiles = htsmsg_create_list(); + htsmsg_add_str_exclusive(a->aa_profiles, idnode_uuid_as_str(&pro->pro_id, ubuf)); + } + } } } - LIST_FOREACH(ilm, &ae->ae_dvr_configs, ilm_in1_link) { - dvr_config_t *dvr = (dvr_config_t *)ilm->ilm_in2; - if(dvr && dvr->dvr_config_name[0] != '\0') { - if (a->aa_dvrcfgs == NULL) - a->aa_dvrcfgs = htsmsg_create_list(); - htsmsg_add_str_exclusive(a->aa_dvrcfgs, idnode_uuid_as_str(&dvr->dvr_id, ubuf)); - } + if (ae->ae_change_dvr_configs) { + if (LIST_EMPTY(&ae->ae_dvr_configs)) { + idnode_list_destroy(&ae->ae_dvr_configs, ae); + } else { + LIST_FOREACH(ilm, &ae->ae_dvr_configs, ilm_in1_link) { + dvr_config_t *dvr = (dvr_config_t *)ilm->ilm_in2; + if(dvr && dvr->dvr_config_name[0] != '\0') { + if (a->aa_dvrcfgs == NULL) + a->aa_dvrcfgs = htsmsg_create_list(); + htsmsg_add_str_exclusive(a->aa_dvrcfgs, idnode_uuid_as_str(&dvr->dvr_id, ubuf)); + } + } + } } - if (ae->ae_chtags_exclude) { - channel_tag_t *ct; - TAILQ_FOREACH(ct, &channel_tags, ct_link) { - if(ct && ct->ct_name[0] != '\0') { - LIST_FOREACH(ilm, &ae->ae_chtags, ilm_in1_link) { - channel_tag_t *ct2 = (channel_tag_t *)ilm->ilm_in2; - if (ct == ct2) break; - } - if (ilm == NULL) { - if (a->aa_chtags == NULL) - a->aa_chtags = htsmsg_create_list(); - htsmsg_add_str_exclusive(a->aa_chtags, idnode_uuid_as_str(&ct->ct_id, ubuf)); + if (ae->ae_change_chtags) { + if (ae->ae_chtags_exclude && !LIST_EMPTY(&ae->ae_chtags)) { + channel_tag_t *ct; + TAILQ_FOREACH(ct, &channel_tags, ct_link) { + if(ct && ct->ct_name[0] != '\0') { + LIST_FOREACH(ilm, &ae->ae_chtags, ilm_in1_link) { + channel_tag_t *ct2 = (channel_tag_t *)ilm->ilm_in2; + if (ct == ct2) break; + } + if (ilm == NULL) { + if (a->aa_chtags == NULL) + a->aa_chtags = htsmsg_create_list(); + htsmsg_add_str_exclusive(a->aa_chtags, idnode_uuid_as_str(&ct->ct_id, ubuf)); + } } } - } - } else { - LIST_FOREACH(ilm, &ae->ae_chtags, ilm_in1_link) { - channel_tag_t *ct = (channel_tag_t *)ilm->ilm_in2; - if(ct && ct->ct_name[0] != '\0') { - if (a->aa_chtags == NULL) - a->aa_chtags = htsmsg_create_list(); - htsmsg_add_str_exclusive(a->aa_chtags, idnode_uuid_as_str(&ct->ct_id, ubuf)); + } else { + if (LIST_EMPTY(&ae->ae_chtags)) { + idnode_list_destroy(&ae->ae_chtags, ae); + } else { + LIST_FOREACH(ilm, &ae->ae_chtags, ilm_in1_link) { + channel_tag_t *ct = (channel_tag_t *)ilm->ilm_in2; + if(ct && ct->ct_name[0] != '\0') { + if (a->aa_chtags == NULL) + a->aa_chtags = htsmsg_create_list(); + htsmsg_add_str_exclusive(a->aa_chtags, idnode_uuid_as_str(&ct->ct_id, ubuf)); + } + } } } } - if (!a->aa_lang && ae->ae_lang && ae->ae_lang[0]) - a->aa_lang = lang_code_user(ae->ae_lang); + if (ae->ae_change_lang) { + free(a->aa_lang); + if (ae->ae_lang && ae->ae_lang[0]) { + a->aa_lang = lang_code_user(ae->ae_lang); + } else { + a->aa_lang = NULL; + } + } - if (!a->aa_lang_ui) { + if (ae->ae_change_lang_ui) { + free(ae->ae_lang_ui); if (ae->ae_lang_ui && ae->ae_lang_ui[0]) a->aa_lang_ui = lang_code_user(ae->ae_lang_ui); else if ((s = config_get_language_ui()) != NULL) a->aa_lang_ui = lang_code_user(s); + else + a->aa_lang_ui = NULL; } - if ((!a->aa_theme || a->aa_theme[0] == '\0') && ae->ae_theme && ae->ae_theme[0]) - a->aa_theme = strdup(ae->ae_theme); + if (ae->ae_change_theme) { + free(a->aa_theme); + if (ae->ae_theme && ae->ae_theme[0]) + a->aa_theme = strdup(ae->ae_theme); + else + a->aa_theme = NULL; + } - a->aa_rights |= ae->ae_rights; + if (ae->ae_change_rights) { + if (ae->ae_rights == 0) + a->aa_rights = 0; + else + a->aa_rights |= ae->ae_rights; + } } /** @@ -1007,6 +1044,16 @@ access_entry_create(const char *uuid, htsmsg_t *conf) if (conf) { /* defaults */ + ae->ae_change_lang = 1; + ae->ae_change_lang_ui = 1; + ae->ae_change_theme = 1; + ae->ae_change_uilevel = 1; + ae->ae_change_profiles = 1; + ae->ae_change_conn_limit = 1; + ae->ae_change_dvr_configs = 1; + ae->ae_change_chrange = 1; + ae->ae_change_chtags = 1; + ae->ae_change_rights = 1; ae->ae_htsp_streaming = 1; ae->ae_htsp_dvr = 1; ae->ae_all_dvr = 1; @@ -1363,6 +1410,84 @@ theme_get_ui_list ( void *p, const char *lang ) return strtab2htsmsg_str(tab, 1, lang); } +static idnode_slist_t access_entry_class_change_slist[] = { + { + .id = "change_rights", + .name = N_("Rights"), + .off = offsetof(access_entry_t, ae_change_rights), + }, + { + .id = "change_chrange", + .name = N_("Channel range"), + .off = offsetof(access_entry_t, ae_change_chrange), + }, + { + .id = "change_chtags", + .name = N_("Channel tags"), + .off = offsetof(access_entry_t, ae_change_chtags), + }, + { + .id = "change_dvr_configs", + .name = N_("DVR configurations"), + .off = offsetof(access_entry_t, ae_change_dvr_configs), + }, + { + .id = "change_profiles", + .name = N_("Streaming profiles"), + .off = offsetof(access_entry_t, ae_change_profiles), + }, + { + .id = "change_conn_limit", + .name = N_("Connection limits"), + .off = offsetof(access_entry_t, ae_change_conn_limit), + }, + { + .id = "change_lang", + .name = N_("Language"), + .off = offsetof(access_entry_t, ae_change_lang), + }, + { + .id = "change_lang_ui", + .name = N_("Web interface language"), + .off = offsetof(access_entry_t, ae_change_lang_ui), + }, + { + .id = "change_theme", + .name = N_("Theme"), + .off = offsetof(access_entry_t, ae_change_theme), + }, + { + .id = "change_uilevel", + .name = N_("User interface level"), + .off = offsetof(access_entry_t, ae_change_uilevel), + }, + {} +}; + +static htsmsg_t * +access_entry_class_change_enum ( void *obj, const char *lang ) +{ + return idnode_slist_enum(obj, access_entry_class_change_slist, lang); +} + +static const void * +access_entry_class_change_get ( void *obj ) +{ + return idnode_slist_get(obj, access_entry_class_change_slist); +} + +static char * +access_entry_class_change_rend ( void *obj, const char *lang ) +{ + return idnode_slist_rend(obj, access_entry_class_change_slist, lang); +} + +static int +access_entry_class_change_set ( void *obj, const void *p ) +{ + return idnode_slist_set(obj, access_entry_class_change_slist, p); +} + CLASS_DOC(access_entry) PROP_DOC(viewlevel_access_entries) PROP_DOC(themes) @@ -1413,6 +1538,18 @@ const idclass_t access_entry_class = { .get = access_entry_class_prefix_get, .opts = PO_ADVANCED }, + { + .type = PT_INT, + .islist = 1, + .id = "change", + .name = N_("Change parameters"), + .desc = N_("Specify the parameters to be changed."), + .list = access_entry_class_change_enum, + .get = access_entry_class_change_get, + .set = access_entry_class_change_set, + .rend = access_entry_class_change_rend, + .opts = PO_DOC_NLIST, + }, { .type = PT_INT, .id = "uilevel", diff --git a/src/access.h b/src/access.h index b2498fb05..ed5bfebc9 100644 --- a/src/access.h +++ b/src/access.h @@ -97,13 +97,17 @@ typedef struct access_entry { char *ae_username; char *ae_comment; char *ae_lang; + int ae_change_lang; char *ae_lang_ui; + int ae_change_lang_ui; char *ae_theme; + int ae_change_theme; int ae_index; int ae_wizard; int ae_enabled; int ae_uilevel; + int ae_change_uilevel; int ae_uilevel_nochange; int ae_streaming; @@ -111,9 +115,11 @@ typedef struct access_entry { int ae_htsp_streaming; idnode_list_head_t ae_profiles; + int ae_change_profiles; int ae_conn_limit_type; uint32_t ae_conn_limit; + int ae_change_conn_limit; int ae_dvr; int ae_htsp_dvr; @@ -124,16 +130,20 @@ typedef struct access_entry { int ae_htsp_anonymize; idnode_list_head_t ae_dvr_configs; + int ae_change_dvr_configs; int ae_webui; int ae_admin; uint64_t ae_chmin; uint64_t ae_chmax; + int ae_change_chrange; int ae_chtags_exclude; idnode_list_head_t ae_chtags; + int ae_change_chtags; + int ae_change_rights; uint32_t ae_rights; struct access_ipmask_queue ae_ipmasks; diff --git a/src/webui/static/app/acleditor.js b/src/webui/static/app/acleditor.js index 8d68df227..e0be7fea2 100644 --- a/src/webui/static/app/acleditor.js +++ b/src/webui/static/app/acleditor.js @@ -4,7 +4,7 @@ tvheadend.acleditor = function(panel, index) { - var list = 'enabled,username,password,prefix,' + + var list = 'enabled,username,password,prefix,change,' + 'lang,webui,uilevel,uilevel_nochange,admin,' + 'streaming,adv_streaming,htsp_streaming,' + 'profile,conn_limit_type,conn_limit,' + @@ -12,7 +12,7 @@ tvheadend.acleditor = function(panel, index) 'dvr_config,channel_min,channel_max,' + 'channel_tag_exclude,channel_tag,comment'; - var list2 = 'enabled,username,password,prefix,' + + var list2 = 'enabled,username,password,prefix,change,' + 'lang,webui,themeui,langui,uilevel,uilevel_nochange,admin,' + 'streaming,adv_streaming,htsp_streaming,' + 'profile,conn_limit_type,conn_limit,' + @@ -32,6 +32,7 @@ tvheadend.acleditor = function(panel, index) username: { width: 250 }, password: { width: 250 }, prefix: { width: 350 }, + change: { width: 350 }, streaming: { width: 110 }, adv_streaming: { width: 200 }, htsp_streaming: { width: 200 },