]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Initial ticket support, needs testing
authorJohn Törnblom <john.tornblom@gmail.com>
Tue, 1 Feb 2011 21:43:22 +0000 (22:43 +0100)
committerJohn Törnblom <john.tornblom@gmail.com>
Fri, 4 Feb 2011 15:00:52 +0000 (16:00 +0100)
src/access.c
src/access.h
src/http.c
src/http.h
src/webui/webui.c

index e04f7ad5128014b6c15ee21408071b2371bd4be8..696822f2099f68f56bbd916b12f9bc571ed7cc98 100644 (file)
 #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);
 
index 834a372c7fef347f9d0dcd97b277fcac9bd293e7..7af118e20874f6720a825b466b81956e4e98db18 100644 (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
index ea8a4f9862e1632c355157ff2a907c83a27e4167..9cca5036fef53b0184449ecd369df6252daa7ffb 100644 (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);
 }
index 8cc497c3ba4134a068d5faf308c9b4bbc9c03cc8..27897dfe9bf991b48bbc970365a08141051f6c57 100644 (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;
index c2060b923a5c0b3b947b2797f92609de59cd464c..13e754f44407c3aab3bd47eded4a6579e7e1d063 100644 (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) {