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;