Add fine grained user / source address access control configurable from web ui.

This commit is contained in:
Andreas Öman 2008-04-29 06:53:21 +00:00
parent 5142e37c4d
commit 8d47b9b946
19 changed files with 525 additions and 136 deletions

View file

@ -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
View 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
View 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_ */

View file

@ -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,

View file

@ -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,

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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);
}

View file

@ -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
View file

@ -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;