]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
ACL: add per entry (user) stream profile selection
authorJaroslav Kysela <perex@perex.cz>
Thu, 16 Oct 2014 13:36:02 +0000 (15:36 +0200)
committerJaroslav Kysela <perex@perex.cz>
Thu, 16 Oct 2014 13:44:34 +0000 (15:44 +0200)
src/access.c
src/access.h
src/htsp_server.c
src/profile.c
src/profile.h
src/webui/static/app/acleditor.js
src/webui/webui.c

index 7fc9ae9cef8330f25246dac0f00b2c58fbfab04f..af6c730cf02f8a72502263cf83b7320386012444 100644 (file)
@@ -171,6 +171,8 @@ access_copy(access_t *src)
     dst->aa_username = strdup(src->aa_username);
   if (src->aa_representative)
     dst->aa_representative = strdup(src->aa_representative);
+  if (src->aa_profiles)
+    dst->aa_profiles = htsmsg_copy(src->aa_profiles);
   if (src->aa_dvrcfgs)
     dst->aa_dvrcfgs = htsmsg_copy(src->aa_dvrcfgs);
   if (src->aa_chtags)
@@ -188,6 +190,7 @@ access_destroy(access_t *a)
     return;
   free(a->aa_username);
   free(a->aa_representative);
+  htsmsg_destroy(a->aa_profiles);
   htsmsg_destroy(a->aa_dvrcfgs);
   htsmsg_destroy(a->aa_chtags);
   free(a);
@@ -335,6 +338,12 @@ access_update(access_t *a, access_entry_t *ae)
     }
   }
 
+  if(ae->ae_profile && ae->ae_profile->pro_name[0] != '\0') {
+    if (a->aa_profiles == NULL)
+      a->aa_profiles = htsmsg_create_list();
+    htsmsg_add_str(a->aa_profiles, NULL, idnode_uuid_as_str(&ae->ae_profile->pro_id));
+  }
+
   if(ae->ae_dvr_config && ae->ae_dvr_config->dvr_config_name[0] != '\0') {
     if (a->aa_dvrcfgs == NULL)
       a->aa_dvrcfgs = htsmsg_create_list();
@@ -757,6 +766,8 @@ access_entry_destroy(access_entry_t *ae)
   TAILQ_REMOVE(&access_entries, ae, ae_link);
   idnode_unlink(&ae->ae_id);
 
+  if (ae->ae_profile)
+    LIST_REMOVE(ae, ae_profile_link);
   if (ae->ae_dvr_config)
     LIST_REMOVE(ae, ae_dvr_config_link);
   if (ae->ae_chtag)
@@ -775,6 +786,22 @@ access_entry_destroy(access_entry_t *ae)
   free(ae);
 }
 
+/*
+ *
+ */
+void
+access_destroy_by_profile(profile_t *pro, int delconf)
+{
+  access_entry_t *ae;
+
+  while ((ae = LIST_FIRST(&pro->pro_accesses)) != NULL) {
+    LIST_REMOVE(ae, ae_profile_link);
+    ae->ae_dvr_config = NULL;
+    if (delconf)
+      access_entry_save(ae);
+  }
+}
+
 /*
  *
  */
@@ -785,7 +812,7 @@ access_destroy_by_dvr_config(dvr_config_t *cfg, int delconf)
 
   while ((ae = LIST_FIRST(&cfg->dvr_accesses)) != NULL) {
     LIST_REMOVE(ae, ae_dvr_config_link);
-    ae->ae_dvr_config = NULL;
+    ae->ae_profile = profile_find_by_name(NULL, NULL);
     if (delconf)
       access_entry_save(ae);
   }
@@ -1026,6 +1053,37 @@ access_entry_dvr_config_get(void *o)
   return &ret;
 }
 
