Add fine grained user / source address access control configurable from web ui.
This commit is contained in:
parent
5142e37c4d
commit
8d47b9b946
19 changed files with 525 additions and 136 deletions
5
Makefile
5
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
|
||||
|
||||
|
|
325
access.c
Normal file
325
access.c
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
73
access.h
Normal file
73
access.h
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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_ */
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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='<div style="width:100%; overflow:auto">' +
|
||||
'<div style="width:75%; float:left">' +
|
||||
'<input id="val' + id + '" type="password" class="textinput">' +
|
||||
'</div>' +
|
||||
'<div style="width:25%; float:left">' +
|
||||
'<input class="textinput" type="button" value="Set" ' +
|
||||
'onClick="new Ajax.Request(\'' + url + '\', ' +
|
||||
'{parameters: {value: $F(\'val' + id + '\')}})">' +
|
||||
'</div></div>';
|
||||
}
|
26
http.c
26
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);
|
||||
}
|
||||
|
|
3
http.h
3
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);
|
||||
|
|
30
main.c
30
main.c
|
@ -60,6 +60,7 @@
|
|||
#include "ffmuxer.h"
|
||||
#include "xbmsp.h"
|
||||
#include "ajaxui/ajaxui.h"
|
||||
#include "access.h"
|
||||
|
||||
#include <libhts/htsparachute.h>
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
45
rtsp.c
45
rtsp.c
|
@ -40,6 +40,7 @@
|
|||
#include "tsmux.h"
|
||||
#include "tcp.h"
|
||||
#include "http.h"
|
||||
#include "access.h"
|
||||
|
||||
#include <libavutil/random.h>
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
3
tvhead.h
3
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;
|
||||
|
|
24
xbmsp.c
24
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;
|
||||
|
|
Loading…
Add table
Reference in a new issue