From 8157cf8316ef9b3769933d5b17e169b400d36da8 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Mon, 4 Feb 2008 22:22:57 +0100 Subject: [PATCH] Implement access control for the dccp sender. Introduce new acl functions to avoid duplicate code in the http/dccp sender. --- NEWS | 1 + acl.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++--- acl.h | 10 +++++----- dccp_send.c | 25 ++++++++++++++++++++++-- error.h | 6 ++++-- http_send.c | 21 +++++++------------- server.ggo | 11 +++++++++++ 7 files changed, 103 insertions(+), 26 deletions(-) diff --git a/NEWS b/NEWS index 6bf968ab..103eda1f 100644 --- 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 53a4170c..fb9cded6 100644 --- 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 9f43e6ca..0e53ce05 100644 --- 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); diff --git a/dccp_send.c b/dccp_send.c index 7b7c8051..d0f9448e 100644 --- a/dccp_send.c +++ b/dccp_send.c @@ -28,9 +28,12 @@ #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 644c8044..5f27f1c9 100644 --- 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 \ diff --git a/http_send.c b/http_send.c index 63bfec03..9a55ba0e 100644 --- a/http_send.c +++ b/http_send.c @@ -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; } diff --git a/server.ggo b/server.ggo index 19c8bd9b..62e08305 100644 --- a/server.ggo +++ b/server.ggo @@ -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" #~~~~~~~~~~~~~~~~~~~~ -- 2.39.5