Initial ticket support, needs testing

This commit is contained in:
John Törnblom 2011-02-01 22:43:22 +01:00
parent 0885b19df7
commit 7b1ce7852b
5 changed files with 176 additions and 12 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -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) {