]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Make access system ipv6 aware
authorBtbN <btbn@btbn.de>
Tue, 15 Jan 2013 04:32:02 +0000 (05:32 +0100)
committerBtbN <btbn@btbn.de>
Tue, 15 Jan 2013 06:01:12 +0000 (07:01 +0100)
src/access.c
src/access.h

index 7814025ebec217509fde391751fb65c9adfeafb5..4be611df00e96888823ed09a03f1294f334d4840 100644 (file)
@@ -149,6 +149,70 @@ access_ticket_verify(const char *id, const char *resource)
   return 0;
 }
 
+/**
+ *
+ */
+static int
+netmask_verify(access_entry_t *ae, struct sockaddr *src)
+{
+  int isv4v6 = 0;
+  uint32_t v4v6 = 0;
+  
+  if(src->sa_family == AF_INET6)
+  {
+    struct in6_addr *in6 = &(((struct sockaddr_in6 *)src)->sin6_addr);
+    uint32_t *a32 = (uint32_t*)in6->s6_addr;
+    if(a32[0] == 0 && a32[1] == 0 && ntohl(a32[2]) == 0x0000FFFFu)
+    {
+      isv4v6 = 1;
+      v4v6 = ntohl(a32[3]);
+    }
+  }
+
+  if(ae->ae_ipv6 == 0 && src->sa_family == AF_INET)
+  {
+    struct sockaddr_in *in4 = (struct sockaddr_in *)src;
+    uint32_t b = ntohl(in4->sin_addr.s_addr);
+    return (b & ae->ae_netmask) == ae->ae_network;
+  }
+  else if(ae->ae_ipv6 == 0 && isv4v6)
+  {
+    return (v4v6 & ae->ae_netmask) == ae->ae_network;
+  }
+  else if(ae->ae_ipv6 && isv4v6)
+  {
+    return 0;
+  }
+  else if(ae->ae_ipv6 && src->sa_family == AF_INET6)
+  {
+    struct in6_addr *in6 = &(((struct sockaddr_in6 *)src)->sin6_addr);
+    uint8_t *a8 = (uint8_t*)in6->s6_addr;
+    uint8_t *m8 = (uint8_t*)ae->ae_ip6.s6_addr;
+    int slen = ae->ae_prefixlen;
+    uint32_t apos = 0;
+    uint8_t lastMask = (0xFFu << (8 - (slen % 8)));
+
+    if(slen < 0 || slen > 128)
+      return 0;
+
+    while(slen >= 8)
+    {
+      if(a8[apos] != m8[apos])
+        return 0;
+
+      apos += 1;
+      slen -= 8;
+    }
+
+    if(slen == 0)
+      return 1;
+
+    return (a8[apos] & lastMask) == (m8[apos] & lastMask);
+  }
+
+  return 0;
+}
+
 /**
  *
  */
