From 4b7a674e7f834c6471cdc25adea291323db4cc2b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 16 Oct 2014 11:03:22 +0200 Subject: [PATCH] ACL: add more restrictive permissions for all config urls, fix the http ticket issue, fixes #2383 --- src/access.c | 1 + src/api/api_access.c | 6 ++-- src/api/api_mpegts.c | 30 ++++++++++---------- src/api/api_service.c | 4 +-- src/esfilter.c | 2 ++ src/http.c | 19 ++++++------- src/http.h | 1 - src/idnode.c | 16 +++++++++++ src/idnode.h | 9 ++---- src/input/mpegts/mpegts_input.c | 2 ++ src/input/mpegts/mpegts_mux.c | 3 ++ src/input/mpegts/mpegts_network.c | 4 ++- src/main.c | 13 ++------- src/profile.c | 4 ++- src/service.c | 2 ++ src/webui/static/app/acleditor.js | 2 +- src/webui/static/app/caclient.js | 19 +++++++------ src/webui/static/app/esfilter.js | 18 ++++++------ src/webui/static/app/mpegts.js | 46 +++++++++++++++---------------- src/webui/static/app/tvheadend.js | 8 ++---- 20 files changed, 111 insertions(+), 98 deletions(-) diff --git a/src/access.c b/src/access.c index 27f6dec8..7fc9ae9c 100644 --- a/src/access.c +++ b/src/access.c @@ -1030,6 +1030,7 @@ const idclass_t access_entry_class = { .ic_class = "access", .ic_caption = "Access", .ic_event = "access", + .ic_perm_def = ACCESS_ADMIN, .ic_save = access_entry_class_save, .ic_get_title = access_entry_class_get_title, .ic_delete = access_entry_class_delete, diff --git a/src/api/api_access.c b/src/api/api_access.c index 15d87214..63f98398 100644 --- a/src/api/api_access.c +++ b/src/api/api_access.c @@ -52,9 +52,9 @@ api_access_entry_create void api_access_init ( void ) { static api_hook_t ah[] = { - { "access/entry/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&access_entry_class }, - { "access/entry/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_access_entry_grid }, - { "access/entry/create", ACCESS_ADMIN, api_access_entry_create, NULL }, + { "access/entry/class", ACCESS_ADMIN, api_idnode_class, (void*)&access_entry_class }, + { "access/entry/grid", ACCESS_ADMIN, api_idnode_grid, api_access_entry_grid }, + { "access/entry/create", ACCESS_ADMIN, api_access_entry_create, NULL }, { NULL }, }; diff --git a/src/api/api_mpegts.c b/src/api/api_mpegts.c index 618ae683..30e8a017 100644 --- a/src/api/api_mpegts.c +++ b/src/api/api_mpegts.c @@ -347,22 +347,22 @@ api_mpegts_init ( void ) extern const idclass_t mpegts_service_class; static api_hook_t ah[] = { - { "mpegts/input/network_list", ACCESS_ANONYMOUS, api_mpegts_input_network_list, NULL }, - { "mpegts/network/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_mpegts_network_grid }, - { "mpegts/network/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&mpegts_network_class }, - { "mpegts/network/builders", ACCESS_ANONYMOUS, api_mpegts_network_builders, NULL }, - { "mpegts/network/create", ACCESS_ANONYMOUS, api_mpegts_network_create, NULL }, - { "mpegts/network/mux_class", ACCESS_ANONYMOUS, api_mpegts_network_muxclass, NULL }, - { "mpegts/network/mux_create", ACCESS_ANONYMOUS, api_mpegts_network_muxcreate, NULL }, - { "mpegts/mux/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_mpegts_mux_grid }, - { "mpegts/mux/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&mpegts_mux_class }, - { "mpegts/service/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_mpegts_service_grid }, - { "mpegts/service/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&mpegts_service_class }, - { "mpegts/mux_sched/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&mpegts_mux_sched_class }, - { "mpegts/mux_sched/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_mpegts_mux_sched_grid }, - { "mpegts/mux_sched/create", ACCESS_ANONYMOUS, api_mpegts_mux_sched_create, NULL }, + { "mpegts/input/network_list", ACCESS_ADMIN, api_mpegts_input_network_list, NULL }, + { "mpegts/network/grid", ACCESS_ADMIN, api_idnode_grid, api_mpegts_network_grid }, + { "mpegts/network/class", ACCESS_ADMIN, api_idnode_class, (void*)&mpegts_network_class }, + { "mpegts/network/builders", ACCESS_ADMIN, api_mpegts_network_builders, NULL }, + { "mpegts/network/create", ACCESS_ADMIN, api_mpegts_network_create, NULL }, + { "mpegts/network/mux_class", ACCESS_ADMIN, api_mpegts_network_muxclass, NULL }, + { "mpegts/network/mux_create", ACCESS_ADMIN, api_mpegts_network_muxcreate, NULL }, + { "mpegts/mux/grid", ACCESS_ADMIN, api_idnode_grid, api_mpegts_mux_grid }, + { "mpegts/mux/class", ACCESS_ADMIN, api_idnode_class, (void*)&mpegts_mux_class }, + { "mpegts/service/grid", ACCESS_ADMIN, api_idnode_grid, api_mpegts_service_grid }, + { "mpegts/service/class", ACCESS_ADMIN, api_idnode_class, (void*)&mpegts_service_class }, + { "mpegts/mux_sched/class", ACCESS_ADMIN, api_idnode_class, (void*)&mpegts_mux_sched_class }, + { "mpegts/mux_sched/grid", ACCESS_ADMIN, api_idnode_grid, api_mpegts_mux_sched_grid }, + { "mpegts/mux_sched/create", ACCESS_ADMIN, api_mpegts_mux_sched_create, NULL }, #if ENABLE_MPEGTS_DVB - { "dvb/scanfile/list", ACCESS_ANONYMOUS, api_dvb_scanfile_list, NULL }, + { "dvb/scanfile/list", ACCESS_ADMIN, api_dvb_scanfile_list, NULL }, #endif { NULL }, }; diff --git a/src/api/api_service.c b/src/api/api_service.c index 3cc822ea..38012e42 100644 --- a/src/api/api_service.c +++ b/src/api/api_service.c @@ -189,9 +189,9 @@ void api_service_init ( void ) { "service/mapper/start", ACCESS_ADMIN, api_mapper_start, NULL }, { "service/mapper/stop", ACCESS_ADMIN, api_mapper_stop, NULL }, { "service/mapper/status", ACCESS_ADMIN, api_mapper_status, NULL }, - { "service/list", ACCESS_ANONYMOUS, api_idnode_load_by_class, + { "service/list", ACCESS_ADMIN, api_idnode_load_by_class, (void*)&service_class }, - { "service/streams", ACCESS_ANONYMOUS, api_service_streams, NULL }, + { "service/streams", ACCESS_ADMIN, api_service_streams, NULL }, { NULL }, }; diff --git a/src/esfilter.c b/src/esfilter.c index 0f72938b..802e0e5d 100644 --- a/src/esfilter.c +++ b/src/esfilter.c @@ -20,6 +20,7 @@ #include "settings.h" #include "lang_codes.h" #include "service.h" +#include "access.h" #include "esfilter.h" struct esfilter_entry_queue esfilters[ESF_CLASS_LAST + 1]; @@ -588,6 +589,7 @@ const idclass_t esfilter_class = { .ic_class = "esfilter", .ic_caption = "Elementary Stream Filter", .ic_event = "esfilter", + .ic_perm_def = ACCESS_ADMIN, .ic_save = esfilter_class_save, .ic_get_title = esfilter_class_get_title, .ic_delete = esfilter_class_delete, diff --git a/src/http.c b/src/http.c index 1959b9dc..1f42111b 100644 --- a/src/http.c +++ b/src/http.c @@ -408,22 +408,21 @@ http_redirect(http_connection_t *hc, const char *location, /** * */ -static int http_access_verify_ticket(http_connection_t *hc) +static void +http_access_verify_ticket(http_connection_t *hc) { const char *ticket_id; - if (hc->hc_ticket || hc->hc_access) - return 0; + if (hc->hc_access) + return; ticket_id = http_arg_get(&hc->hc_req_args, "ticket"); hc->hc_access = access_ticket_verify2(ticket_id, hc->hc_url); if (hc->hc_access == NULL) - return -1; + return; char addrstr[50]; tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrstr, 50); tvhlog(LOG_INFO, "HTTP", "%s: using ticket %s for %s", addrstr, ticket_id, hc->hc_url); - hc->hc_ticket = 1; - return 0; } /** @@ -432,8 +431,7 @@ static int http_access_verify_ticket(http_connection_t *hc) int http_access_verify(http_connection_t *hc, int mask) { - if (!http_access_verify_ticket(hc)) - return 0; + http_access_verify_ticket(hc); if (hc->hc_access == NULL) { hc->hc_access = access_get(hc->hc_username, hc->hc_password, @@ -456,8 +454,8 @@ http_access_verify_channel(http_connection_t *hc, int mask, assert(ch); - if (ticket && !http_access_verify_ticket(hc)) - return 0; + if (ticket) + http_access_verify_ticket(hc); if (hc->hc_access == NULL) { hc->hc_access = access_get(hc->hc_username, hc->hc_password, @@ -488,7 +486,6 @@ http_exec(http_connection_t *hc, http_path_t *hp, char *remain) err = hp->hp_callback(hc, remain, hp->hp_opaque); access_destroy(hc->hc_access); hc->hc_access = NULL; - hc->hc_ticket = 0; if(err == -1) return 1; diff --git a/src/http.h b/src/http.h index 544db669..010ea6a9 100644 --- a/src/http.h +++ b/src/http.h @@ -132,7 +132,6 @@ typedef struct http_connection { char *hc_username; char *hc_password; access_t *hc_access; - int hc_ticket; struct config_head *hc_user_config; diff --git a/src/idnode.c b/src/idnode.c index 33a15d3c..962d0ba1 100644 --- a/src/idnode.c +++ b/src/idnode.c @@ -29,6 +29,7 @@ #include "notify.h" #include "settings.h" #include "uuid.h" +#include "access.h" static const idnodes_rb_t * idnode_domain ( const idclass_t *idc ); static void idclass_root_register ( idnode_t *in ); @@ -548,6 +549,21 @@ idnode_get_time * Lookup * *************************************************************************/ +int +idnode_perm(idnode_t *self, struct access *a, htsmsg_t *msg_to_write) +{ + const idclass_t *ic = self->in_class; + + while (ic) { + if (ic->ic_perm) + return self->in_class->ic_perm(self, a, msg_to_write); + if (ic->ic_perm_def) + return access_verify2(a, self->in_class->ic_perm_def); + ic = ic->ic_super; + } + return 0; +} + /** * */ diff --git a/src/idnode.h b/src/idnode.h index 12693533..fbaae48f 100644 --- a/src/idnode.h +++ b/src/idnode.h @@ -62,6 +62,7 @@ struct idclass { const property_group_t *ic_groups; ///< Groups for visual representation const property_t *ic_properties; ///< Property list const char *ic_event; ///< Events to fire on add/delete/title + uint32_t ic_perm_def; ///< Default permissions /* Callbacks */ idnode_set_t *(*ic_get_childs) (idnode_t *self); @@ -175,13 +176,7 @@ int idnode_write0 (idnode_t *self, htsmsg_t *m, int optmask, int dosave); #define idnode_save(in, m) idnode_read0(in, m, NULL, PO_NOSAVE | PO_USERAW) #define idnode_update(in, m) idnode_write0(in, m, PO_RDONLY | PO_WRONCE, 1) -static inline int -idnode_perm(idnode_t *self, struct access *a, htsmsg_t *msg_to_write) -{ - if (self->in_class->ic_perm) - return self->in_class->ic_perm(self, a, msg_to_write); - return 0; -} +int idnode_perm(idnode_t *self, struct access *a, htsmsg_t *msg_to_write); const char *idnode_get_str (idnode_t *self, const char *key ); int idnode_get_u32 (idnode_t *self, const char *key, uint32_t *u32); diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index 35e9a9ba..c6ef152e 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -21,6 +21,7 @@ #include "packet.h" #include "streaming.h" #include "subscriptions.h" +#include "access.h" #include "atomic.h" #include "notify.h" #include "idnode.h" @@ -143,6 +144,7 @@ const idclass_t mpegts_input_class = .ic_class = "mpegts_input", .ic_caption = "MPEGTS Input", .ic_event = "mpegts_input", + .ic_perm_def = ACCESS_ADMIN, .ic_get_title = mpegts_input_class_get_title, .ic_properties = (const property_t[]){ { diff --git a/src/input/mpegts/mpegts_mux.c b/src/input/mpegts/mpegts_mux.c index 1a9fc9f9..30271c1e 100644 --- a/src/input/mpegts/mpegts_mux.c +++ b/src/input/mpegts/mpegts_mux.c @@ -21,6 +21,7 @@ #include "queue.h" #include "input.h" #include "subscriptions.h" +#include "access.h" #include "dvb_charset.h" #include @@ -37,6 +38,7 @@ const idclass_t mpegts_mux_instance_class = { .ic_class = "mpegts_mux_instance", .ic_caption = "MPEGTS Multiplex Phy", + .ic_perm_def = ACCESS_ADMIN }; static void @@ -319,6 +321,7 @@ const idclass_t mpegts_mux_class = .ic_class = "mpegts_mux", .ic_caption = "MPEGTS Multiplex", .ic_event = "mpegts_mux", + .ic_perm_def = ACCESS_ADMIN, .ic_save = mpegts_mux_class_save, .ic_delete = mpegts_mux_class_delete, .ic_get_title = mpegts_mux_class_get_title, diff --git a/src/input/mpegts/mpegts_network.c b/src/input/mpegts/mpegts_network.c index d7f8561c..a07dea02 100644 --- a/src/input/mpegts/mpegts_network.c +++ b/src/input/mpegts/mpegts_network.c @@ -18,6 +18,7 @@ #include "input.h" #include "subscriptions.h" +#include "access.h" #include "dvb_charset.h" #include @@ -109,8 +110,9 @@ const idclass_t mpegts_network_class = { .ic_class = "mpegts_network", .ic_caption = "MPEGTS Network", - .ic_save = mpegts_network_class_save, .ic_event = "mpegts_network", + .ic_perm_def = ACCESS_ADMIN, + .ic_save = mpegts_network_class_save, .ic_get_title = mpegts_network_class_get_title, .ic_properties = (const property_t[]){ { diff --git a/src/main.c b/src/main.c index 3322b37d..f4eeb4c1 100644 --- a/src/main.c +++ b/src/main.c @@ -137,17 +137,8 @@ const tvh_caps_t tvheadend_capabilities[] = { #if ENABLE_CWC || ENABLE_CAPMT || ENABLE_CONSTCW { "caclient", NULL }, #endif -#if ENABLE_V4L - { "v4l", NULL }, -#endif -#if ENABLE_LINUXDVB - { "linuxdvb", NULL }, -#endif -#if ENABLE_SATIP_CLIENT - { "satip_client", NULL }, -#endif -#if ENABLE_HDHOMERUN_CLIENT - { "tvhdhomerun_client", NULL }, +#if ENABLE_V4L || ENABLE_LINUXDVB || ENABLE_SATIP_CLIENT || ENABLE_HDHOMERUN_CLIENT + { "tvadapters", NULL }, #endif #if ENABLE_IMAGECACHE { "imagecache", (uint32_t*)&imagecache_conf.enabled }, diff --git a/src/profile.c b/src/profile.c index 5752d1c3..51cc0459 100644 --- a/src/profile.c +++ b/src/profile.c @@ -20,6 +20,7 @@ #include "settings.h" #include "profile.h" #include "streaming.h" +#include "access.h" #include "plumbing/tsfix.h" #include "plumbing/globalheaders.h" #if ENABLE_LIBAV @@ -218,8 +219,9 @@ const idclass_t profile_class = { .ic_class = "profile", .ic_caption = "Stream Profile", - .ic_save = profile_class_save, .ic_event = "profile", + .ic_perm_def = ACCESS_ADMIN, + .ic_save = profile_class_save, .ic_get_title = profile_class_get_title, .ic_delete = profile_class_delete, .ic_properties = (const property_t[]){ diff --git a/src/service.c b/src/service.c index 9157b595..9622bcd3 100644 --- a/src/service.c +++ b/src/service.c @@ -44,6 +44,7 @@ #include "lang_codes.h" #include "descrambler.h" #include "input.h" +#include "access.h" #include "esfilter.h" static void service_data_timeout(void *aux); @@ -169,6 +170,7 @@ const idclass_t service_class = { .ic_class = "service", .ic_caption = "Service", .ic_event = "service", + .ic_perm_def = ACCESS_ADMIN, .ic_save = service_class_save, .ic_get_title = service_class_get_title, .ic_properties = (const property_t[]){ diff --git a/src/webui/static/app/acleditor.js b/src/webui/static/app/acleditor.js index 97d805ad..dc68e136 100644 --- a/src/webui/static/app/acleditor.js +++ b/src/webui/static/app/acleditor.js @@ -14,7 +14,7 @@ tvheadend.acleditor = function(panel, index) titleP: 'Access Entries', iconCls: 'group', columns: { - enabled: { width: 120 }, + enabled: { width: 120 }, username: { width: 250 }, password: { width: 250 }, prefix: { width: 350 }, diff --git a/src/webui/static/app/caclient.js b/src/webui/static/app/caclient.js index 40e00a93..f605e91c 100644 --- a/src/webui/static/app/caclient.js +++ b/src/webui/static/app/caclient.js @@ -2,15 +2,18 @@ * Conditional Access Client (cwc,capmt) */ -tvheadend.caclient_builders = new Ext.data.JsonStore({ - url: 'api/caclient/builders', - root: 'entries', - fields: ['class', 'caption', 'props'], - id: 'class', - autoLoad: true -}); - tvheadend.caclient = function(panel, index) { + + if (!tvheadend.caclient_builders) { + tvheadend.caclient_builders = new Ext.data.JsonStore({ + url: 'api/caclient/builders', + root: 'entries', + fields: ['class', 'caption', 'props'], + id: 'class', + autoLoad: true + }); + } + var actions = new Ext.ux.grid.RowActions({ id: 'status', header: '', diff --git a/src/webui/static/app/esfilter.js b/src/webui/static/app/esfilter.js index b89e89e2..68e77045 100644 --- a/src/webui/static/app/esfilter.js +++ b/src/webui/static/app/esfilter.js @@ -2,16 +2,18 @@ * Stream Profiles, Elementary Stream Filters */ -tvheadend.profile_builders = new Ext.data.JsonStore({ - url: 'api/profile/builders', - root: 'entries', - fields: ['class', 'caption', 'props'], - id: 'class', - autoLoad: true -}); - tvheadend.esfilter_tab = function(panel) { + if (!tvheadend.profile_builders) { + tvheadend.profile_builders = new Ext.data.JsonStore({ + url: 'api/profile/builders', + root: 'entries', + fields: ['class', 'caption', 'props'], + id: 'class', + autoLoad: true + }); + } + var list = '-class'; tvheadend.idnode_form_grid(panel, { diff --git a/src/webui/static/app/mpegts.js b/src/webui/static/app/mpegts.js index b92eb4e8..cdbc2574 100644 --- a/src/webui/static/app/mpegts.js +++ b/src/webui/static/app/mpegts.js @@ -2,31 +2,31 @@ * DVB network */ -tvheadend.network_builders = new Ext.data.JsonStore({ - url: 'api/mpegts/network/builders', - root: 'entries', - fields: ['class', 'caption', 'props'], - id: 'class', - autoLoad: true -}); - -tvheadend.network_list = new Ext.data.JsonStore({ - url: 'api/idnode/load', - baseParams: {class: 'mpegts_network', enum: 1}, - root: 'entries', - fields: ['key', 'val'], - id: 'key', - autoLoad: true -}); - -tvheadend.comet.on('mpegts_network', function() { - // TODO: Might be a bit excessive - tvheadend.network_builders.reload(); - tvheadend.network_list.reload(); -}); - tvheadend.networks = function(panel, index) { + if (!tvheadend.network_list) { + tvheadend.network_list = new Ext.data.JsonStore({ + url: 'api/idnode/load', + baseParams: {class: 'mpegts_network', enum: 1}, + root: 'entries', + fields: ['key', 'val'], + id: 'key', + autoLoad: true + }); + tvheadend.network_builders = new Ext.data.JsonStore({ + url: 'api/mpegts/network/builders', + root: 'entries', + fields: ['class', 'caption', 'props'], + id: 'class', + autoLoad: true + }); + tvheadend.comet.on('mpegts_network', function() { + // TODO: Might be a bit excessive + tvheadend.network_builders.reload(); + tvheadend.network_list.reload(); + }); + } + tvheadend.idnode_grid(panel, { url: 'api/mpegts/network', titleS: 'Network', diff --git a/src/webui/static/app/tvheadend.js b/src/webui/static/app/tvheadend.js index cb73ef17..0be16ed7 100644 --- a/src/webui/static/app/tvheadend.js +++ b/src/webui/static/app/tvheadend.js @@ -1,8 +1,6 @@ tvheadend.dynamic = true; tvheadend.accessupdate = null; -tvheadend.capabilties = null; -tvheadend.dvrpanel = null; -tvheadend.confpanel = null; +tvheadend.capabilities = null; /* State Provider */ Ext.state.Manager.setProvider(new Ext.state.CookieProvider({ @@ -353,9 +351,7 @@ function accessUpdate(o) { var idx = 0; - if (tvheadend.capabilities.indexOf('linuxdvb') !== -1 || - tvheadend.capabilities.indexOf('satip_client') !== -1 || - tvheadend.capabilities.indexOf('v4l') !== -1) + if (tvheadend.capabilities.indexOf('tvadapters') !== -1) tvheadend.tvadapters(dvbin); tvheadend.networks(dvbin); tvheadend.muxes(dvbin);