Initial ticket support, needs testing
This commit is contained in:
parent
0885b19df7
commit
7b1ce7852b
5 changed files with 176 additions and 12 deletions
137
src/access.c
137
src/access.c
|
@ -37,10 +37,144 @@
|
|||
#include "settings.h"
|
||||
|
||||
struct access_entry_queue access_entries;
|
||||
struct access_ticket_queue access_tickets;
|
||||
|
||||
const char *superuser_username;
|
||||
const char *superuser_password;
|
||||
|
||||
static pthread_mutex_t access_ticket_mutex;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
access_ticket_destroy(access_ticket_t *at)
|
||||
{
|
||||
free(at->at_id);
|
||||
free(at->at_resource);
|
||||
TAILQ_REMOVE(&access_tickets, at, at_link);
|
||||
free(at);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static access_ticket_t *
|
||||
access_ticket_find(const char *id)
|
||||
{
|
||||
access_ticket_t *at = NULL;
|
||||
|
||||
if(id != NULL) {
|
||||
TAILQ_FOREACH(at, &access_tickets, at_link)
|
||||
if(!strcmp(at->at_id, id))
|
||||
return at;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
access_ticket_timout(void *aux)
|
||||
{
|
||||
access_ticket_t *at = aux;
|
||||
|
||||
pthread_mutex_lock(&access_ticket_mutex);
|
||||
access_ticket_destroy(at);
|
||||
pthread_mutex_unlock(&access_ticket_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ticket for the requested resource and generate a id for it
|
||||
*/
|
||||
const char *
|
||||
access_ticket_create(const char *resource)
|
||||
{
|
||||
uint8_t buf[20];
|
||||
char id[41];
|
||||
unsigned int i, rnd;
|
||||
access_ticket_t *at;
|
||||
SHA_CTX shactx;
|
||||
|
||||
static const char hex_string[16] = "0123456789ABCDEF";
|
||||
|
||||
pthread_mutex_lock(&access_ticket_mutex);
|
||||
|
||||
at = calloc(1, sizeof(access_ticket_t));
|
||||
rnd = time(NULL);
|
||||
|
||||
//Generate a pseudo-random ticket id
|
||||
SHA_Init(&shactx);
|
||||
for(i=0; i<5; i++) {
|
||||
SHA_Update(&shactx, (const uint8_t *)&rnd, sizeof(int));
|
||||
rnd = rand_r(&rnd);
|
||||
}
|
||||
SHA_Final(buf, &shactx);
|
||||
|
||||
//convert to hexstring
|
||||
for(i=0; i<sizeof(buf); i++){
|
||||
id[i*2] = hex_string[((buf[i] >> 4) & 0xF)];
|
||||
id[(i*2)+1] = hex_string[(buf[i]) & 0x0F];
|
||||
}
|
||||
id[40] = '\0';
|
||||
|
||||
at->at_id = strdup(id);
|
||||
at->at_resource = strdup(resource);
|
||||
|
||||
TAILQ_INSERT_TAIL(&access_tickets, at, at_link);
|
||||
gtimer_arm(&at->at_timer, access_ticket_timout, at, 60*5);
|
||||
|
||||
pthread_mutex_unlock(&access_ticket_mutex);
|
||||
|
||||
return at->at_id;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
access_ticket_delete(const char *id)
|
||||
{
|
||||
access_ticket_t *at;
|
||||
pthread_mutex_lock(&access_ticket_mutex);
|
||||
|
||||
if((at = access_ticket_find(id)) == NULL) {
|
||||
pthread_mutex_unlock(&access_ticket_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gtimer_disarm(&at->at_timer);
|
||||
access_ticket_destroy(at);
|
||||
|
||||
pthread_mutex_unlock(&access_ticket_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
access_ticket_verify(const char *id, const char *resource)
|
||||
{
|
||||
access_ticket_t *at;
|
||||
|
||||
pthread_mutex_lock(&access_ticket_mutex);
|
||||
|
||||
if((at = access_ticket_find(id)) == NULL) {
|
||||
pthread_mutex_unlock(&access_ticket_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strcmp(at->at_resource, resource)) {
|
||||
pthread_mutex_unlock(&access_ticket_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&access_ticket_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -424,6 +558,9 @@ access_init(int createdefault)
|
|||
const char *s;
|
||||
|
||||
TAILQ_INIT(&access_entries);
|
||||
TAILQ_INIT(&access_tickets);
|
||||
|
||||
pthread_mutex_init(&access_ticket_mutex, NULL);
|
||||
|
||||
dt = dtable_create(&access_dtc, "accesscontrol", NULL);
|
||||
|
||||
|
|
24
src/access.h
24
src/access.h
|
@ -42,14 +42,36 @@ typedef struct access_entry {
|
|||
uint32_t ae_netmask; /* derived from ae_prefixlen */
|
||||
} access_entry_t;
|
||||
|
||||
TAILQ_HEAD(access_ticket_queue, access_ticket);
|
||||
|
||||
extern struct access_ticket_queue access_tickets;
|
||||
|
||||
typedef struct access_ticket {
|
||||
char *at_id;
|
||||
|
||||
TAILQ_ENTRY(access_ticket) at_link;
|
||||
|
||||
gtimer_t at_timer;
|
||||
char *at_resource;
|
||||
} access_ticket_t;
|
||||
|
||||
#define ACCESS_STREAMING 0x1
|
||||
#define ACCESS_WEB_INTERFACE 0x2
|
||||
#define ACCESS_RECORDER 0x4
|
||||
#define ACCESS_ADMIN 0x8
|
||||
|
||||
#define ACCESS_FULL 0x3f
|
||||
|
||||
/**
|
||||
* Create a new ticket for the requested resource and generate a id for it
|
||||
*/
|
||||
const char* access_ticket_create(const char *resource);
|
||||
|
||||
/**
|
||||
* Verifies that a given ticket id matches a resource
|
||||
*/
|
||||
int access_ticket_verify(const char *id, const char *resource);
|
||||
|
||||
int access_ticket_delete(const char *ticket_id);
|
||||
/**
|
||||
* Verifies that the given user in combination with the source ip
|
||||
* complies with the requested mask
|
||||
|
|
|
@ -308,6 +308,15 @@ http_redirect(http_connection_t *hc, const char *location)
|
|||
int
|
||||
http_access_verify(http_connection_t *hc, int mask)
|
||||
{
|
||||
const char *ticket_id = http_arg_get(&hc->hc_req_args, "ticket");
|
||||
|
||||
if(!access_ticket_verify(ticket_id, hc->hc_url)) {
|
||||
tvhlog(LOG_INFO, "HTTP", "%s: using ticket %s for %s",
|
||||
inet_ntoa(hc->hc_peer->sin_addr), ticket_id,
|
||||
hc->hc_url);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return access_verify(hc->hc_username, hc->hc_password,
|
||||
(struct sockaddr *)hc->hc_peer, mask);
|
||||
}
|
||||
|
|
|
@ -80,11 +80,6 @@ typedef struct http_connection {
|
|||
char *hc_username;
|
||||
char *hc_password;
|
||||
|
||||
int hc_authenticated; /* Used by RTSP, it seems VLC does not
|
||||
send authentication headers for each
|
||||
command, so we just say that it's ok
|
||||
if it has authenticated at least once */
|
||||
|
||||
struct config_head *hc_user_config;
|
||||
|
||||
int hc_no_output;
|
||||
|
|
|
@ -243,6 +243,9 @@ static void
|
|||
http_stream_playlist(http_connection_t *hc, channel_t *channel)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
char buf[255];
|
||||
const char *ticket_id = NULL;
|
||||
|
||||
channel_t *ch = NULL;
|
||||
const char *host = http_arg_get(&hc->hc_args, "Host");
|
||||
|
||||
|
@ -252,7 +255,10 @@ http_stream_playlist(http_connection_t *hc, channel_t *channel)
|
|||
RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
|
||||
if (channel == NULL || ch == channel) {
|
||||
htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", ch->ch_name);
|
||||
htsbuf_qprintf(hq, "http://%s/stream/channelid/%d\n", host, ch->ch_id);
|
||||
|
||||
snprintf(buf, sizeof(buf), "/stream/channelid/%d", ch->ch_id);
|
||||
ticket_id = access_ticket_create(buf);
|
||||
htsbuf_qprintf(hq, "http://%s%s?ticket=%s\n", host, buf, ticket_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -385,11 +391,6 @@ http_stream(http_connection_t *hc, const char *remain, void *opaque)
|
|||
channel_t *ch = NULL;
|
||||
service_t *service = NULL;
|
||||
|
||||
if(http_access_verify(hc, ACCESS_STREAMING)) {
|
||||
http_error(hc, HTTP_STATUS_UNAUTHORIZED);
|
||||
return HTTP_STATUS_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
hc->hc_keep_alive = 0;
|
||||
|
||||
if(remain == NULL) {
|
||||
|
|
Loading…
Add table
Reference in a new issue