diff --git a/access.c b/access.c index fa1d0574..54a3b2e7 100644 --- a/access.c +++ b/access.c @@ -310,6 +310,8 @@ static const dtable_class_t access_dtc = { .dtc_record_create = access_record_create, .dtc_record_update = access_record_update, .dtc_record_delete = access_record_delete, + .dtc_read_access = ACCESS_ADMIN, + .dtc_write_access = ACCESS_ADMIN, }; /** diff --git a/channels.c b/channels.c index 6bbab6b9..84bfd01c 100644 --- a/channels.c +++ b/channels.c @@ -778,6 +778,8 @@ static const dtable_class_t channel_tags_dtc = { .dtc_record_create = channel_tag_record_create, .dtc_record_update = channel_tag_record_update, .dtc_record_delete = channel_tag_record_delete, + .dtc_read_access = ACCESS_ADMIN, + .dtc_write_access = ACCESS_ADMIN, }; diff --git a/cwc.c b/cwc.c index be2553ed..00f4ff3a 100644 --- a/cwc.c +++ b/cwc.c @@ -1207,6 +1207,8 @@ static const dtable_class_t cwc_dtc = { .dtc_record_create = cwc_entry_create, .dtc_record_update = cwc_entry_update, .dtc_record_delete = cwc_entry_delete, + .dtc_read_access = ACCESS_ADMIN, + .dtc_write_access = ACCESS_ADMIN, }; diff --git a/dtable.h b/dtable.h index febb0629..30bb2d99 100644 --- a/dtable.h +++ b/dtable.h @@ -22,6 +22,7 @@ #include #include +#include "access.h" typedef struct dtable_class { const char *dtc_name; @@ -37,6 +38,9 @@ typedef struct dtable_class { int (*dtc_record_delete)(void *opaque, const char *id); + int dtc_read_access; + int dtc_write_access; + } dtable_class_t; diff --git a/dvr/dvr_autorec.c b/dvr/dvr_autorec.c index b98127cb..fefa228d 100644 --- a/dvr/dvr_autorec.c +++ b/dvr/dvr_autorec.c @@ -322,6 +322,8 @@ static const dtable_class_t autorec_dtc = { .dtc_record_create = autorec_record_create, .dtc_record_update = autorec_record_update, .dtc_record_delete = autorec_record_delete, + .dtc_read_access = ACCESS_RECORDER, + .dtc_write_access = ACCESS_RECORDER, }; /** diff --git a/http.c b/http.c index 6920965b..8953e221 100644 --- a/http.c +++ b/http.c @@ -295,6 +295,15 @@ http_redirect(http_connection_t *hc, const char *location) http_send_reply(hc, HTTP_STATUS_FOUND, "text/html", NULL, location, 0); } +/** + * Return non-zero if no access + */ +int +http_access_verify(http_connection_t *hc, int mask) +{ + return access_verify(hc->hc_username, hc->hc_password, + (struct sockaddr *)hc->hc_peer, mask); +} /** * Execute url callback @@ -306,8 +315,7 @@ static void http_exec(http_connection_t *hc, http_path_t *hp, char *remain) { int err; - if(access_verify(hc->hc_username, hc->hc_password, - (struct sockaddr *)hc->hc_peer, hp->hp_accessmask)) { + if(http_access_verify(hc, hp->hp_accessmask)) { http_error(hc, HTTP_STATUS_UNAUTHORIZED); return; } diff --git a/http.h b/http.h index b95bc8df..53a79b6a 100644 --- a/http.h +++ b/http.h @@ -135,4 +135,6 @@ http_path_t *http_path_add(const char *path, void *opaque, void http_server_init(void); +int http_access_verify(http_connection_t *hc, int mask); + #endif /* HTTP_H_ */ diff --git a/webui/comet.c b/webui/comet.c index 1a3eec24..cf6b7bde 100644 --- a/webui/comet.c +++ b/webui/comet.c @@ -132,6 +132,23 @@ comet_mailbox_create(void) return cmb; } +/** + * + */ +static void +comet_access_update(http_connection_t *hc, comet_mailbox_t *cmb) +{ + htsmsg_t *m = htsmsg_create(); + + htsmsg_add_str(m, "notificationClass", "accessUpdate"); + + htsmsg_add_u32(m, "dvr", !http_access_verify(hc, ACCESS_RECORDER)); + htsmsg_add_u32(m, "admin", !http_access_verify(hc, ACCESS_ADMIN)); + + if(cmb->cmb_messages == NULL) + cmb->cmb_messages = htsmsg_create_array(); + htsmsg_add_msg(cmb->cmb_messages, NULL, htsmsg_copy(m)); +} /** * Poll callback @@ -154,9 +171,10 @@ comet_mailbox_poll(http_connection_t *hc, const char *remain, void *opaque) if(!strcmp(cmb->cmb_boxid, cometid)) break; - if(cmb == NULL) + if(cmb == NULL) { cmb = comet_mailbox_create(); - + comet_access_update(hc, cmb); + } time(&reqtime); ts.tv_sec = reqtime + 10; diff --git a/webui/extjs.c b/webui/extjs.c index a4e7cdf1..5cff1981 100644 --- a/webui/extjs.c +++ b/webui/extjs.c @@ -170,11 +170,17 @@ extjs_tablemgr(http_connection_t *hc, const char *remain, void *opaque) if(tablename == NULL || (dt = dtable_find(tablename)) == NULL) return 404; + if(http_access_verify(hc, dt->dt_dtc->dtc_read_access)) + return HTTP_STATUS_UNAUTHORIZED; + in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL; pthread_mutex_lock(&global_lock); if(!strcmp(op, "create")) { + if(http_access_verify(hc, dt->dt_dtc->dtc_write_access)) + goto noaccess; + out = dtable_record_create(dt); } else if(!strcmp(op, "get")) { @@ -184,12 +190,18 @@ extjs_tablemgr(http_connection_t *hc, const char *remain, void *opaque) htsmsg_add_msg(out, "entries", array); } else if(!strcmp(op, "update")) { + if(http_access_verify(hc, dt->dt_dtc->dtc_write_access)) + goto noaccess; + if(in == NULL) goto bad; dtable_record_update_by_array(dt, in); } else if(!strcmp(op, "delete")) { + if(http_access_verify(hc, dt->dt_dtc->dtc_write_access)) + goto noaccess; + if(in == NULL) goto bad; @@ -199,6 +211,10 @@ extjs_tablemgr(http_connection_t *hc, const char *remain, void *opaque) bad: pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; + + noaccess: + pthread_mutex_unlock(&global_lock); + return HTTP_STATUS_BAD_REQUEST; } pthread_mutex_unlock(&global_lock); @@ -324,6 +340,11 @@ extjs_dvbtree(http_connection_t *hc, const char *remain, void *opaque) out = htsmsg_create_array(); pthread_mutex_lock(&global_lock); + if(http_access_verify(hc, ACCESS_ADMIN)) { + pthread_mutex_unlock(&global_lock); + return HTTP_STATUS_UNAUTHORIZED; + } + if(!strcmp(s, "root")) { /** * List of all adapters @@ -389,6 +410,11 @@ extjs_dvbnetworks(http_connection_t *hc, const char *remain, void *opaque) pthread_mutex_lock(&global_lock); + if(http_access_verify(hc, ACCESS_ADMIN)) { + pthread_mutex_unlock(&global_lock); + return HTTP_STATUS_UNAUTHORIZED; + } + if((tda = dvb_adapter_find_by_identifier(a)) == NULL) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; @@ -441,6 +467,11 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) pthread_mutex_lock(&global_lock); + if(http_access_verify(hc, ACCESS_ADMIN)) { + pthread_mutex_unlock(&global_lock); + return HTTP_STATUS_UNAUTHORIZED; + } + if(!strcmp(op, "load")) { r = htsmsg_create(); htsmsg_add_str(r, "id", tda->tda_identifier); @@ -613,6 +644,11 @@ extjs_channel(http_connection_t *hc, const char *remain, void *opaque) pthread_mutex_lock(&global_lock); + if(http_access_verify(hc, ACCESS_ADMIN)) { + pthread_mutex_unlock(&global_lock); + return HTTP_STATUS_UNAUTHORIZED; + } + ch = s ? channel_find_by_identifier(atoi(s)) : NULL; if(ch == NULL) { pthread_mutex_unlock(&global_lock); @@ -722,6 +758,15 @@ extjs_xmltv(http_connection_t *hc, const char *remain, void *opaque) htsmsg_t *out, *array, *e, *r; const char *s; + pthread_mutex_lock(&global_lock); + + if(http_access_verify(hc, ACCESS_ADMIN)) { + pthread_mutex_unlock(&global_lock); + return HTTP_STATUS_UNAUTHORIZED; + } + + pthread_mutex_unlock(&global_lock); + if(!strcmp(op, "listChannels")) { out = htsmsg_create(); @@ -936,6 +981,11 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque) pthread_mutex_lock(&global_lock); + if(http_access_verify(hc, ACCESS_RECORDER)) { + pthread_mutex_unlock(&global_lock); + return HTTP_STATUS_UNAUTHORIZED; + } + if(!strcmp(op, "recordEvent")) { s = http_arg_get(&hc->hc_req_args, "eventId"); @@ -1047,10 +1097,16 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque) else limit = 20; /* XXX */ + pthread_mutex_lock(&global_lock); + + if(http_access_verify(hc, ACCESS_RECORDER)) { + pthread_mutex_unlock(&global_lock); + return HTTP_STATUS_UNAUTHORIZED; + } + out = htsmsg_create(); array = htsmsg_create_array(); - pthread_mutex_lock(&global_lock); dvr_query(&dqr); diff --git a/webui/static/app/dvr.js b/webui/static/app/dvr.js index 0d2841a3..84b26fe4 100644 --- a/webui/static/app/dvr.js +++ b/webui/static/app/dvr.js @@ -1,32 +1,8 @@ -tvheadend.dvrStore = new Ext.data.JsonStore({ - root: 'entries', - totalProperty: 'totalCount', - fields: [ - {name: 'id'}, - {name: 'channel'}, - {name: 'title'}, - {name: 'description'}, - {name: 'chicon'}, - {name: 'start', type: 'date', dateFormat: 'U' /* unix time */}, - {name: 'end', type: 'date', dateFormat: 'U' /* unix time */}, - {name: 'status'}, - {name: 'schedstate'}, - {name: 'creator'}, - {name: 'duration'}, - {name: 'filesize'}, - {name: 'url'}, - ], - url: 'dvrlist', - autoLoad: true, - id: 'id', - remoteSort: true, -}); + /** * */ - - tvheadend.dvrDetails = function(entry) { var content = ''; @@ -196,19 +172,6 @@ tvheadend.dvrlog = function() { /** * */ -tvheadend.autorecRecord = Ext.data.Record.create([ - 'enabled','title','channel','tag','creator','contentgrp','comment' -]); - - -tvheadend.autorecStore = new Ext.data.JsonStore({ - root: 'entries', - fields: tvheadend.autorecRecord, - url: "tablemgr", - autoLoad: true, - id: 'id', - baseParams: {table: "autorec", op: "get"} -}); /** @@ -285,6 +248,46 @@ tvheadend.autoreceditor = function() { */ tvheadend.dvr = function() { + + tvheadend.dvrStore = new Ext.data.JsonStore({ + root: 'entries', + totalProperty: 'totalCount', + fields: [ + {name: 'id'}, + {name: 'channel'}, + {name: 'title'}, + {name: 'description'}, + {name: 'chicon'}, + {name: 'start', type: 'date', dateFormat: 'U' /* unix time */}, + {name: 'end', type: 'date', dateFormat: 'U' /* unix time */}, + {name: 'status'}, + {name: 'schedstate'}, + {name: 'creator'}, + {name: 'duration'}, + {name: 'filesize'}, + {name: 'url'}, + ], + url: 'dvrlist', + autoLoad: true, + id: 'id', + remoteSort: true, + }); + + + tvheadend.autorecRecord = Ext.data.Record.create([ + 'enabled','title','channel','tag','creator','contentgrp','comment' + ]); + + + tvheadend.autorecStore = new Ext.data.JsonStore({ + root: 'entries', + fields: tvheadend.autorecRecord, + url: "tablemgr", + autoLoad: true, + id: 'id', + baseParams: {table: "autorec", op: "get"} + }); + var panel = new Ext.TabPanel({ activeTab:0, autoScroll:true, @@ -293,7 +296,6 @@ tvheadend.dvr = function() { new tvheadend.autoreceditor ] }); - return panel; } diff --git a/webui/static/app/tvheadend.js b/webui/static/app/tvheadend.js index c80e9dd3..fb07fd86 100644 --- a/webui/static/app/tvheadend.js +++ b/webui/static/app/tvheadend.js @@ -1,5 +1,40 @@ +/** + * This function creates top level tabs based on access so users without + * access to subsystems won't see them. + * + * Obviosuly, access is verified in the server too. + */ +function accessUpdate(o) { + + + if(o.dvr == true && tvheadend.dvrpanel == null) { + tvheadend.dvrpanel = new tvheadend.dvr; + tvheadend.rootTabPanel.add(tvheadend.dvrpanel); + } + + if(o.admin == true && tvheadend.confpanel == null) { + tvheadend.confpanel = new Ext.TabPanel({ + activeTab:0, + autoScroll:true, + title: 'Configuration', + items: [new tvheadend.chconf, + new tvheadend.xmltv, + new tvheadend.cteditor, + new tvheadend.dvrsettings, + new tvheadend.dvb, + new tvheadend.acleditor, + new tvheadend.cwceditor] + }); + tvheadend.rootTabPanel.add(tvheadend.confpanel); + } + + + tvheadend.rootTabPanel.doLayout(); + + console.log(o); +} /** * Comet interfaces @@ -14,6 +49,11 @@ tvheadend.comet_poller = function() { var m = response.messages[x]; switch(m.notificationClass) { + + case 'accessUpdate': + accessUpdate(m); + break; + case 'channeltags': if(m.reload != null) tvheadend.channelTags.reload(); @@ -102,17 +142,11 @@ tvheadend.app = function() { // public methods init: function() { - var confpanel = new Ext.TabPanel({ - activeTab:0, - autoScroll:true, - title: 'Configuration', - items: [new tvheadend.chconf, - new tvheadend.xmltv, - new tvheadend.cteditor, - new tvheadend.dvrsettings, - new tvheadend.dvb, - new tvheadend.acleditor, - new tvheadend.cwceditor] + + tvheadend.rootTabPanel = new Ext.TabPanel({ + region:'center', + activeTab:0, + items:[new tvheadend.epg] }); var viewport = new Ext.Viewport({ @@ -129,18 +163,11 @@ tvheadend.app = function() { collapsible: true, title:'System log', margins:'0 0 0 0' - },new Ext.TabPanel({ - region:'center', - activeTab:0, - items:[ - new tvheadend.epg, - new tvheadend.dvr, - confpanel - ] - }) + },tvheadend.rootTabPanel ] }); - + + new tvheadend.comet_poller; Ext.QuickTips.init(); } diff --git a/webui/webui.c b/webui/webui.c index 88b8c19a..f994821c 100644 --- a/webui/webui.c +++ b/webui/webui.c @@ -123,6 +123,12 @@ page_dvrfile(http_connection_t *hc, const char *remain, void *opaque) return 404; pthread_mutex_lock(&global_lock); + + if(http_access_verify(hc, ACCESS_RECORDER)) { + pthread_mutex_unlock(&global_lock); + return HTTP_STATUS_UNAUTHORIZED; + } + de = dvr_entry_find_by_id(atoi(remain)); if(de == NULL || de->de_filename == NULL) { pthread_mutex_unlock(&global_lock);