diff options
Diffstat (limited to '')
-rw-r--r-- | src/acl.c | 503 |
1 files changed, 264 insertions, 239 deletions
@@ -33,23 +33,27 @@ /* Define how long an IPv6 address is in bytes (128 bits, 16 bytes) */ #define IPV6_LEN 16 -enum acl_type { ACL_STRING, ACL_NUMERIC }; +enum acl_type +{ ACL_STRING, ACL_NUMERIC }; /* * Hold the information about a particular access control. We store * whether it's an ALLOW or DENY entry, and also whether it's a string * entry (like a domain name) or an IP entry. */ -struct acl_s { - acl_access_t access; - enum acl_type type; - union { - char *string; - struct { - unsigned char octet[IPV6_LEN]; - unsigned char mask[IPV6_LEN]; - } ip; - } address; +struct acl_s +{ + acl_access_t access; + enum acl_type type; + union + { + char *string; + struct + { + unsigned char octet[IPV6_LEN]; + unsigned char mask[IPV6_LEN]; + } ip; + } address; }; /* @@ -67,41 +71,45 @@ static vector_t access_list = NULL; * */ inline static int -fill_netmask_array(char *bitmask_string, unsigned char array[], unsigned int len) +fill_netmask_array (char *bitmask_string, unsigned char array[], + unsigned int len) { - unsigned int i; - long int mask; - char *endptr; - - errno = 0; /* to distinguish success/failure after call */ - mask = strtol(bitmask_string, &endptr, 10); - - /* check for various conversion errors */ - if ((errno == ERANGE && (mask == LONG_MIN || mask == LONG_MAX)) - || (errno != 0 && mask == 0) - || (endptr == bitmask_string)) - return -1; - - /* valid range for a bit mask */ - if (mask < 0 || mask > (8 * len)) - return -1; - - /* we have a valid range to fill in the array */ - for (i = 0; i != len; ++i) { - if (mask >= 8) { - array[i] = 0xff; - mask -= 8; - } - else if (mask > 0) { - array[i] = (unsigned char)(0xff << (8 - mask)); - mask = 0; - } - else { - array[i] = 0; - } - } - - return 0; + unsigned int i; + long int mask; + char *endptr; + + errno = 0; /* to distinguish success/failure after call */ + mask = strtol (bitmask_string, &endptr, 10); + + /* check for various conversion errors */ + if ((errno == ERANGE && (mask == LONG_MIN || mask == LONG_MAX)) + || (errno != 0 && mask == 0) || (endptr == bitmask_string)) + return -1; + + /* valid range for a bit mask */ + if (mask < 0 || mask > (8 * len)) + return -1; + + /* we have a valid range to fill in the array */ + for (i = 0; i != len; ++i) + { + if (mask >= 8) + { + array[i] = 0xff; + mask -= 8; + } + else if (mask > 0) + { + array[i] = (unsigned char) (0xff << (8 - mask)); + mask = 0; + } + else + { + array[i] = 0; + } + } + + return 0; } @@ -115,74 +123,82 @@ fill_netmask_array(char *bitmask_string, unsigned char array[], unsigned int len * 0 otherwise. */ int -insert_acl(char *location, acl_access_t access_type) +insert_acl (char *location, acl_access_t access_type) { - struct acl_s acl; - int ret; - char *p, ip_dst[IPV6_LEN]; - - assert(location != NULL); - - /* - * If the access list has not been set up, create it. - */ - if (!access_list) { - access_list = vector_create(); - if (!access_list) { - log_message(LOG_ERR, - "Unable to allocate memory for access list"); - return -1; - } - } - - /* - * Start populating the access control structure. - */ - memset(&acl, 0, sizeof(struct acl_s)); - acl.access = access_type; - - /* - * Check for a valid IP address (the simplest case) first. - */ - if (full_inet_pton(location, ip_dst) > 0) { - acl.type = ACL_NUMERIC; - memcpy(acl.address.ip.octet, ip_dst, IPV6_LEN); - memset(acl.address.ip.mask, 0xff, IPV6_LEN); - } else { - /* - * At this point we're either a hostname or an - * IP address with a slash. - */ - p = strchr(location, '/'); - if (p != NULL) { - /* - * We have a slash, so it's intended to be an - * IP address with mask - */ - *p = '\0'; - if (full_inet_pton(location, ip_dst) <= 0) - return -1; - - acl.type = ACL_NUMERIC; - memcpy(acl.address.ip.octet, ip_dst, IPV6_LEN); - - if (fill_netmask_array(p + 1, &(acl.address.ip.mask[0]), IPV6_LEN) < 0) - return -1; - } else { - /* In all likelihood a string */ - acl.type = ACL_STRING; - acl.address.string = safestrdup(location); - if (!acl.address.string) - return -1; - } - } - - /* - * Add the entry and then clean up. - */ - ret = vector_append(access_list, &acl, sizeof(struct acl_s)); - safefree(acl.address.string); - return ret; + struct acl_s acl; + int ret; + char *p, ip_dst[IPV6_LEN]; + + assert (location != NULL); + + /* + * If the access list has not been set up, create it. + */ + if (!access_list) + { + access_list = vector_create (); + if (!access_list) + { + log_message (LOG_ERR, "Unable to allocate memory for access list"); + return -1; + } + } + + /* + * Start populating the access control structure. + */ + memset (&acl, 0, sizeof (struct acl_s)); + acl.access = access_type; + + /* + * Check for a valid IP address (the simplest case) first. + */ + if (full_inet_pton (location, ip_dst) > 0) + { + acl.type = ACL_NUMERIC; + memcpy (acl.address.ip.octet, ip_dst, IPV6_LEN); + memset (acl.address.ip.mask, 0xff, IPV6_LEN); + } + else + { + /* + * At this point we're either a hostname or an + * IP address with a slash. + */ + p = strchr (location, '/'); + if (p != NULL) + { + /* + * We have a slash, so it's intended to be an + * IP address with mask + */ + *p = '\0'; + if (full_inet_pton (location, ip_dst) <= 0) + return -1; + + acl.type = ACL_NUMERIC; + memcpy (acl.address.ip.octet, ip_dst, IPV6_LEN); + + if (fill_netmask_array (p + 1, &(acl.address.ip.mask[0]), IPV6_LEN) + < 0) + return -1; + } + else + { + /* In all likelihood a string */ + acl.type = ACL_STRING; + acl.address.string = safestrdup (location); + if (!acl.address.string) + return -1; + } + } + + /* + * Add the entry and then clean up. + */ + ret = vector_append (access_list, &acl, sizeof (struct acl_s)); + safefree (acl.address.string); + return ret; } /* @@ -195,73 +211,79 @@ insert_acl(char *location, acl_access_t access_type) * -1 if no tests match, so skip */ static int -acl_string_processing(struct acl_s *acl, - const char *ip_address, const char *string_address) +acl_string_processing (struct acl_s *acl, + const char *ip_address, const char *string_address) { - int match; - struct addrinfo hints, *res, *ressave; - size_t test_length, match_length; - char ipbuf[512]; - - assert(acl && acl->type == ACL_STRING); - assert(ip_address && strlen(ip_address) > 0); - assert(string_address && strlen(string_address) > 0); - - /* - * If the first character of the ACL string is a period, we need to - * do a string based test only; otherwise, we can do a reverse - * lookup test as well. - */ - if (acl->address.string[0] != '.') { - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - if (getaddrinfo(acl->address.string, NULL, &hints, &res) != 0) - goto STRING_TEST; - - ressave = res; - - match = FALSE; - do { - get_ip_string(res->ai_addr, ipbuf, sizeof(ipbuf)); - if (strcmp(ip_address, ipbuf) == 0) { - match = TRUE; - break; - } - } while ((res = res->ai_next) != NULL); - - freeaddrinfo(ressave); - - if (match) { - if (acl->access == ACL_DENY) - return 0; - else - return 1; - } - } - - STRING_TEST: - test_length = strlen(string_address); - match_length = strlen(acl->address.string); - - /* - * If the string length is shorter than AC string, return a -1 so - * that the "driver" will skip onto the next control in the list. - */ - if (test_length < match_length) - return -1; - - if (strcasecmp - (string_address + (test_length - match_length), - acl->address.string) == 0) { - if (acl->access == ACL_DENY) - return 0; - else - return 1; - } - - /* Indicate that no tests succeeded, so skip to next control. */ - return -1; + int match; + struct addrinfo hints, *res, *ressave; + size_t test_length, match_length; + char ipbuf[512]; + + assert (acl && acl->type == ACL_STRING); + assert (ip_address && strlen (ip_address) > 0); + assert (string_address && strlen (string_address) > 0); + + /* + * If the first character of the ACL string is a period, we need to + * do a string based test only; otherwise, we can do a reverse + * lookup test as well. + */ + if (acl->address.string[0] != '.') + { + memset (&hints, 0, sizeof (struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo (acl->address.string, NULL, &hints, &res) != 0) + goto STRING_TEST; + + ressave = res; + + match = FALSE; + do + { + get_ip_string (res->ai_addr, ipbuf, sizeof (ipbuf)); + if (strcmp (ip_address, ipbuf) == 0) + { + match = TRUE; + break; + } + } + while ((res = res->ai_next) != NULL); + + freeaddrinfo (ressave); + + if (match) + { + if (acl->access == ACL_DENY) + return 0; + else + return 1; + } + } + +STRING_TEST: + test_length = strlen (string_address); + match_length = strlen (acl->address.string); + + /* + * If the string length is shorter than AC string, return a -1 so + * that the "driver" will skip onto the next control in the list. + */ + if (test_length < match_length) + return -1; + + if (strcasecmp + (string_address + (test_length - match_length), + acl->address.string) == 0) + { + if (acl->access == ACL_DENY) + return 0; + else + return 1; + } + + /* Indicate that no tests succeeded, so skip to next control. */ + return -1; } /* @@ -273,28 +295,29 @@ acl_string_processing(struct acl_s *acl, * -1 neither allowed nor denied. */ static int -check_numeric_acl(const struct acl_s *acl, const char *ip) +check_numeric_acl (const struct acl_s *acl, const char *ip) { - uint8_t addr[IPV6_LEN], x, y; - int i; + uint8_t addr[IPV6_LEN], x, y; + int i; - assert(acl && acl->type == ACL_NUMERIC); - assert(ip && strlen(ip) > 0); + assert (acl && acl->type == ACL_NUMERIC); + assert (ip && strlen (ip) > 0); - if (full_inet_pton(ip, &addr) <= 0) - return -1; + if (full_inet_pton (ip, &addr) <= 0) + return -1; - for (i = 0; i != IPV6_LEN; ++i) { - x = addr[i] & acl->address.ip.mask[i]; - y = acl->address.ip.octet[i] & acl->address.ip.mask[i]; + for (i = 0; i != IPV6_LEN; ++i) + { + x = addr[i] & acl->address.ip.mask[i]; + y = acl->address.ip.octet[i] & acl->address.ip.mask[i]; - /* If x and y don't match, the IP addresses don't match */ - if (x != y) - return 0; - } + /* If x and y don't match, the IP addresses don't match */ + if (x != y) + return 0; + } - /* The addresses match, return the permission */ - return (acl->access == ACL_ALLOW); + /* The addresses match, return the permission */ + return (acl->access == ACL_ALLOW); } /* @@ -305,50 +328,52 @@ check_numeric_acl(const struct acl_s *acl, const char *ip) * 0 if denied */ int -check_acl(int fd, const char *ip, const char *host) +check_acl (int fd, const char *ip, const char *host) { - struct acl_s *acl; - int perm; - size_t i; - - assert(fd >= 0); - assert(ip != NULL); - assert(host != NULL); - - /* - * If there is no access list allow everything. - */ - if (!access_list) - return 1; - - for (i = 0; i != vector_length(access_list); ++i) { - acl = vector_getentry(access_list, i, NULL); - switch (acl->type) { - case ACL_STRING: - perm = acl_string_processing(acl, ip, host); - break; - - case ACL_NUMERIC: - if (ip[0] == '\0') - continue; - perm = check_numeric_acl(acl, ip); - break; - } - - /* - * Check the return value too see if the IP address is - * allowed or denied. - */ - if (perm == 0) - break; - else if (perm == 1) - return perm; - } - - /* - * Deny all connections by default. - */ - log_message(LOG_NOTICE, "Unauthorized connection from \"%s\" [%s].", - host, ip); - return 0; + struct acl_s *acl; + int perm; + size_t i; + + assert (fd >= 0); + assert (ip != NULL); + assert (host != NULL); + + /* + * If there is no access list allow everything. + */ + if (!access_list) + return 1; + + for (i = 0; i != vector_length (access_list); ++i) + { + acl = vector_getentry (access_list, i, NULL); + switch (acl->type) + { + case ACL_STRING: + perm = acl_string_processing (acl, ip, host); + break; + + case ACL_NUMERIC: + if (ip[0] == '\0') + continue; + perm = check_numeric_acl (acl, ip); + break; + } + + /* + * Check the return value too see if the IP address is + * allowed or denied. + */ + if (perm == 0) + break; + else if (perm == 1) + return perm; + } + + /* + * Deny all connections by default. + */ + log_message (LOG_NOTICE, "Unauthorized connection from \"%s\" [%s].", + host, ip); + return 0; } |