]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
conf: rework allow/deny parser
authorMiroslav Lichvar <mlichvar@redhat.com>
Wed, 22 Sep 2021 13:54:50 +0000 (15:54 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 23 Sep 2021 13:16:33 +0000 (15:16 +0200)
Refactor the (cmd)allow/deny parser and make it more strict in what
input it accepts. Check the scanned numbers and require whole input to
be processed.

Move the parser to cmdparse to make it available to the client.

cmdparse.c
cmdparse.h
conf.c

index e2c51153a6bdef31b495d90657f53fe0d38084fd..d44b426c0c70aa4c8f6c59d51621ca3b0abac0cc 100644 (file)
@@ -181,6 +181,85 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
 
 /* ================================================== */
 
+int
+CPS_ParseAllowDeny(char *line, int *all, IPAddr *ip, int *subnet_bits)
+{
+  char *p, *net, *slash;
+  uint32_t a, b, c;
+  int bits, len, n;
+
+  p = CPS_SplitWord(line);
+
+  if (strcmp(line, "all") == 0) {
+    *all = 1;
+    net = p;
+    p = CPS_SplitWord(p);
+  } else {
+    *all = 0;
+    net = line;
+  }
+
+  /* Make sure there are no other arguments */
+  if (*p)
+    return 0;
+
+  /* No specified address or network means all IPv4 and IPv6 addresses */
+  if (!*net) {
+    ip->family = IPADDR_UNSPEC;
+    *subnet_bits = 0;
+    return 1;
+  }
+
+  slash = strchr(net, '/');
+  if (slash) {
+    if (sscanf(slash + 1, "%d%n", &bits, &len) != 1 || slash[len + 1] || bits < 0)
+      return 0;
+    *slash = '\0';
+  } else {
+    bits = -1;
+  }
+
+  if (UTI_StringToIP(net, ip)) {
+    if (bits >= 0)
+      *subnet_bits = bits;
+    else
+      *subnet_bits = ip->family == IPADDR_INET6 ? 128 : 32;
+    return 1;
+  }
+
+  /* Check for a shortened IPv4 network notation using only 1, 2, or 3 decimal
+     numbers.  This is different than the numbers-and-dots notation accepted
+     by inet_aton()! */
+
+  a = b = c = 0;
+  n = sscanf(net, "%"PRIu32"%n.%"PRIu32"%n.%"PRIu32"%n", &a, &len, &b, &len, &c, &len);
+
+  if (n > 0 && !net[len]) {
+    if (a > 255 || b > 255 || c > 255)
+      return 0;
+
+    ip->family = IPADDR_INET4;
+    ip->addr.in4 = (a << 24) | (b << 16) | (c << 8);
+
+    if (bits >= 0)
+      *subnet_bits = bits;
+    else
+      *subnet_bits = n * 8;
+
+    return 1;
+  }
+
+  /* The last possibility is a hostname */
+  if (bits < 0 && DNS_Name2IPAddress(net, ip, 1) == DNS_Success) {
+    *subnet_bits = ip->family == IPADDR_INET6 ? 128 : 32;
+    return 1;
+  }
+
+  return 0;
+}
+
+/* ================================================== */
+
 int
 CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance)
 {
index 199d9722c5d99c78a41f0d11d7e327143183753f..fd1eb43938d76152572eda8d5d855926a60dd1ab 100644 (file)
@@ -39,6 +39,9 @@ typedef struct {
 /* Parse a command to add an NTP server or peer */
 extern int CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
   
+/* Parse a command to allow/deny access */
+extern int CPS_ParseAllowDeny(char *line, int *all, IPAddr *ip, int *subnet_bits);
+
 /* Parse a command to enable local reference */
 extern int CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance);
 
diff --git a/conf.c b/conf.c
index 93e93fc6ca1058ef8d2260d79159b638b40442c0..06ea1e51f54486b3b4f2174bd4ee392f2fde388d 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -1217,100 +1217,18 @@ parse_ntstrustedcerts(char *line)
 static void
 parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
 {
-  char *p;
-  unsigned long a, b, c, d, n;
-  int all = 0;
-  AllowDeny *new_node = NULL;
-  IPAddr ip_addr;
-
-  p = line;
-
-  if (!strncmp(p, "all", 3)) {
-    all = 1;
-    p = CPS_SplitWord(line);
-  }
+  int all, subnet_bits;
+  AllowDeny *node;
+  IPAddr ip;
 
-  if (!*p) {
-    /* Empty line applies to all addresses */
-    new_node = (AllowDeny *)ARR_GetNewElement(restrictions);
-    new_node->allow = allow;
-    new_node->all = all;
-    new_node->ip.family = IPADDR_UNSPEC;
-    new_node->subnet_bits = 0;
-  } else {
-    char *slashpos;
-    slashpos = strchr(p, '/');
-    if (slashpos) *slashpos = 0;
-
-    check_number_of_args(p, 1);
-    n = 0;
-    if (UTI_StringToIP(p, &ip_addr) ||
-        (n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) >= 1) {
-      new_node = (AllowDeny *)ARR_GetNewElement(restrictions);
-      new_node->allow = allow;
-      new_node->all = all;
-
-      if (n == 0) {
-        new_node->ip = ip_addr;
-        if (ip_addr.family == IPADDR_INET6)
-          new_node->subnet_bits = 128;
-        else
-          new_node->subnet_bits = 32;
-      } else {
-        new_node->ip.family = IPADDR_INET4;
-
-        a &= 0xff;
-        b &= 0xff;
-        c &= 0xff;
-        d &= 0xff;
-        
-        switch (n) {
-          case 1:
-            new_node->ip.addr.in4 = (a<<24);
-            new_node->subnet_bits = 8;
-            break;
-          case 2:
-            new_node->ip.addr.in4 = (a<<24) | (b<<16);
-            new_node->subnet_bits = 16;
-            break;
-          case 3:
-            new_node->ip.addr.in4 = (a<<24) | (b<<16) | (c<<8);
-            new_node->subnet_bits = 24;
-            break;
-          case 4:
-            new_node->ip.addr.in4 = (a<<24) | (b<<16) | (c<<8) | d;
-            new_node->subnet_bits = 32;
-            break;
-          default:
-            assert(0);
-        }
-      }
-      
-      if (slashpos) {
-        int specified_subnet_bits, n;
-        n = sscanf(slashpos+1, "%d", &specified_subnet_bits);
-        if (n == 1) {
-          new_node->subnet_bits = specified_subnet_bits;
-        } else {
-          command_parse_error();
-        }
-      }
+  if (!CPS_ParseAllowDeny(line, &all, &ip, &subnet_bits))
+    command_parse_error();
 
-    } else {
-      if (!slashpos && DNS_Name2IPAddress(p, &ip_addr, 1) == DNS_Success) {
-        new_node = (AllowDeny *)ARR_GetNewElement(restrictions);
-        new_node->allow = allow;
-        new_node->all = all;
-        new_node->ip = ip_addr;
-        if (ip_addr.family == IPADDR_INET6)
-          new_node->subnet_bits = 128;
-        else
-          new_node->subnet_bits = 32;
-      } else {
-        command_parse_error();
-      }      
-    }
-  }
+  node = ARR_GetNewElement(restrictions);
+  node->allow = allow;
+  node->all = all;
+  node->ip = ip;
+  node->subnet_bits = subnet_bits;
 }
   
 /* ================================================== */