+static int
+access_entry_profile_set(void *o, const void *v)
+{
+  access_entry_t *ae = (access_entry_t *)o;
+  profile_t *pro = v ? profile_find_by_uuid(v) : NULL;
+  if (pro == NULL && ae->ae_profile) {
+    LIST_REMOVE(ae, ae_profile_link);
+    ae->ae_profile = NULL;
+    return 1;
+  } else if (ae->ae_profile != pro) {
+    if (ae->ae_profile)
+      LIST_REMOVE(ae, ae_profile_link);
+    ae->ae_profile = pro;
+    LIST_INSERT_HEAD(&pro->pro_accesses, ae, ae_profile_link);
+    return 1;
+  }
+  return 0;
+}
+
+static const void *
+access_entry_profile_get(void *o)
+{
+  static const char *ret;
+  access_entry_t *ae = (access_entry_t *)o;
+  if (ae->ae_profile)
+    ret = idnode_uuid_as_str(&ae->ae_profile->pro_id);
+  else
+    ret = "";
+  return &ret;
+}
+
 const idclass_t access_entry_class = {
   .ic_class      = "access",
   .ic_caption    = "Access",
@@ -1091,6 +1149,14 @@ const idclass_t access_entry_class = {
       .name     = "Advanced Streaming",
       .off      = offsetof(access_entry_t, ae_adv_streaming),
     },
+    {
+      .type     = PT_STR,
+      .id       = "profile",
+      .name     = "Streaming Profile",
+      .set      = access_entry_profile_set,
+      .get      = access_entry_profile_get,
+      .list     = profile_class_get_list,
+    },
     {
       .type     = PT_BOOL,
       .id       = "dvr",
index 12189a3f3efafcdab75a82c46bde84f05d6b1b6d..e0d55c8f3adf737598219b07632ca1da2e2e4251 100644 (file)
@@ -22,6 +22,7 @@
 #include "idnode.h"
 #include "htsmsg.h"
 
+struct profile;
 struct dvr_config;
 struct channel_tag;
 
@@ -57,6 +58,9 @@ typedef struct access_entry {
   int ae_streaming;
   int ae_adv_streaming;
 
+  struct profile *ae_profile;
+  LIST_ENTRY(access_entry) ae_profile_link;
+
   uint32_t ae_conn_limit;
 
   int ae_dvr;
@@ -83,6 +87,7 @@ typedef struct access {
   char     *aa_username;
   char     *aa_representative;
   uint32_t  aa_rights;
+  htsmsg_t *aa_profiles;
   htsmsg_t *aa_dvrcfgs;
   uint32_t  aa_chmin;
   uint32_t  aa_chmax;
@@ -185,6 +190,8 @@ access_entry_save(access_entry_t *ae);
  *
  */
 void
+access_destroy_by_profile(struct profile *pro, int delconf);
+void
 access_destroy_by_dvr_config(struct dvr_config *cfg, int delconf);
 void
 access_destroy_by_channel_tag(struct channel_tag *ct, int delconf);
index 2558da541beaf774f3aa5031d661955cd0f49a34..36a586b0ccff8096f24ccd92e58a0a384cfea37d 100644 (file)
@@ -1783,18 +1783,14 @@ htsp_method_subscribe(htsp_connection_t *htsp, htsmsg_t *in)
   }
 #endif
 
-#if ENABLE_LIBAV
+  profile_t *pro;
   const char *profile_id = htsmsg_get_str(in, "profile");
-  profile_t *pro = NULL;
   if (profile_id) {
     pro = profile_find_by_uuid(profile_id);
-    if (pro == NULL)
-      pro = profile_find_by_name(profile_id, "htsp");
+    if (pro)
+      profile_id = pro->pro_name;
   }
-
-#else
-  profile_t *pro = profile_find_by_name("htsp", NULL);
-#endif
+  pro = profile_find_by_list(htsp->htsp_granted_access->aa_profiles, profile_id, "htsp");
 
   hs->hs_work = profile_work(pro, st, &hs->hs_work_destroy);
   if (hs->hs_work) {
index 78bcad003373cce1ad16fc9155c83e81d1319e15..89cd97685dce659c50e9e24c5882cc4ee7077bd0 100644 (file)
@@ -83,6 +83,7 @@ profile_create
     return NULL;
   }
   LIST_INIT(&pro->pro_dvr_configs);
+  LIST_INIT(&pro->pro_accesses);
   if (idnode_insert(&pro->pro_id, uuid, pb->clazz, 0)) {
     if (uuid)
       tvherror("profile", "invalid uuid '%s'", uuid);
@@ -114,6 +115,7 @@ profile_delete(profile_t *pro, int delconf)
   TAILQ_REMOVE(&profiles, pro, pro_link);
   idnode_unlink(&pro->pro_id);
   dvr_config_destroy_by_profile(pro, delconf);
+  access_destroy_by_profile(pro, delconf);
   if (pro->pro_free)
     pro->pro_free(pro);
   free(pro->pro_name);
@@ -308,13 +310,13 @@ profile_find_by_name(const char *name, const char *alt)
     return profile_default;
 
   TAILQ_FOREACH(pro, &profiles, pro_link) {
-    if (!strcmp(pro->pro_name, name))
+    if (pro->pro_enabled && !strcmp(pro->pro_name, name))
       return pro;
   }
 
   if (alt) {
     TAILQ_FOREACH(pro, &profiles, pro_link) {
-      if (!strcmp(pro->pro_name, alt))
+      if (pro->pro_enabled && !strcmp(pro->pro_name, alt))
         return pro;
     }
   }
@@ -322,6 +324,35 @@ profile_find_by_name(const char *name, const char *alt)
   return profile_default;
 }
 
+/*
+ *
+ */
+profile_t *
+profile_find_by_list(htsmsg_t *uuids, const char *name, const char *alt)
+{
+  profile_t *pro, *res = NULL;
+  htsmsg_field_t *f;
+  const char *uuid, *uuid2;
+
+  pro  = profile_find_by_name(name, alt);
+  uuid = idnode_uuid_as_str(&pro->pro_id);
+  if (uuids) {
+    HTSMSG_FOREACH(f, uuids) {
+      uuid2 = htsmsg_field_get_str(f) ?: "";
+      if (strcmp(uuid, uuid2) == 0)
+        return res;
+      if (!res) {
+        res = profile_find_by_uuid(uuid2);
+        if (!res->pro_enabled)
+          res = NULL;
+      }
+    }
+  }
+  if (!res)
+    res = profile_find_by_name(NULL, NULL);
+  return res;
+}
+
 /*
  *
  */
index c97acf29f38b6e78d477eefa8fd781307f2a95a6..a0e71043f98745b8e5f2d95ad8092ac8e564afec 100644 (file)
@@ -64,6 +64,7 @@ typedef struct profile {
   TAILQ_ENTRY(profile) pro_link;
 
   LIST_HEAD(,dvr_config) pro_dvr_configs;
+  LIST_HEAD(,access_entry) pro_accesses;
 
   int pro_enabled;
   int pro_shield;
@@ -104,6 +105,7 @@ void profile_chain_close(profile_chain_t *prch);
 static inline profile_t *profile_find_by_uuid(const char *uuid)
   {  return (profile_t*)idnode_find(uuid, &profile_class, NULL); }
 profile_t *profile_find_by_name(const char *name, const char *alt);
+profile_t *profile_find_by_list(htsmsg_t *uuids, const char *name, const char *alt);
 
 htsmsg_t * profile_class_get_list(void *o);
 
index dc68e13621ea727fc30acda9822b634af383bd93..672f5aff19aff260f250049ccadd5621e5753328 100644 (file)
@@ -4,9 +4,10 @@
 
 tvheadend.acleditor = function(panel, index)
 {
-    var list = 'enabled,username,password,prefix,streaming,adv_streaming,' +
-               'dvr,dvr_config,webui,admin,conn_limit,channel_min,channel_max,' +
-               'channel_tag,comment';
+    var list = 'enabled,username,password,prefix,' +
+               'streaming,adv_streaming,profile,' +
+               'dvr,dvr_config,webui,admin,conn_limit,' +
+               'channel_min,channel_max,channel_tag,comment';
 
     tvheadend.idnode_grid(panel, {
         url: 'api/access/entry',
index fb98f967c3b644e1cde145eb39dfa442ed3ed048..295e17b469a854932266cffaa55ea715438b9438 100644 (file)
@@ -719,7 +719,9 @@ http_stream_service(http_connection_t *hc, service_t *service, int weight)
   if(http_access_verify(hc, ACCESS_ADVANCED_STREAMING))
     return HTTP_STATUS_UNAUTHORIZED;
 
-  if(!(pro = profile_find_by_name(http_arg_get(&hc->hc_req_args, "profile"), "service")))
+  if(!(pro = profile_find_by_list(hc->hc_access->aa_profiles,
+                                  http_arg_get(&hc->hc_req_args, "profile"),
+                                  "service")))
     return HTTP_STATUS_NOT_ALLOWED;
 
   if((tcp_id = http_stream_preop(hc)) == NULL)
@@ -831,7 +833,9 @@ http_stream_channel(http_connection_t *hc, channel_t *ch, int weight)
   if (http_access_verify_channel(hc, ACCESS_STREAMING, ch, 1))
     return HTTP_STATUS_UNAUTHORIZED;
 
-  if(!(pro = profile_find_by_name(http_arg_get(&hc->hc_req_args, "profile"), "channel")))
+  if(!(pro = profile_find_by_list(hc->hc_access->aa_profiles,
+                                  http_arg_get(&hc->hc_req_args, "profile"),
+                                  "channel")))
     return HTTP_STATUS_NOT_ALLOWED;
 
   if((tcp_id = http_stream_preop(hc)) == NULL)