From 5d67c3dcd623fb61ca6ec4b427eeeb51daeca71e Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sat, 7 Feb 2009 20:16:50 +0100 Subject: [PATCH] Put IPv4-specific parts inside the ACL subsystem The ACL subsystem performs access validation based on IPv4 address / netmask pairs. Since the internals of this system are exposed via struct sender_command_data, other subsystems can only use IPv4. This patch migrates the IPv4-specific parts of the ACL subsystem inside that system and replaces the 'struct in_addr' address with a host string. A subsequent patch converts the remaining subsystems to also use strings instead of AF-dependent addresses. For the present purpose the string size (fixed) is over-dimensioned, since a valid IPv4 address contains at most 15 = 4*3 + 3 + 1 bytes (including the 3 dots and the '\0'). The size should also be sufficient for hostnames, since RFC 1123, 2.1 suggests a maximum length of 255. Since the conversion string -> struct in_addr now happens later, syntax checks have been added for argument strings. --- acl.c | 31 +++++++++++++------------------ acl.h | 6 ++---- command.c | 5 +++-- net.h | 15 +++++++++++++++ send_common.c | 4 ++-- server.h | 2 ++ 6 files changed, 37 insertions(+), 26 deletions(-) diff --git a/acl.c b/acl.c index 52eba1d4..14edcf7d 100644 --- a/acl.c +++ b/acl.c @@ -73,14 +73,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) +static 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/%i to access list\n", addr, ai->netmask); para_list_add(&ai->node, acl); } @@ -91,21 +90,18 @@ 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, int netmask) { struct access_info *ai, *tmp; list_for_each_entry_safe(ai, tmp, acl, node) { - char *nad = para_strdup(inet_ntoa(ai->addr)); - if (!strcmp(nad, inet_ntoa(addr)) && + if (!strcmp(addr, inet_ntoa(ai->addr)) && ai->netmask == netmask) { PARA_NOTICE_LOG("removing %s/%i from access list\n", - nad, ai->netmask); + addr, ai->netmask); list_del(&ai->node); free(ai); } - free(nad); } } @@ -146,18 +142,17 @@ void acl_init(struct list_head *acl, char * const *acl_info, int num) 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)) + if (!is_valid_ipv4_address(arg)) goto err; netmask = atoi(++p); if (netmask < 0 || netmask > 32) goto err; - acl_add_entry(acl, addr, netmask); + acl_add_entry(acl, arg, netmask); goto success; err: PARA_CRIT_LOG("syntax error: %s\n", acl_info[i]); @@ -193,8 +188,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); @@ -210,8 +205,8 @@ void acl_allow(struct in_addr addr, int netmask, * \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); } diff --git a/acl.h b/acl.h index 60185937..e6090a88 100644 --- a/acl.h +++ b/acl.h @@ -9,7 +9,5 @@ void acl_init(struct list_head *acl, char * const *acl_info, int num); 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); +void acl_allow(char *addr, int mask, struct list_head *acl, int default_deny); +void acl_deny(char *addr, int mask, struct list_head *acl, int default_deny); diff --git a/command.c b/command.c index 9abe04a3..988eae64 100644 --- a/command.c +++ b/command.c @@ -192,7 +192,7 @@ static int check_sender_args(int argc, char * const * argv, struct sender_comman case SENDER_ALLOW: if (argc != 4 && argc != 5) return -E_COMMAND_SYNTAX; - if (!inet_pton(AF_INET, argv[3], &scd->addr)) + if (!is_valid_ipv4_address(argv[3])) return -E_COMMAND_SYNTAX; scd->netmask = 32; if (argc == 5) { @@ -200,6 +200,7 @@ static int check_sender_args(int argc, char * const * argv, struct sender_comman if (scd->netmask < 0 || scd->netmask > 32) return -E_COMMAND_SYNTAX; } + strncpy(scd->host, argv[3], sizeof(scd->host)); break; case SENDER_ADD: case SENDER_DELETE: @@ -254,7 +255,7 @@ int com_sender(int fd, int argc, char * const * argv) usleep(100 * 1000); continue; } - mmd->sender_cmd_data = scd; + memcpy(&mmd->sender_cmd_data, &scd, sizeof(scd)); mutex_unlock(mmd_mutex); break; } diff --git a/net.h b/net.h index 3c6628c2..8ec9fa52 100644 --- a/net.h +++ b/net.h @@ -3,6 +3,7 @@ * * Licensed under the GPL v2. For licencing details see COPYING. */ +#include /** \file net.h exported symbols from net.c */ @@ -24,6 +25,20 @@ #endif /** \endcond */ +/** + * Ensure that string conforms to the IPv4 address format. + * + * \param address The address string to check. + * + * \return 1 if \a address conforms to the IPv4 address format, else 0. + */ +_static_inline_ bool is_valid_ipv4_address(const char *address) +{ + struct in_addr test_it; + + return inet_pton(AF_INET, address, &test_it) != 0; +} + /** * Generic socket creation (passive and active sockets). */ diff --git a/send_common.c b/send_common.c index d1dcaeb1..f570273f 100644 --- a/send_common.c +++ b/send_common.c @@ -259,7 +259,7 @@ char *get_sender_info(struct sender_status *ss, char *name) void generic_com_allow(struct sender_command_data *scd, struct sender_status *ss) { - acl_allow(scd->addr, scd->netmask, &ss->acl, ss->default_deny); + acl_allow(scd->host, scd->netmask, &ss->acl, ss->default_deny); } /** @@ -273,7 +273,7 @@ void generic_com_allow(struct sender_command_data *scd, void generic_com_deny(struct sender_command_data *scd, struct sender_status *ss) { - acl_deny(scd->addr, scd->netmask, &ss->acl, ss->default_deny); + acl_deny(scd->host, scd->netmask, &ss->acl, ss->default_deny); } /** diff --git a/server.h b/server.h index b133d82e..8d1d6752 100644 --- a/server.h +++ b/server.h @@ -36,6 +36,8 @@ struct sender_command_data{ int sender_num; /** Used for the allow/deny/add/remove subcommands. */ struct in_addr addr; + /** Used for the allow/deny/add/remove subcommands. */ + char host[256]; /** Used for allow/deny. */ int netmask; /** The port number for add/remove. */ -- 2.39.5