#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;
+}
/**
*
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);
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
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);
}
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");
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);
}
}
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) {