Avoid warning about sys/sysctl.h on glibc-2.30.
[paraslash.git] / acl.c
diff --git a/acl.c b/acl.c
index 72869ee8c79f71756dad66ebac0763592c07be39..2c90052658eda947ea586a55f292dc85f24e68f7 100644 (file)
--- a/acl.c
+++ b/acl.c
@@ -1,16 +1,20 @@
-/*
- * Copyright (C) 2005-2009 Andre Noll <maan@systemlinux.org>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
 
 /** \file acl.c Access control lists for paraslash senders. */
 
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <regex.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <netdb.h>
+
 #include "para.h"
 #include "error.h"
 #include "string.h"
 #include "list.h"
 #include "net.h"
+#include "acl.h"
 
 /**
  * Describes one entry in the blacklist/whitelist of a paraslash sender.
@@ -27,10 +31,12 @@ struct access_info {
 /**
  * Return true if addr_1 matches addr_2 in the first `netmask' bits.
  */
-static int v4_addr_match(uint32_t addr_1, uint32_t addr_2, uint8_t netmask)
+static bool v4_addr_match(uint32_t addr_1, uint32_t addr_2, uint8_t netmask)
 {
        uint32_t mask = ~0U;
 
+       if (netmask == 0) /* avoid 32-bit shift, which is undefined in C. */
+               return true;
        if (netmask < 32)
                mask <<= (32 - netmask);
        return (htonl(addr_1) & mask) == (htonl(addr_2) & mask);
@@ -55,7 +61,7 @@ static int acl_lookup(int fd, struct list_head *acl)
                PARA_ERROR_LOG("Can not determine peer address: %s\n", strerror(errno));
                goto no_match;
        }
-       v4_addr = extract_v4_addr(&ss);
+       extract_v4_addr(&ss, &v4_addr);
        if (!v4_addr.s_addr)
                goto no_match;
 
@@ -73,14 +79,13 @@ no_match:
  * \param addr The address to add.
  * \param netmask The netmask to use for this entry.
  */
-static void acl_add_entry(struct list_head *acl, struct in_addr addr,
-               int netmask)
+void acl_add_entry(struct list_head *acl, char *addr, int netmask)
 {
        struct access_info *ai = para_malloc(sizeof(struct access_info));
-       ai->addr = addr;
+
+       inet_pton(AF_INET, addr, &ai->addr);
        ai->netmask = netmask;
-       PARA_INFO_LOG("adding %s/%i to access list\n", inet_ntoa(ai->addr),
-               ai->netmask);
+       PARA_INFO_LOG("adding %s/%u to access list\n", addr, ai->netmask);
        para_list_add(&ai->node, acl);
 }
 
@@ -91,21 +96,26 @@ static void acl_add_entry(struct list_head *acl, struct in_addr addr,
  * \param addr The address to delete.
  * \param netmask The netmask of the entry to be removed from the list.
  */
-static void acl_del_entry(struct list_head *acl, struct in_addr addr,
-               int netmask)
+static void acl_del_entry(struct list_head *acl, char *addr, unsigned netmask)
 {
        struct access_info *ai, *tmp;
+       struct in_addr to_delete;
+
+       PARA_NOTICE_LOG("removing entries matching %s/%u\n", addr, netmask);
+       inet_pton(AF_INET, addr, &to_delete);
 
        list_for_each_entry_safe(ai, tmp, acl, node) {
-               char *nad = para_strdup(inet_ntoa(ai->addr));
-               if (!strcmp(nad, inet_ntoa(addr)) &&
-                               ai->netmask == netmask) {
-                       PARA_NOTICE_LOG("removing %s/%i from access list\n",
-                               nad, ai->netmask);
+               if (v4_addr_match(to_delete.s_addr, ai->addr.s_addr,
+                                       PARA_MIN(netmask, ai->netmask))) {
+                       char dst[INET_ADDRSTRLEN + 1];
+                       const char *p = inet_ntop(AF_INET, &ai->addr.s_addr,
+                               dst, sizeof(dst));
+                       if (p)
+                               PARA_INFO_LOG("removing %s/%u\n", p,
+                                       ai->netmask);
                        list_del(&ai->node);
                        free(ai);
                }
-               free(nad);
        }
 }
 
@@ -123,7 +133,7 @@ char *acl_get_contents(struct list_head *acl)
        char *ret = NULL;
 
        list_for_each_entry_safe(ai, tmp_ai, acl, node) {
-               char *tmp = make_message("%s%s/%d ", ret? ret : "",
+               char *tmp = make_message("%s%s/%u ", ret? ret : "",
                        inet_ntoa(ai->addr), ai->netmask);
                free(ret);
                ret = tmp;
@@ -131,42 +141,6 @@ char *acl_get_contents(struct list_head *acl)
        return ret;
 }
 
-/**
- * Initialize an access control list.
- *
- * \param acl The list to initialize.
- * \param acl_info An array of strings of the form ip/netmask.
- * \param num The number of strings in \a acl_info.
- */
-void acl_init(struct list_head *acl, char * const *acl_info, int num)
-{
-       int i;
-
-       INIT_LIST_HEAD(acl);
-       for (i = 0; i < num; i++) {
-               char *arg = para_strdup(acl_info[i]);
-               char *p = strchr(arg, '/');
-               struct in_addr addr;
-               int netmask;
-
-               if (!p)
-                       goto err;
-               *p = '\0';
-               if (!inet_pton(AF_INET, arg, &addr))
-                       goto err;
-               netmask = atoi(++p);
-               if (netmask < 0 || netmask > 32)
-                       goto err;
-               acl_add_entry(acl, addr, netmask);
-               goto success;
-err:
-               PARA_CRIT_LOG("syntax error: %s\n", acl_info[i]);
-success:
-               free(arg);
-               continue;
-       }
-}
-
 /**
  * Check whether the peer name of a given fd is allowed by an acl.
  *
@@ -193,8 +167,8 @@ int acl_check_access(int fd, struct list_head *acl, int default_deny)
  * \param acl The access control list.
  * \param default_deny Whether \a acl is a whitelist.
  */
-void acl_allow(struct in_addr addr, int netmask,
-               struct list_head *acl, int default_deny)
+void acl_allow(char *addr, int netmask,
+              struct list_head *acl, int default_deny)
 {
        if (default_deny)
                acl_add_entry(acl, addr, netmask);
@@ -205,13 +179,13 @@ void acl_allow(struct in_addr addr, int netmask,
 /**
  * Deny access for a range of IP addresses.
  *
- * \param addr The address to permit.
- * \param netmask The netmask of the entry to be permitted.
+ * \param addr The address to deny.
+ * \param netmask The netmask of the entry to be denied.
  * \param acl The access control list.
  * \param default_deny Whether \a acl is a whitelist.
  */
-void acl_deny(struct in_addr addr, int netmask,
-               struct list_head *acl, int default_deny)
+void acl_deny(char *addr, int netmask,
+             struct list_head *acl, int default_deny)
 {
        acl_allow(addr, netmask, acl, !default_deny);
 }