@@ -157,8 +221,6 @@ access_verify(const char *username, const char *password,
              struct sockaddr *src, uint32_t mask)
 {
   uint32_t bits = 0;
-  struct sockaddr_in *si = (struct sockaddr_in *)src;
-  uint32_t b = ntohl(si->sin_addr.s_addr);
   access_entry_t *ae;
 
   if(username != NULL && superuser_username != NULL && 
@@ -182,7 +244,7 @@ access_verify(const char *username, const char *password,
        continue; /* username/password mismatch */
     }
 
-    if((b & ae->ae_netmask) != ae->ae_network)
+    if(!netmask_verify(ae, src))
       continue; /* IP based access mismatches */
 
     bits |= ae->ae_rights;
@@ -200,8 +262,6 @@ access_get_hashed(const char *username, const uint8_t digest[20],
                  const uint8_t *challenge, struct sockaddr *src,
                  int *entrymatch)
 {
-  struct sockaddr_in *si = (struct sockaddr_in *)src;
-  uint32_t b = ntohl(si->sin_addr.s_addr);
   access_entry_t *ae;
   SHA_CTX shactx;
   uint8_t d[20];
@@ -226,7 +286,7 @@ access_get_hashed(const char *username, const uint8_t digest[20],
     if(!ae->ae_enabled)
       continue;
 
-    if((b & ae->ae_netmask) != ae->ae_network)
+    if(!netmask_verify(ae, src))
       continue; /* IP based access mismatches */
 
     SHA1_Init(&shactx);
@@ -253,8 +313,6 @@ access_get_hashed(const char *username, const uint8_t digest[20],
 uint32_t
 access_get_by_addr(struct sockaddr *src)
 {
-  struct sockaddr_in *si = (struct sockaddr_in *)src;
-  uint32_t b = ntohl(si->sin_addr.s_addr);
   access_entry_t *ae;
   uint32_t r = 0;
 
@@ -263,7 +321,7 @@ access_get_by_addr(struct sockaddr *src)
     if(ae->ae_username[0] != '*')
       continue;
 
-    if((b & ae->ae_netmask) != ae->ae_network)
+    if(!netmask_verify(ae, src))
       continue; /* IP based access mismatches */
 
     r |= ae->ae_rights;
@@ -300,21 +358,50 @@ access_set_prefix(access_entry_t *ae, const char *prefix)
     return;
   
   strcpy(buf, prefix);
-  p = strchr(buf, '/');
-  if(p) {
-    *p++ = 0;
-    prefixlen = atoi(p);
-    if(prefixlen > 32)
-      return;
-  } else {
-    prefixlen = 32;
+
+  if(strchr(buf, ':') != NULL)
+    ae->ae_ipv6 = 1;
+  else
+    ae->ae_ipv6 = 0;
+
+  if(ae->ae_ipv6)
+  {
+    p = strchr(buf, '/');
+    if(p)
+    {
+      *p++ = 0;
+      prefixlen = atoi(p);
+      if(prefixlen > 128)
+        return;
+    } else {
+      prefixlen = 128;
+    }
+
+    ae->ae_prefixlen = prefixlen;
+    inet_pton(AF_INET6, buf, &ae->ae_ip6);
+
+    ae->ae_netmask = 0xffffffff;
+    ae->ae_network = 0x00000000;
   }
+  else
+  {
+    p = strchr(buf, '/');
+    if(p)
+    {
+      *p++ = 0;
+      prefixlen = atoi(p);
+      if(prefixlen > 32)
+        return;
+    } else {
+      prefixlen = 32;
+    }
 
-  ae->ae_ip.s_addr = inet_addr(buf);
-  ae->ae_prefixlen = prefixlen;
+    ae->ae_ip.s_addr = inet_addr(buf);
+    ae->ae_prefixlen = prefixlen;
 
-  ae->ae_netmask   = prefixlen ? 0xffffffff << (32 - prefixlen) : 0;
-  ae->ae_network   = ntohl(ae->ae_ip.s_addr) & ae->ae_netmask;
+    ae->ae_netmask   = prefixlen ? 0xffffffff << (32 - prefixlen) : 0;
+    ae->ae_network   = ntohl(ae->ae_ip.s_addr) & ae->ae_netmask;
+  }
 }
 
 
@@ -378,6 +465,7 @@ static htsmsg_t *
 access_record_build(access_entry_t *ae)
 {
   htsmsg_t *e = htsmsg_create_map();
+  char addrbuf[50];
   char buf[100];
 
   htsmsg_add_u32(e, "enabled",  !!ae->ae_enabled);
@@ -386,7 +474,13 @@ access_record_build(access_entry_t *ae)
   htsmsg_add_str(e, "password", ae->ae_password);
   htsmsg_add_str(e, "comment",  ae->ae_comment);
 
-  snprintf(buf, sizeof(buf), "%s/%d", inet_ntoa(ae->ae_ip), ae->ae_prefixlen);
+  if(ae->ae_ipv6)
+  {
+    inet_ntop(AF_INET6, &ae->ae_ip6, addrbuf, 50);
+    snprintf(buf, sizeof(buf), "%s/%d", addrbuf, ae->ae_prefixlen);
+  }
+  else
+    snprintf(buf, sizeof(buf), "%s/%d", inet_ntoa(ae->ae_ip), ae->ae_prefixlen);
   htsmsg_add_str(e, "prefix",   buf);
 
   htsmsg_add_u32(e, "streaming", ae->ae_rights & ACCESS_STREAMING     ? 1 : 0);
@@ -558,17 +652,33 @@ access_init(int createdefault)
     ae = access_entry_find(NULL, 1);
 
     free(ae->ae_comment);
-    ae->ae_comment = strdup("Default access entry");
+    ae->ae_comment = strdup("Default IPv6 access entry");
+
+    ae->ae_enabled = 1;
+    ae->ae_rights = 0xffffffff;
+
+    ae->ae_ipv6 = 1;
+
+    r = access_record_build(ae);
+    dtable_record_store(dt, ae->ae_id, r);
+    htsmsg_destroy(r);
+
+    ae = access_entry_find(NULL, 1);
+
+    free(ae->ae_comment);
+    ae->ae_comment = strdup("Default IPv4 access entry");
 
     ae->ae_enabled = 1;
     ae->ae_rights = 0xffffffff;
 
+    ae->ae_ipv6 = 0;
+
     r = access_record_build(ae);
     dtable_record_store(dt, ae->ae_id, r);
     htsmsg_destroy(r);
 
     tvhlog(LOG_WARNING, "accesscontrol",
-          "Created default wide open access controle entry");
+          "Created default wide open access controle entrys");
   }
 
   /* Load superuser account */
index 35bb1d831d5e9269bb623caac4cd916bf18c557d..3562b0ac40a866a63c3fa7564a5564a7fc1aad36 100644 (file)
@@ -31,7 +31,9 @@ typedef struct access_entry {
   char *ae_username;
   char *ae_password;
   char *ae_comment;
+  int ae_ipv6;
   struct in_addr ae_ip;
+  struct in6_addr ae_ip6;
   int ae_prefixlen;
   int ae_enabled;