From 8d47b9b946b1d575b95bd751310e2611989bc310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Tue, 29 Apr 2008 06:53:21 +0000 Subject: [PATCH] Add fine grained user / source address access control configurable from web ui. --- Makefile | 5 +- access.c | 325 +++++++++++++++++++++++++++++++ access.h | 73 +++++++ ajaxui/ajaxui.c | 10 +- ajaxui/ajaxui.h | 9 + ajaxui/ajaxui_channels.c | 7 +- ajaxui/ajaxui_config.c | 13 +- ajaxui/ajaxui_config_channels.c | 21 +- ajaxui/ajaxui_config_dvb.c | 30 ++- ajaxui/ajaxui_config_transport.c | 9 +- ajaxui/ajaxui_config_xmltv.c | 12 +- ajaxui/ajaxui_mailbox.c | 3 +- ajaxui/tvheadend.js | 13 ++ http.c | 26 ++- http.h | 3 +- main.c | 30 +-- rtsp.c | 45 +---- tvhead.h | 3 - xbmsp.c | 24 +-- 19 files changed, 525 insertions(+), 136 deletions(-) create mode 100644 access.c create mode 100644 access.h diff --git a/Makefile b/Makefile index ede52dd2..45f6410c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ SRCS = main.c dispatch.c channels.c transports.c teletext.c psi.c \ subscriptions.c mux.c tsdemux.c buffer.c tcp.c \ resolver.c tsmux.c parsers.c bitstream.c parser_h264.c spawn.c \ - notify.c intercom.c + notify.c intercom.c access.c SRCS += http.c @@ -36,7 +36,8 @@ SRCS += FFdecsa.c VPATH += ajaxui SRCS += ajaxui.c ajaxui_mailbox.c ajaxui_channels.c \ ajaxui_config.c ajaxui_config_channels.c ajaxui_config_dvb.c \ - ajaxui_config_transport.c ajaxui_config_xmltv.c + ajaxui_config_transport.c ajaxui_config_xmltv.c \ + ajaxui_config_access.c JSSRCS += tvheadend.js diff --git a/access.c b/access.c new file mode 100644 index 00000000..03fb9cb3 --- /dev/null +++ b/access.c @@ -0,0 +1,325 @@ +/* + * tvheadend, access control + * Copyright (C) 2008 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tvhead.h" +#include "access.h" + +static int atally; +struct access_entry_queue access_entries; +static void access_load(void); + + +/** + * + */ +void +access_init(void) +{ + TAILQ_INIT(&access_entries); + access_load(); +} + +/** + * + */ +static access_entry_t * +access_alloc(void) +{ + access_entry_t *ae; + + ae = calloc(1, sizeof(access_entry_t)); + TAILQ_INSERT_TAIL(&access_entries, ae, ae_link); + ae->ae_tally = ++atally; + return ae; +} + + + +/** + * + */ +access_entry_t * +access_add_network(const char *prefix) +{ + access_entry_t *ae; + char buf[100]; + int prefixlen; + char *p; + struct in_addr ip; + char title[100]; + + if(strlen(prefix) > 90) + return NULL; + + strcpy(buf, prefix); + p = strchr(buf, '/'); + if(p) { + *p++ = 0; + prefixlen = atoi(p); + if(prefixlen > 32) + return NULL; + } else { + prefixlen = 32; + } + + ip.s_addr = inet_addr(buf); + + ae = access_alloc(); + + ae->ae_ip.s_addr = ip.s_addr; + ae->ae_prefixlen = prefixlen; + ae->ae_netmask = prefixlen ? 0xffffffff << (32 - prefixlen) : 0; + ae->ae_network = ntohl(ip.s_addr) & ae->ae_netmask; + + ip.s_addr = htonl(ae->ae_network); + + snprintf(title, sizeof(title), "%s/%d", inet_ntoa(ip), prefixlen); + + ae->ae_title = strdup(title); + return ae; +} + + + +/** + * + */ +access_entry_t * +access_add_user(const char *username) +{ + access_entry_t *ae; + + ae = access_alloc(); + ae->ae_username = strdup(username); + ae->ae_title = strdup(username); + return ae; +} + +/** + * + */ +access_entry_t * +access_add(const char *id) +{ + access_entry_t *ae; + + if(isdigit(id[0])) + ae = access_add_network(id); + else + ae = access_add_user(id); + + if(ae != NULL) + access_save(); + + return ae; +} + + + +/** + * + */ +int +access_verify(const char *username, const char *password, + struct sockaddr *src, uint32_t mask) +{ + uint32_t bits = 0; + struct sockaddr_in *si = (struct sockaddr_in *)src; + uint32_t b = ntohl(si->sin_addr.s_addr); + access_entry_t *ae; + + TAILQ_FOREACH(ae, &access_entries, ae_link) { + + if(access_is_prefix(ae)) { + if((b & ae->ae_netmask) == ae->ae_network) + bits |= ae->ae_rights; + + } else { + + if(username != NULL && + !strcmp(ae->ae_username, username) && + !strcmp(ae->ae_password, password)) + bits |= ae->ae_rights; + } + } + + return (mask & bits) == mask ? 0 : -1; +} + + +/** + * + */ +access_entry_t * +access_by_id(int id) +{ + access_entry_t *ae; + + TAILQ_FOREACH(ae, &access_entries, ae_link) { + if(ae->ae_tally == id) + return ae; + } + return NULL; +} + +/** + * + */ +void +access_delete(access_entry_t *ae) +{ + TAILQ_REMOVE(&access_entries, ae, ae_link); + free(ae->ae_title); + free(ae->ae_username); + free(ae->ae_password); + free(ae); + access_save(); +} + + +/** + * + */ +static void +access_save_right(FILE *fp, access_entry_t *ae, const char *right, int v) +{ + fprintf(fp, "\t%s = %d\n", right, !!(ae->ae_rights & v)); +} + +/** + * + */ +static void +access_load_right(struct config_head *h, access_entry_t *ae, + const char *right, int v) +{ + int on = atoi(config_get_str_sub(h, right, "0")); + + if(on) + ae->ae_rights |= v; +} + +/** + * + */ +void +access_save(void) +{ + access_entry_t *ae; + char buf[400]; + FILE *fp; + + snprintf(buf, sizeof(buf), "%s/access.cfg", settings_dir); + if((fp = settings_open_for_write(buf)) == NULL) + return; + + TAILQ_FOREACH(ae, &access_entries, ae_link) { + if(access_is_prefix(ae)) { + fprintf(fp, "prefix {\n"); + fprintf(fp, "\tid = %s\n", ae->ae_title); + } else { + fprintf(fp, "user {\n"); + fprintf(fp, "\tname = %s\n", ae->ae_username); + if(ae->ae_password != NULL) + fprintf(fp, "\tpassword = %s\n", ae->ae_password); + } + + access_save_right(fp, ae, "streaming", ACCESS_STREAMING); + access_save_right(fp, ae, "rec", ACCESS_RECORDER_VIEW); + access_save_right(fp, ae, "recedit", ACCESS_RECORDER_CHANGE); + access_save_right(fp, ae, "conf", ACCESS_CONFIGURE); + access_save_right(fp, ae, "webui", ACCESS_WEB_INTERFACE); + access_save_right(fp, ae, "access", ACCESS_ACCESSCONTROL); + + fprintf(fp, "}\n"); + } + fclose(fp); +} + +/** + * + */ +static void +access_load(void) +{ + char buf[400]; + access_entry_t *ae; + const char *name; + struct config_head cl; + config_entry_t *ce; + + TAILQ_INIT(&cl); + + snprintf(buf, sizeof(buf), "%s/access.cfg", settings_dir); + + if(config_read_file0(buf, &cl)) { + ae = access_add_network("0.0.0.0/0"); + ae->ae_rights = ACCESS_FULL; + access_save(); + return; + } + + TAILQ_FOREACH(ce, &cl, ce_link) { + if(ce->ce_type != CFG_SUB) + continue; + + if(!strcasecmp("user", ce->ce_key)) { + + if((name = config_get_str_sub(&ce->ce_sub, "name", NULL)) == NULL) + continue; + + ae = access_add_user(name); + + if((name = config_get_str_sub(&ce->ce_sub, "password", NULL)) != NULL) + ae->ae_password = strdup(name); + + } else if(!strcasecmp("prefix", ce->ce_key)) { + + if((name = config_get_str_sub(&ce->ce_sub, "id", NULL)) == NULL) + continue; + + ae = access_add_network(name); + + } else { + continue; + } + + if(ae == NULL) + continue; + + access_load_right(&ce->ce_sub, ae, "streaming", ACCESS_STREAMING); + access_load_right(&ce->ce_sub, ae, "rec", ACCESS_RECORDER_VIEW); + access_load_right(&ce->ce_sub, ae, "recedit", ACCESS_RECORDER_CHANGE); + access_load_right(&ce->ce_sub, ae, "conf", ACCESS_CONFIGURE); + access_load_right(&ce->ce_sub, ae, "webui", ACCESS_WEB_INTERFACE); + access_load_right(&ce->ce_sub, ae, "access", ACCESS_ACCESSCONTROL); + } +} diff --git a/access.h b/access.h new file mode 100644 index 00000000..9f242a04 --- /dev/null +++ b/access.h @@ -0,0 +1,73 @@ +/* + * TV headend - Access control + * Copyright (C) 2008 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ACCESS_H_ +#define ACCESS_H_ + + +TAILQ_HEAD(access_entry_queue, access_entry); + +extern struct access_entry_queue access_entries; + +#define access_is_prefix(ae) ((ae)->ae_username == NULL) + +typedef struct access_entry { + int ae_tally; + char *ae_title; + + TAILQ_ENTRY(access_entry) ae_link; + char *ae_username; + char *ae_password; + struct in_addr ae_ip; + int ae_prefixlen; + uint32_t ae_rights; + + uint32_t ae_network; /* derived from ae_ip */ + uint32_t ae_netmask; /* derived from ae_prefixlen */ +} access_entry_t; + + +#define ACCESS_STREAMING 0x1 +#define ACCESS_RECORDER_VIEW 0x2 +#define ACCESS_RECORDER_CHANGE 0x4 +#define ACCESS_CONFIGURE 0x8 +#define ACCESS_WEB_INTERFACE 0x10 +#define ACCESS_ACCESSCONTROL 0x20 + +#define ACCESS_FULL 0x3f + +/** + * Verifies that the given user in combination with the source ip + * complies with the requested mask + * + * Return 0 if access is granted, -1 otherwise + */ +int access_verify(const char *username, const char *password, + struct sockaddr *src, uint32_t mask); + +void access_init(void); + +access_entry_t *access_add(const char *id); + +access_entry_t *access_by_id(int id); + +void access_delete(access_entry_t *ae); + +void access_save(void); + +#endif /* ACCESS_H_ */ diff --git a/ajaxui/ajaxui.c b/ajaxui/ajaxui.c index 693c25da..10377a5e 100644 --- a/ajaxui/ajaxui.c +++ b/ajaxui/ajaxui.c @@ -617,10 +617,14 @@ ajax_page_root(http_connection_t *hc, http_reply_t *hr, void ajaxui_start(void) { - http_path_add("/ajax/index.html", NULL, ajax_page_root); + http_path_add("/ajax/index.html", NULL, ajax_page_root, + ACCESS_WEB_INTERFACE); - http_path_add("/ajax/topmenu", NULL, ajax_page_titlebar); - http_path_add("/ajax/toptab", NULL, ajax_page_tab); + http_path_add("/ajax/topmenu", NULL, ajax_page_titlebar, + ACCESS_WEB_INTERFACE); + + http_path_add("/ajax/toptab", NULL, ajax_page_tab, + ACCESS_WEB_INTERFACE); /* Stylesheet */ http_resource_add("/ajax/ajaxui.css", embedded_ajaxui, diff --git a/ajaxui/ajaxui.h b/ajaxui/ajaxui.h index 7dbb9e12..9bb69cbe 100644 --- a/ajaxui/ajaxui.h +++ b/ajaxui/ajaxui.h @@ -19,6 +19,12 @@ #ifndef AJAXUI_H_ #define AJAXUI_H_ +#include "access.h" + +#define AJAX_ACCESS_CONFIG (ACCESS_WEB_INTERFACE | ACCESS_CONFIGURE) +#define AJAX_ACCESS_ACCESSCTRL \ + (ACCESS_WEB_INTERFACE | ACCESS_CONFIGURE | ACCESS_ACCESSCONTROL) + typedef enum { AJAX_BOX_FILLED, AJAX_BOX_SIDEBOX, @@ -92,6 +98,9 @@ void ajax_config_dvb_init(void); int ajax_config_xmltv_tab(http_connection_t *hc, http_reply_t *hr); void ajax_config_xmltv_init(void); +int ajax_config_access_tab(http_connection_t *hc, http_reply_t *hr); +void ajax_config_access_init(void); + void ajax_config_transport_init(void); int ajax_transport_build_list(http_connection_t *hc, tcp_queue_t *tq, diff --git a/ajaxui/ajaxui_channels.c b/ajaxui/ajaxui_channels.c index d41ce2c2..2ed65356 100644 --- a/ajaxui/ajaxui_channels.c +++ b/ajaxui/ajaxui_channels.c @@ -210,6 +210,9 @@ ajax_channelgroup_tab(http_connection_t *hc, http_reply_t *hr) void ajax_channels_init(void) { - http_path_add("/ajax/channelgroupmenu", NULL, ajax_channelgroup_menu); - http_path_add("/ajax/channelgrouptab", NULL, ajax_channel_tab); + http_path_add("/ajax/channelgroupmenu", NULL, ajax_channelgroup_menu, + ACCESS_WEB_INTERFACE); + http_path_add("/ajax/channelgrouptab", NULL, ajax_channel_tab, + ACCESS_WEB_INTERFACE); + } diff --git a/ajaxui/ajaxui_config.c b/ajaxui/ajaxui_config.c index a051ab11..5c27465b 100644 --- a/ajaxui/ajaxui_config.c +++ b/ajaxui/ajaxui_config.c @@ -32,12 +32,14 @@ #define AJAX_CONFIG_TAB_CHANNELS 0 #define AJAX_CONFIG_TAB_DVB 1 #define AJAX_CONFIG_TAB_XMLTV 2 -#define AJAX_CONFIG_TABS 3 +#define AJAX_CONFIG_TAB_ACCESS 3 +#define AJAX_CONFIG_TABS 4 const char *ajax_config_tabnames[] = { [AJAX_CONFIG_TAB_CHANNELS] = "Channels & Groups", [AJAX_CONFIG_TAB_DVB] = "DVB adapters", [AJAX_CONFIG_TAB_XMLTV] = "XML-TV", + [AJAX_CONFIG_TAB_ACCESS] = "Access control", }; @@ -83,6 +85,8 @@ ajax_config_dispatch(http_connection_t *hc, http_reply_t *hr, return ajax_config_dvb_tab(hc, hr); case AJAX_CONFIG_TAB_XMLTV: return ajax_config_xmltv_tab(hc, hr); + case AJAX_CONFIG_TAB_ACCESS: + return ajax_config_access_tab(hc, hr); default: return HTTP_STATUS_NOT_FOUND; @@ -125,10 +129,13 @@ ajax_config_tab(http_connection_t *hc, http_reply_t *hr) void ajax_config_init(void) { - http_path_add("/ajax/configmenu", NULL, ajax_config_menu); - http_path_add("/ajax/configtab", NULL, ajax_config_dispatch); + http_path_add("/ajax/configmenu", NULL, ajax_config_menu, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/configtab", NULL, ajax_config_dispatch, + AJAX_ACCESS_CONFIG); ajax_config_channels_init(); ajax_config_dvb_init(); ajax_config_xmltv_init(); + ajax_config_access_init(); } diff --git a/ajaxui/ajaxui_config_channels.c b/ajaxui/ajaxui_config_channels.c index 4cbccd15..97779bef 100644 --- a/ajaxui/ajaxui_config_channels.c +++ b/ajaxui/ajaxui_config_channels.c @@ -539,12 +539,19 @@ ajax_chsetcomdetect(http_connection_t *hc, http_reply_t *hr, void ajax_config_channels_init(void) { - http_path_add("/ajax/chgroup_add" , NULL, ajax_chgroup_add); - http_path_add("/ajax/chgroup_del" , NULL, ajax_chgroup_del); - http_path_add("/ajax/chgroup_updateorder", NULL, ajax_chgroup_updateorder); - http_path_add("/ajax/chgroup_editor", NULL, ajax_chgroup_editor); - http_path_add("/ajax/cheditor", NULL, ajax_cheditor); - http_path_add("/ajax/chop/changegroup", NULL, ajax_changegroup); - http_path_add("/ajax/chsetcomdetect", NULL, ajax_chsetcomdetect); + http_path_add("/ajax/chgroup_add" , NULL, ajax_chgroup_add, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/chgroup_del" , NULL, ajax_chgroup_del, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/chgroup_updateorder", NULL, ajax_chgroup_updateorder, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/chgroup_editor", NULL, ajax_chgroup_editor, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/cheditor", NULL, ajax_cheditor, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/chop/changegroup", NULL, ajax_changegroup, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/chsetcomdetect", NULL, ajax_chsetcomdetect, + AJAX_ACCESS_CONFIG); } diff --git a/ajaxui/ajaxui_config_dvb.c b/ajaxui/ajaxui_config_dvb.c index b0fe4e42..adf97879 100644 --- a/ajaxui/ajaxui_config_dvb.c +++ b/ajaxui/ajaxui_config_dvb.c @@ -879,15 +879,25 @@ ajax_dvbadapteraddnetwork(http_connection_t *hc, http_reply_t *hr, void ajax_config_dvb_init(void) { - http_path_add("/ajax/dvbadaptermuxlist" , NULL, ajax_adaptermuxlist); - http_path_add("/ajax/dvbadaptersummary" , NULL, ajax_adaptersummary); - http_path_add("/ajax/dvbadapterrename" , NULL, ajax_adapterrename); - http_path_add("/ajax/dvbadaptereditor", NULL, ajax_adaptereditor); - http_path_add("/ajax/dvbadapteraddmux", NULL, ajax_adapteraddmux); - http_path_add("/ajax/dvbadapterdelmux", NULL, ajax_adapterdelmux); - http_path_add("/ajax/dvbadaptercreatemux", NULL, ajax_adaptercreatemux); - http_path_add("/ajax/dvbmuxeditor", NULL, ajax_dvbmuxeditor); - http_path_add("/ajax/dvbnetworkinfo", NULL, ajax_dvbnetworkinfo); - http_path_add("/ajax/dvbadapteraddnetwork", NULL, ajax_dvbadapteraddnetwork); + http_path_add("/ajax/dvbadaptermuxlist" , NULL, ajax_adaptermuxlist, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/dvbadaptersummary" , NULL, ajax_adaptersummary, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/dvbadapterrename" , NULL, ajax_adapterrename, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/dvbadaptereditor", NULL, ajax_adaptereditor, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/dvbadapteraddmux", NULL, ajax_adapteraddmux, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/dvbadapterdelmux", NULL, ajax_adapterdelmux, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/dvbadaptercreatemux", NULL, ajax_adaptercreatemux, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/dvbmuxeditor", NULL, ajax_dvbmuxeditor, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/dvbnetworkinfo", NULL, ajax_dvbnetworkinfo, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/dvbadapteraddnetwork", NULL, ajax_dvbadapteraddnetwork, + AJAX_ACCESS_CONFIG); } diff --git a/ajaxui/ajaxui_config_transport.c b/ajaxui/ajaxui_config_transport.c index 5d1d982e..745c363f 100644 --- a/ajaxui/ajaxui_config_transport.c +++ b/ajaxui/ajaxui_config_transport.c @@ -368,12 +368,15 @@ void ajax_config_transport_init(void) { http_path_add("/ajax/transport_rename_channel", NULL, - ajax_transport_rename_channel); + ajax_transport_rename_channel, + AJAX_ACCESS_CONFIG); http_path_add("/ajax/transport_op", NULL, - ajax_transport_op); + ajax_transport_op, + AJAX_ACCESS_CONFIG); http_path_add("/ajax/transport_chdisable", NULL, - ajax_transport_chdisable); + ajax_transport_chdisable, + AJAX_ACCESS_CONFIG); } diff --git a/ajaxui/ajaxui_config_xmltv.c b/ajaxui/ajaxui_config_xmltv.c index c35099e5..2518041a 100644 --- a/ajaxui/ajaxui_config_xmltv.c +++ b/ajaxui/ajaxui_config_xmltv.c @@ -322,9 +322,13 @@ ajax_xmltvgrabberchmap(http_connection_t *hc, http_reply_t *hr, void ajax_config_xmltv_init(void) { - http_path_add("/ajax/xmltvgrabber" , NULL, ajax_xmltvgrabber); - http_path_add("/ajax/xmltvgrabbermode" , NULL, ajax_xmltvgrabbermode); - http_path_add("/ajax/xmltvgrabberlist" , NULL, ajax_xmltvgrabberlist); - http_path_add("/ajax/xmltvgrabberchmap" , NULL, ajax_xmltvgrabberchmap); + http_path_add("/ajax/xmltvgrabber" , NULL, ajax_xmltvgrabber, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/xmltvgrabbermode" , NULL, ajax_xmltvgrabbermode, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/xmltvgrabberlist" , NULL, ajax_xmltvgrabberlist, + AJAX_ACCESS_CONFIG); + http_path_add("/ajax/xmltvgrabberchmap" , NULL, ajax_xmltvgrabberchmap, + AJAX_ACCESS_CONFIG); } diff --git a/ajaxui/ajaxui_mailbox.c b/ajaxui/ajaxui_mailbox.c index 2b7a0431..7f8ed21e 100644 --- a/ajaxui/ajaxui_mailbox.c +++ b/ajaxui/ajaxui_mailbox.c @@ -286,7 +286,8 @@ ajax_mailbox_poll(http_connection_t *hc, http_reply_t *hr, void ajax_mailbox_init(void) { - http_path_add("/ajax/mailbox", NULL, ajax_mailbox_poll); + http_path_add("/ajax/mailbox", NULL, ajax_mailbox_poll, + ACCESS_WEB_INTERFACE); } diff --git a/ajaxui/tvheadend.js b/ajaxui/tvheadend.js index c68587e9..778b7a8d 100644 --- a/ajaxui/tvheadend.js +++ b/ajaxui/tvheadend.js @@ -83,4 +83,17 @@ function dvb_adapter_rename(id, oldname) a = new Ajax.Request('/ajax/dvbadapterrename/' + id, { parameters: { 'newname': newname}}); } +} + +function makedivinput(id, url) +{ + $(id).innerHTML='
' + + '
' + + '' + + '
' + + '
' + + '' + + '
'; } \ No newline at end of file diff --git a/http.c b/http.c index 44b43c7f..12766d9d 100644 --- a/http.c +++ b/http.c @@ -42,6 +42,7 @@ #include "tsmux.h" #include "http.h" #include "rtsp.h" +#include "access.h" int http_port; @@ -355,6 +356,12 @@ http_exec(http_connection_t *hc, http_path_t *hp, char *remain, int err) hr->hr_version = hc->hc_version; hr->hr_keep_alive = hc->hc_keep_alive; + if(!err && + access_verify(hc->hc_username, hc->hc_password, + (struct sockaddr *)&hc->hc_tcp_session.tcp_peer_addr, + hp->hp_accessmask)) + err = HTTP_STATUS_UNAUTHORIZED; + if(!err) err = hp->hp_callback(hc, hr, remain, hp->hp_opaque); @@ -504,18 +511,6 @@ http_process_request(http_connection_t *hc) } } -/** - * Verify username, and if password match, set 'hc->hc_user_config' - * to subconfig for that user - */ -static void -hc_user_resolve(http_connection_t *hc) -{ - hc->hc_user_config = user_resolve_to_config(hc->hc_username, - hc->hc_password); -} - - /** * Process a request, extract info from headers, dispatch command and * clean up @@ -564,7 +559,6 @@ process_request(http_connection_t *hc) if((n = http_tokenize((char *)authbuf, argv, 2, ':')) == 2) { hc->hc_username = strdup(argv[0]); hc->hc_password = strdup(argv[1]); - hc_user_resolve(hc); } } } @@ -815,7 +809,8 @@ http_tokenize(char *buf, char **vec, int vecsize, int delimiter) * Add a callback for a given "virtual path" on our HTTP server */ http_path_t * -http_path_add(const char *path, void *opaque, http_callback_t *callback) +http_path_add(const char *path, void *opaque, http_callback_t *callback, + uint32_t accessmask) { http_path_t *hp = malloc(sizeof(http_path_t)); @@ -823,6 +818,7 @@ http_path_add(const char *path, void *opaque, http_callback_t *callback) hp->hp_path = strdup(path); hp->hp_opaque = opaque; hp->hp_callback = callback; + hp->hp_accessmask = accessmask; LIST_INSERT_HEAD(&http_paths, hp, hp_link); return hp; } @@ -940,5 +936,5 @@ http_resource_add(const char *path, const void *ptr, size_t len, hres->content = content; hres->encoding = encoding; - http_path_add(path, hres, deliver_resource); + http_path_add(path, hres, deliver_resource, ACCESS_WEB_INTERFACE); } diff --git a/http.h b/http.h index 55b6cd0e..38538b42 100644 --- a/http.h +++ b/http.h @@ -151,10 +151,11 @@ typedef struct http_path { void *hp_opaque; http_callback_t *hp_callback; int hp_len; + uint32_t hp_accessmask; } http_path_t; http_path_t *http_path_add(const char *path, void *opaque, - http_callback_t *callback); + http_callback_t *callback, uint32_t accessmask); void http_resource_add(const char *path, const void *ptr, size_t len, const char *content, const char *encoding); diff --git a/main.c b/main.c index 4dc7857b..865e925a 100644 --- a/main.c +++ b/main.c @@ -60,6 +60,7 @@ #include "ffmuxer.h" #include "xbmsp.h" #include "ajaxui/ajaxui.h" +#include "access.h" #include @@ -220,6 +221,8 @@ main(int argc, char **argv) dispatch_init(); + access_init(); + htsparachute_init(pull_chute); signal(SIGTERM, doexit); @@ -391,30 +394,3 @@ settings_open_for_write(const char *name) name, strerror(errno)); return fp; } - -struct config_head * -user_resolve_to_config(const char *username, const char *password) -{ - config_entry_t *ce; - const char *name, *pass; - - TAILQ_FOREACH(ce, &config_list, ce_link) { - if(ce->ce_type == CFG_SUB && !strcasecmp("user", ce->ce_key)) { - if((name = config_get_str_sub(&ce->ce_sub, "name", NULL)) == NULL) - continue; - if(!strcmp(name, username)) - break; - } - } - - if(ce == NULL) - return NULL; - - if((pass = config_get_str_sub(&ce->ce_sub, "password", NULL)) == NULL) - return NULL; - - if(strcmp(pass, password)) - return NULL; - - return &ce->ce_sub; -} diff --git a/rtsp.c b/rtsp.c index 36fe5ce2..fe9a5eee 100644 --- a/rtsp.c +++ b/rtsp.c @@ -40,6 +40,7 @@ #include "tsmux.h" #include "tcp.h" #include "http.h" +#include "access.h" #include @@ -568,47 +569,9 @@ rtsp_cmd_teardown(http_connection_t *hc) static int rtsp_access_list(http_connection_t *hc) { - config_entry_t *ce; - struct config_head *head; - int prefixlen; - char *p; - struct sockaddr_in *si; - char buf[100]; - - uint32_t a, b, m; - - ce = config_get_key(&config_list, "rtsp-access"); - if(ce == NULL || ce->ce_type != CFG_SUB) - return -1; - - si = (struct sockaddr_in *)&hc->hc_tcp_session.tcp_peer_addr; - - b = ntohl(si->sin_addr.s_addr); - - head = &ce->ce_sub; - - TAILQ_FOREACH(ce, head, ce_link) { - if(strcasecmp("permit", ce->ce_key) || ce->ce_type != CFG_VALUE) - continue; - - if(strlen(ce->ce_value) > 90) - continue; - - strcpy(buf, ce->ce_value); - p = strchr(buf, '/'); - if(p) { - *p++ = 0; - prefixlen = atoi(p); - } else { - prefixlen = 32; - } - - m = prefixlen ? 0xffffffff << (32 - prefixlen) : 0; - a = ntohl(inet_addr(buf)); - if((b & m) == (a & m)) - return 0; - } - return -1; + return access_verify(hc->hc_username, hc->hc_password, + (struct sockaddr *)&hc->hc_tcp_session.tcp_peer_addr, + ACCESS_STREAMING); } diff --git a/tvhead.h b/tvhead.h index 2c19ec76..9d8c369c 100644 --- a/tvhead.h +++ b/tvhead.h @@ -889,9 +889,6 @@ FILE *settings_open_for_read(const char *name); extern const char *sys_warning; extern th_channel_group_t *defgroup; -struct config_head *user_resolve_to_config(const char *username, - const char *password); - extern inline unsigned int tvh_strhash(const char *s, unsigned int mod) { unsigned int v = 5381; diff --git a/xbmsp.c b/xbmsp.c index 5c9a6490..60de361f 100644 --- a/xbmsp.c +++ b/xbmsp.c @@ -35,6 +35,7 @@ #include "dispatch.h" #include "xbmsp.h" #include "tcp.h" +#include "access.h" #define XBMSP_FILEFORMAT "ts" @@ -537,7 +538,6 @@ xbmsp_input_authenticate(xbmsp_t *xbmsp, uint32_t msgid, { char *username, *password; uint32_t handle; - int grant; if(xbmsp_extract_u32(xbmsp, &buf, &len, &handle)) return EBADMSG; @@ -551,21 +551,17 @@ xbmsp_input_authenticate(xbmsp_t *xbmsp, uint32_t msgid, snprintf(xbmsp->xbmsp_logname, sizeof(xbmsp->xbmsp_logname), "xbmsp: %s @ %s", username, tcp_logname(&xbmsp->xbmsp_tcp_session)); - xbmsp->xbmsp_user_config = user_resolve_to_config(username, password); - if(xbmsp->xbmsp_user_config != NULL) { - grant = atoi(config_get_str_sub(xbmsp->xbmsp_user_config, "xbmsp", "0")); - if(grant == 0) { - xbmsp_send_err(xbmsp, msgid, XBMSP_ERROR_AUTHENTICATION_FAILED, - "User \"%s\" lacks xbmsp privileges", username); - return 0; - } - xbmsp->xbmsp_authenticated = 1; - /* Auth ok */ - xbmsp_send_msg(xbmsp, XBMSP_PACKET_OK, msgid, NULL, 0); - } else { + if(access_verify(username, password, + (struct sockaddr *)&xbmsp->xbmsp_tcp_session.tcp_peer_addr, + ACCESS_STREAMING) != 0) { xbmsp_send_err(xbmsp, msgid, XBMSP_ERROR_AUTHENTICATION_FAILED, - "Invalid username / password"); + "Access denied"); + return 0; } + xbmsp->xbmsp_authenticated = 1; + /* Auth ok */ + xbmsp_send_msg(xbmsp, XBMSP_PACKET_OK, msgid, NULL, 0); + free(username); free(password); return 0;