Implement access control for the dccp sender.
authorAndre Noll <maan@systemlinux.org>
Mon, 4 Feb 2008 21:22:57 +0000 (22:22 +0100)
committerAndre Noll <maan@systemlinux.org>
Mon, 4 Feb 2008 21:22:57 +0000 (22:22 +0100)
Introduce new acl functions to avoid duplicate code
in the http/dccp sender.

NEWS
acl.c
acl.h
dccp_send.c
error.h
http_send.c
server.ggo

diff --git a/NEWS b/NEWS
index 6bf968a..103eda1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ NEWS
 
        - Share some similar/duplicate code between the http and the dccp sender.
        - Generic access control lists for paraslash senders.
+       - Access control for the dccp sender.
        - Update to gengetopt-2.22
        - fix a bug in the "off" command of the http sender.
        - fix some fd and memory leaks.
diff --git a/acl.c b/acl.c
index 53a4170..fb9cded 100644 (file)
--- a/acl.c
+++ b/acl.c
@@ -45,7 +45,7 @@ static int v4_addr_match(uint32_t addr_1, uint32_t addr_2, uint8_t netmask)
  *
  * \return One if \a fd belongs to \a acl, zero otherwise.
  */
-int acl_lookup(int fd, struct list_head *acl)
+static int acl_lookup(int fd, struct list_head *acl)
 {
        struct access_info *ai, *tmp;
        struct sockaddr_storage ss;
@@ -74,7 +74,7 @@ no_match:
  * \param addr The address to add.
  * \param netmask The netmask to use for this entry.
  */
-void acl_add_entry(struct list_head *acl, struct in_addr addr,
+static void acl_add_entry(struct list_head *acl, struct in_addr addr,
                int netmask)
 {
        struct access_info *ai = para_malloc(sizeof(struct access_info));
@@ -93,7 +93,7 @@ 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.
  */
-void acl_del_entry(struct list_head *acl, struct in_addr addr,
+static void acl_del_entry(struct list_head *acl, struct in_addr addr,
                int netmask)
 {
        struct access_info *ai, *tmp;
@@ -169,3 +169,52 @@ success:
        }
 }
 
+
+/**
+ * Check whether the peer name of a given fd is allowed by an acl.
+ *
+ * \param fd File descriptor.
+ * \param acl The access control list.
+ * \param default_deny Whether \a acl is a whitelist.
+ *
+ * \return Positive if the peer of \a fd is permitted by \a acl, \p -E_ACL_PERM
+ * otherwise.
+ */
+int acl_check_access(int fd, struct list_head *acl, int default_deny)
+{
+       int match = acl_lookup(fd, acl);
+
+       return (!match || default_deny) && (match || !default_deny)?
+               1 : -E_ACL_PERM;
+}
+
+/**
+ * Permit access for a range of IP addresses.
+ *
+ * \param addr The address to permit.
+ * \param netmask The netmask of the entry to be permitted.
+ * \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)
+{
+       if (default_deny)
+               acl_add_entry(acl, addr, netmask);
+       else
+               acl_del_entry(acl, addr, 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 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)
+{
+       acl_allow(addr, netmask, acl, !default_deny);
+}
diff --git a/acl.h b/acl.h
index 9f43e6c..0e53ce0 100644 (file)
--- a/acl.h
+++ b/acl.h
@@ -7,9 +7,9 @@
 /** \file acl.h Exported functions of acl.c. */
 
 void acl_init(struct list_head *acl, char * const *acl_info, int num);
-int acl_lookup(int fd, struct list_head *acl);
-void acl_add_entry(struct list_head *acl, struct in_addr addr,
-               int netmask);
-void acl_del_entry(struct list_head *acl, struct in_addr addr,
-               int netmask);
 char *acl_get_contents(struct list_head *acl);
+int acl_check_access(int fd, struct list_head *acl, int default_deny);
+void acl_allow(struct in_addr addr, int netmask,
+               struct list_head *acl, int default_deny);
+void acl_deny(struct in_addr addr, int netmask,
+               struct list_head *acl, int default_deny);
index 7b7c805..d0f9448 100644 (file)
 #include "close_on_fork.h"
 #include "chunk_queue.h"
 #include "server.cmdline.h"
+#include "acl.h"
 
 /** the list of connected clients **/
 static struct list_head clients;
+/** The whitelist/blacklist. */
+static struct list_head dccp_acl;
 static int listen_fd = -1;
 
 /** Maximal number of bytes in a chunk queue. */
@@ -69,6 +72,9 @@ static void dccp_post_select(fd_set *rfds, __a_unused fd_set *wfds)
                goto err;
        }
        ret = mark_fd_nonblocking(fd);
+       if (ret < 0)
+               goto err;
+       ret = acl_check_access(fd, &dccp_acl, conf.dccp_default_deny_given);
        if (ret < 0)
                goto err;
        sc = para_calloc(sizeof(*sc));
@@ -102,6 +108,20 @@ static void dccp_shutdown_clients(void)
                shutdown_client(sc);
 }
 
+static int dccp_com_deny(struct sender_command_data *scd)
+{
+       acl_deny(scd->addr, scd->netmask, &dccp_acl,
+               conf.dccp_default_deny_given);
+       return 1;
+}
+
+static int dccp_com_allow(struct sender_command_data *scd)
+{
+       acl_allow(scd->addr, scd->netmask, &dccp_acl,
+               conf.dccp_default_deny_given);
+       return 1;
+}
+
 static char *dccp_info(void)
 {
        int num_clients = 0;
@@ -138,10 +158,11 @@ void dccp_send_init(struct sender *s)
        s->help = dccp_help;
        s->client_cmds[SENDER_ON] = NULL;
        s->client_cmds[SENDER_OFF] = NULL;
-       s->client_cmds[SENDER_DENY] = NULL;
-       s->client_cmds[SENDER_ALLOW] = NULL;
+       s->client_cmds[SENDER_DENY] = dccp_com_deny;
+       s->client_cmds[SENDER_ALLOW] = dccp_com_allow;
        s->client_cmds[SENDER_ADD] = NULL;
        s->client_cmds[SENDER_DELETE] = NULL;
+       acl_init(&dccp_acl, conf.dccp_access_arg, conf.dccp_access_given);
        ret = open_sender(IPPROTO_DCCP, conf.dccp_port_arg);
        if (ret < 0)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
diff --git a/error.h b/error.h
index 644c804..5f27f1c 100644 (file)
--- a/error.h
+++ b/error.h
@@ -27,11 +27,14 @@ DEFINE_ERRLIST_OBJECT_ENUM;
 #define AFH_COMMON_ERRORS
 #define RBTREE_ERRORS
 #define RECV_ERRORS
-#define ACL_ERRORS
 #define SEND_COMMON_ERRORS
 
 extern const char **para_errlist[];
 
+#define ACL_ERRORS \
+       PARA_ERROR(ACL_PERM, "access denied by acl"), \
+
+
 #define FSCK_ERRORS \
        PARA_ERROR(FSCK_SYNTAX, "fsck syntax error"), \
        PARA_ERROR(RANGE_VIOLATION, "range violation detected, very bad"), \
@@ -320,7 +323,6 @@ extern const char **para_errlist[];
 #define HTTP_SEND_ERRORS \
        PARA_ERROR(WRITE_OK, "can not check whether fd is writable"), \
        PARA_ERROR(MAX_CLIENTS, "maximal number of clients exceeded"), \
-       PARA_ERROR(ACL_PERM, "access denied by acl"), \
 
 
 #define COMMAND_ERRORS \
index 63bfec0..9a55ba0 100644 (file)
@@ -98,7 +98,7 @@ static void http_send(long unsigned current_chunk,
 
 static void http_post_select(fd_set *rfds, __a_unused fd_set *wfds)
 {
-       int ret, fd, match;
+       int ret, fd;
        struct sender_client *sc, *tmp;
        struct private_http_sender_data *phsd;
 
@@ -147,11 +147,8 @@ static void http_post_select(fd_set *rfds, __a_unused fd_set *wfds)
        ret = mark_fd_nonblocking(fd);
        if (ret < 0)
                goto err_out;
-       match = acl_lookup(fd, &http_acl);
-       PARA_DEBUG_LOG("acl lookup returned %d\n", match);
-       ret = -E_ACL_PERM;
-       if ((match && !conf.http_default_deny_given) ||
-                       (!match && conf.http_default_deny_given))
+       ret = acl_check_access(fd, &http_acl, conf.http_default_deny_given);
+       if (ret < 0)
                goto err_out;
        numclients++;
        sc = para_calloc(sizeof(*sc));
@@ -207,19 +204,15 @@ static int http_com_off(__a_unused struct sender_command_data *scd)
 
 static int http_com_deny(struct sender_command_data *scd)
 {
-       if (conf.http_default_deny_given)
-               acl_del_entry(&http_acl, scd->addr, scd->netmask);
-       else
-               acl_add_entry(&http_acl, scd->addr, scd->netmask);
+       acl_deny(scd->addr, scd->netmask, &http_acl,
+               conf.http_default_deny_given);
        return 1;
 }
 
 static int http_com_allow(struct sender_command_data *scd)
 {
-       if (conf.http_default_deny_given)
-               acl_add_entry(&http_acl, scd->addr, scd->netmask);
-       else
-               acl_del_entry(&http_acl, scd->addr, scd->netmask);
+       acl_allow(scd->addr, scd->netmask, &http_acl,
+               conf.http_default_deny_given);
        return 1;
 }
 
index 19c8bd9..62e0830 100644 (file)
@@ -231,8 +231,19 @@ option "dccp_port" -
        default="8000"
        optional
 
+option "dccp_default_deny" -
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"See http_default_deny"
+
+       flag off
 
+option "dccp_access" -
+#~~~~~~~~~~~~~~~~~~~~~
+"See http_access"
 
+       string typestr="a.b.c.d/n"
+       optional
+       multiple
 
 section "ortp sender"
 #~~~~~~~~~~~~~~~~~~~~