From b791dc9fbd1b88d033d848e3cb0db8f93e2dbff5 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mareynol@redhat.com>
Date: Wed, 9 May 2012 16:03:59 -0400
Subject: [PATCH 374/375] Ticket #196 - RFE: Interpret IPV6 addresses for ACIs,
replication, and chaining
Bug Description: replication, chaining, and access control do not hanbdle IPv6 addresses
Fix Description: For replication and chaining, we just needed to put brackets "[]" around
the IP address in the ldap urls. We also need to update
convert_to_openldap_uri(), which is called by slapi_ldap_init_ext().
Access control needed to remove the IPv6 restriction check, and update
libaccess to be IPv6 aware.
https://fedorahosted.org/389/ticket/196
Reviewed by: Norkio!
(cherry picked from commit 4d7d59e756d5dc2dbc04c7ee95759f211795a093)
(cherry picked from commit 44413ce12710f310d377727399abc8f9a870c5eb)
---
ldap/servers/plugins/acl/acllas.c | 53 +--
ldap/servers/plugins/replication/repl5_plugins.c | 7 +-
ldap/servers/plugins/replication/windows_private.c | 7 +-
ldap/servers/slapd/ldaputil.c | 90 +++--
ldap/servers/slapd/slapi-plugin.h | 9 +
lib/libaccess/lasip.cpp | 397 ++++++++++++++++-----
lib/libaccess/lasip.h | 3 +-
7 files changed, 407 insertions(+), 159 deletions(-)
diff --git a/ldap/servers/plugins/acl/acllas.c b/ldap/servers/plugins/acl/acllas.c
index fc7f185..a0cc53d 100644
--- a/ldap/servers/plugins/acl/acllas.c
+++ b/ldap/servers/plugins/acl/acllas.c
@@ -281,16 +281,12 @@ int
DS_LASIpGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t
auth_info, PList_t global_auth, void *arg)
{
+ struct acl_pblock *aclpb = NULL;
+ PRNetAddr *client_praddr = NULL;
+ char ip_str[256];
+ int rv = LAS_EVAL_TRUE;
- struct acl_pblock *aclpb = NULL;
- IPAddr_t ip=0;
- PRNetAddr client_praddr;
- struct in_addr client_addr;
- int rv;
-
-
- rv = ACL_GetAttribute(errp, DS_PROP_ACLPB, (void **)&aclpb,
- subject, resource, auth_info, global_auth);
+ rv = ACL_GetAttribute(errp, DS_PROP_ACLPB, (void **)&aclpb, subject, resource, auth_info, global_auth);
if ( rv != LAS_EVAL_TRUE || ( NULL == aclpb )) {
acl_print_acllib_err(errp, NULL);
slapi_log_error( SLAPI_LOG_ACL, plugin_name,
@@ -298,29 +294,34 @@ DS_LASIpGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t
return LAS_EVAL_FAIL;
}
- if ( slapi_pblock_get( aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR,
- &client_praddr ) != 0 ) {
- slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "Could not get client IP.\n" );
- return( LAS_EVAL_FAIL );
- }
-
- if ( !PR_IsNetAddrType(&client_praddr, PR_IpAddrV4Mapped) ) {
- slapi_log_error( SLAPI_LOG_ACL, plugin_name,
- "Client address is IPv6. ACLs only support IPv4 addresses so far.\n");
+ client_praddr = (PRNetAddr *)slapi_ch_malloc(sizeof(PRNetAddr));
+ if(client_praddr == NULL){
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "DS_LASIpGetter: failed to allocate client_praddr\n");
return( LAS_EVAL_FAIL );
}
-
- client_addr.s_addr = client_praddr.ipv6.ip.pr_s6_addr32[3];
- ip = (IPAddr_t) ntohl( client_addr.s_addr );
- rv = PListInitProp(subject, 0, ACL_ATTR_IP, (void *)ip, NULL);
+ if ( slapi_pblock_get( aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR, client_praddr ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "DS_LASIpGetter: Could not get client IP.\n" );
+ slapi_ch_free((void **)&client_praddr);
+ return( LAS_EVAL_FAIL );
+ }
- slapi_log_error( SLAPI_LOG_ACL, plugin_name,
- "Returning client ip address '%s'\n",
- (slapi_is_loglevel_set(SLAPI_LOG_ACL) ? inet_ntoa(client_addr) : ""));
+ rv = PListInitProp(subject, 0, ACL_ATTR_IP, (void *)client_praddr, NULL);
+ if (rv < 0) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "DS_LASIpGetter: "
+ "Couldn't set the client addr property(%d)\n", rv );
+ slapi_ch_free((void **)&client_praddr);
+ return LAS_EVAL_FAIL;
+ }
+ if( PR_NetAddrToString(client_praddr, ip_str, sizeof(ip_str)) == PR_SUCCESS){
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "DS_LASIpGetter: "
+ "Returning client ip address '%s'\n", ip_str);
+ } else {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "DS_LASIpGetter: "
+ "Returning client ip address 'unknown'\n");
+ }
return LAS_EVAL_TRUE;
-
}
/*
diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c
index afb0364..dddbf15 100644
--- a/ldap/servers/plugins/replication/repl5_plugins.c
+++ b/ldap/servers/plugins/replication/repl5_plugins.c
@@ -133,7 +133,12 @@ multimaster_set_local_purl()
}
else
{
- local_purl = slapi_ch_smprintf("ldap://%s:%s", host, port);
+ if(slapi_is_ipv6_addr(host)){
+ /* need to put brackets around the ipv6 address */
+ local_purl = slapi_ch_smprintf("ldap://[%s]:%s", host, port);
+ } else {
+ local_purl = slapi_ch_smprintf("ldap://%s:%s", host, port);
+ }
}
/* slapi_ch_free acceptS NULL pointer */
diff --git a/ldap/servers/plugins/replication/windows_private.c b/ldap/servers/plugins/replication/windows_private.c
index a103cad..4381943 100644
--- a/ldap/servers/plugins/replication/windows_private.c
+++ b/ldap/servers/plugins/replication/windows_private.c
@@ -321,7 +321,12 @@ const char* windows_private_get_purl(const Repl_Agmt *ra)
char *hostname;
hostname = agmt_get_hostname(ra);
- windows_purl = slapi_ch_smprintf("ldap://%s:%d", hostname, agmt_get_port(ra));
+ if(slapi_is_ipv6_addr(hostname)){
+ /* need to put brackets around the ipv6 address */
+ windows_purl = slapi_ch_smprintf("ldap://[%s]:%d", hostname, agmt_get_port(ra));
+ } else {
+ windows_purl = slapi_ch_smprintf("ldap://%s:%d", hostname, agmt_get_port(ra));
+ }
slapi_ch_free_string(&hostname);
return windows_purl;
diff --git a/ldap/servers/slapd/ldaputil.c b/ldap/servers/slapd/ldaputil.c
index 331dd71..4b8c16d 100644
--- a/ldap/servers/slapd/ldaputil.c
+++ b/ldap/servers/slapd/ldaputil.c
@@ -165,55 +165,59 @@ convert_to_openldap_uri(const char *hostname_or_uri, int port, const char *proto
char *my_copy = NULL;
char *start = NULL;
char *iter = NULL;
+ char *ptr = NULL;
char *s = NULL;
const char *brkstr = " ";
+ int done = 0;
if (!hostname_or_uri) {
- return NULL;
+ return NULL;
+ }
+
+ if(slapi_is_ipv6_addr(hostname_or_uri)){
+ /* We need to encapsulate the ipv6 addr with brackets */
+ my_copy = slapi_ch_smprintf("[%s]",hostname_or_uri);
+ } else {
+ my_copy = slapi_ch_strdup(hostname_or_uri);
}
- my_copy = slapi_ch_strdup(hostname_or_uri);
/* see if hostname_or_uri is an ldap uri */
if (!proto && !PL_strncasecmp(my_copy, "ldap", 4)) {
- start = my_copy + 4;
- if ((*start == 's') || (*start == 'i')) {
- start++;
- }
- if (!PL_strncmp(start, "://", 3)) {
- *start = '\0';
- proto = my_copy;
- start += 3;
- } else {
- slapi_log_error(SLAPI_LOG_FATAL, "convert_to_openldap_uri",
- "The given LDAP URI [%s] is not valid\n", hostname_or_uri);
- goto end;
- }
+ start = my_copy + 4;
+ if ((*start == 's') || (*start == 'i')) {
+ start++;
+ }
+ if (!PL_strncmp(start, "://", 3)) {
+ *start = '\0';
+ proto = my_copy;
+ start += 3;
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, "convert_to_openldap_uri",
+ "The given LDAP URI [%s] is not valid\n", hostname_or_uri);
+ goto end;
+ }
} else if (!proto) {
- slapi_log_error(SLAPI_LOG_FATAL, "convert_to_openldap_uri",
- "The given LDAP URI [%s] is not valid\n", hostname_or_uri);
- goto end;
+ slapi_log_error(SLAPI_LOG_FATAL, "convert_to_openldap_uri",
+ "The given LDAP URI [%s] is not valid\n", hostname_or_uri);
+ goto end;
} else {
- start = my_copy; /* just assume it's not a uri */
+ start = my_copy; /* just assume it's not a uri */
}
- for (s = ldap_utf8strtok_r(my_copy, brkstr, &iter); s != NULL;
- s = ldap_utf8strtok_r(NULL, brkstr, &iter)) {
- char *ptr;
- int last = 0;
- /* strtok will grab the '/' at the end of the uri, if any,
- so terminate parsing there */
- if ((ptr = strchr(s, '/'))) {
- *ptr = '\0';
- last = 1;
- }
- if (retstr) {
- retstr = PR_sprintf_append(retstr, "/ %s://%s", proto, s);
- } else {
- retstr = PR_smprintf("%s://%s", proto, s);
- }
- if (last) {
- break;
- }
+ for (s = ldap_utf8strtok_r(my_copy, brkstr, &iter); s != NULL; s = ldap_utf8strtok_r(NULL, brkstr, &iter)) {
+ /* strtok will grab the '/' at the end of the uri, if any, so terminate parsing there */
+ if ((ptr = strchr(s, '/'))) {
+ *ptr = '\0';
+ done = 1;
+ }
+ if (retstr) {
+ retstr = PR_sprintf_append(retstr, "/ %s://%s", proto, s);
+ } else {
+ retstr = PR_smprintf("%s://%s", proto, s);
+ }
+ if (done) {
+ break;
+ }
}
/* add the port on the last one */
@@ -2271,3 +2275,15 @@ mozldap_ldap_explode_rdn( const char *rdn, const int notypes )
return( mozldap_ldap_explode( rdn, notypes, LDAP_RDN ) );
}
+int
+slapi_is_ipv6_addr( const char *hostname ){
+ PRNetAddr addr;
+
+ if(PR_StringToNetAddr(hostname, &addr) == PR_SUCCESS &&
+ !PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped) &&
+ addr.raw.family == PR_AF_INET6)
+ {
+ return 1;
+ }
+ return 0;
+}
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 75d5aa9..cb15a25 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -3015,6 +3015,15 @@ void slapi_rdn_set_rdn(Slapi_RDN *rdn,const Slapi_RDN *fromrdn);
void slapi_rdn_free(Slapi_RDN **rdn);
/**
+ * Checks if the value of ipAddress is a IPv6 address
+ *
+ * \param ipAddress is a string that is either an IPv4 or IPv6 address
+ * \return 1 if address is an IPv6 address
+ * \return 0 if address is an IPv4 address
+ */
+int slapi_is_ipv6_addr( const char *ipAddress);
+
+/**
* Frees and clears the contents of a \c Slapi_RDN structure from memory.
*
* Both the RDN value and the array of split RDNs are freed. Those pointers
diff --git a/lib/libaccess/lasip.cpp b/lib/libaccess/lasip.cpp
index 7f5c01e..e66f48a 100644
--- a/lib/libaccess/lasip.cpp
+++ b/lib/libaccess/lasip.cpp
@@ -60,6 +60,8 @@
#include "aclcache.h"
#include <libaccess/dbtlibaccess.h>
#include <libaccess/aclerror.h>
+#include <prio.h>
+#include "nspr.h"
#define LAS_IP_IS_CONSTANT(x) (((x) == (LASIpTree_t *)LAS_EVAL_TRUE) || ((x) == (LASIpTree_t *)LAS_EVAL_FALSE))
@@ -67,8 +69,9 @@
extern int LASIpGetIp();
#endif
-static int
-LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop);
+static int colonhex_ipv6(char *ipstr, char *netmaskstr, PRIPv6Addr *ipv6, int *netmask);
+static int LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop);
+static int LASIpAddPatternIPv6(NSErr_t *errp, int netmask, PRIPv6Addr *ipv6, LASIpTree_t **treetop);
/* dotdecimal
* Takes netmask and ip strings and returns the numeric values,
@@ -259,68 +262,108 @@ LASIpTreeDealloc(LASIpTree_t *startnode)
* ret code The usual LAS return codes.
*/
static int
-LASIpBuild(NSErr_t *errp, char *attr_name, CmpOp_t comparator, char *attr_pattern, LASIpTree_t **treetop)
+LASIpBuild(NSErr_t *errp, char *attr_name, CmpOp_t comparator, char *attr_pattern, LASIpContext_t *context)
{
unsigned int delimiter; /* length of valid token */
char token[64], token2[64]; /* a single ip[+netmask] */
char *curptr; /* current place in attr_pattern */
- int netmask, ip;
+ int netmask = 0;
+ int ip = 0;
char *plusptr;
- int retcode;
+ int retcode;
- if (NULL == treetop) {
+ if (NULL == context) {
return ACL_RES_ERROR;
}
- /* ip address can be delimited by space, tab, comma, or carriage return
- * only.
+ /*
+ * IP address can be delimited by space, tab, comma, or carriage return only.
*/
curptr = attr_pattern;
do {
delimiter = strcspn(curptr, ", \t");
delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
strncpy(token, curptr, delimiter);
- if (delimiter >= sizeof(token)) {
+ if (delimiter >= sizeof(token)) {
return LAS_EVAL_INVALID;
- }
+ }
token[delimiter] = '\0';
/* skip all the white space after the token */
- curptr = strpbrk((curptr+delimiter), "1234567890+.*");
-
- /* Is there a netmask? */
- plusptr = strchr(token, '+');
- if (plusptr == NULL) {
- if (curptr && (*curptr == '+')) {
- /* There was a space before (and possibly after) the plus sign*/
- curptr = strpbrk((++curptr), "1234567890.*");
- delimiter = strcspn(curptr, ", \t");
- delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
- if (delimiter >= sizeof(token2)) {
- return LAS_EVAL_INVALID;
- }
- strncpy(token2, curptr, delimiter);
- token2[delimiter] = '\0';
- retcode = dotdecimal(token, token2, &ip, &netmask);
+ curptr = strpbrk((curptr+delimiter), "1234567890+.*ABCDEFabcdef:/");
+
+ /*
+ * IPv4 addresses do not have ":"
+ */
+ if( strstr(token,":") == NULL ){
+ /* Is there a netmask? */
+ plusptr = strchr(token, '+');
+ if (plusptr == NULL) {
+ if (curptr && (*curptr == '+')) {
+ /* There was a space before (and possibly after) the plus sign*/
+ curptr = strpbrk((++curptr), "1234567890.*");
+ delimiter = strcspn(curptr, ", \t");
+ delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
+ if (delimiter >= sizeof(token2)) {
+ return LAS_EVAL_INVALID;
+ }
+ strncpy(token2, curptr, delimiter);
+ token2[delimiter] = '\0';
+ retcode = dotdecimal(token, token2, &ip, &netmask);
+ if (retcode)
+ return (retcode);
+ curptr = strpbrk((++curptr), "1234567890+.*");
+ } else {
+ retcode = dotdecimal(token, "255.255.255.255", &ip, &netmask);
+ if (retcode)
+ return (retcode);
+ }
+ } else {
+ /* token is the IP addr string in both cases */
+ *plusptr ='\0'; /* truncate the string */
+ retcode =dotdecimal(token, ++plusptr, &ip, &netmask);
if (retcode)
return (retcode);
- curptr = strpbrk((++curptr), "1234567890+.*");
+ }
+
+ if (LASIpAddPattern(errp, netmask, ip, &context->treetop) != 0)
+ return LAS_EVAL_INVALID;
+ } else {
+ /*
+ * IPv6
+ */
+ PRIPv6Addr ipv6;
+
+ plusptr = strchr(token, '/');
+ if (plusptr == NULL) {
+ if (curptr && (*curptr == '/')) {
+ /* There was a space before (and possibly after) the plus sign */
+ curptr = strpbrk((++curptr), "1234567890.*:ABCDEFabcdef");
+ delimiter = strcspn(curptr, ", \t");
+ delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
+ strncpy(token2, curptr, delimiter);
+ token2[delimiter] = '\0';
+ retcode = colonhex_ipv6(token, token2, &ipv6, &netmask);
+ if (retcode)
+ return (retcode);
+ curptr = strpbrk((++curptr), "1234567890+.:ABCDEFabcdef*");
+ } else {
+ retcode = colonhex_ipv6(token, "128", &ipv6, &netmask);
+ if (retcode)
+ return (retcode);
+ }
} else {
- retcode =dotdecimal(token, "255.255.255.255", &ip, &netmask);
+ /* token is the IP addr string in both cases */
+ *plusptr ='\0'; /* truncate the string */
+ retcode = colonhex_ipv6(token, ++plusptr, &ipv6, &netmask);
if (retcode)
return (retcode);
}
- } else {
- /* token is the IP addr string in both cases */
- *plusptr ='\0'; /* truncate the string */
- retcode =dotdecimal(token, ++plusptr, &ip, &netmask);
- if (retcode)
- return (retcode);
- }
-
- if (LASIpAddPattern(errp, netmask, ip, treetop) != 0)
- return LAS_EVAL_INVALID;
+ if (LASIpAddPatternIPv6(errp, netmask, &ipv6, &context->treetop_ipv6) != (int)NULL) {
+ return LAS_EVAL_INVALID;
+ }
+ }
} while ((curptr != NULL) && (delimiter != 0));
return 0;
@@ -361,13 +404,15 @@ LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop)
if (*treetop == (LASIpTree_t *)NULL) { /* No tree at all */
curptr = LASIpTreeAllocNode(errp);
if (curptr == NULL) {
- nserrGenerate(errp, ACLERRFAIL, ACLERR5100, ACL_Program, 1, XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_));
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5100, ACL_Program, 1,
+ XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_));
return ACL_RES_ERROR;
}
*treetop = curptr;
}
- /* Special case if the netmask is 0.
+ /*
+ * Special case if the netmask is 0.
*/
if (stopbit > 31) {
(*treetop)->action[0] = (LASIpTree_t *)LAS_EVAL_TRUE;
@@ -375,24 +420,18 @@ LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop)
return 0;
}
-
/* follow the tree down the pattern path bit by bit until the
* end of the tree is reached (i.e. a constant).
*/
for (curbit=31,curptr=*treetop; curbit >= 0; curbit--) {
-
/* Is the current bit ON? If so set curval to 1 else 0 */
curval = (pattern & (1<<curbit)) ? 1 : 0;
/* Are we done, if so remove the rest of the tree */
if (curbit == stopbit) {
LASIpTreeDealloc(curptr->action[curval]);
- curptr->action[curval] =
- (LASIpTree_t *)LAS_EVAL_TRUE;
-
- /* This is the normal exit point. Most other
- * exits must be due to errors.
- */
+ curptr->action[curval] = (LASIpTree_t *)LAS_EVAL_TRUE;
+ /* This is the normal exit point. Most other exits must be due to errors. */
return 0;
}
@@ -401,7 +440,8 @@ LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop)
newptr = LASIpTreeAllocNode(errp);
if (newptr == NULL) {
LASIpTreeDealloc(*treetop);
- nserrGenerate(errp, ACLERRFAIL, ACLERR5110, ACL_Program, 1, XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_1));
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5110, ACL_Program, 1,
+ XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_1));
return ACL_RES_ERROR;
}
curptr->action[curval] = newptr;
@@ -451,51 +491,57 @@ int LASIpEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
PList_t subject, PList_t resource, PList_t auth_info,
PList_t global_auth)
{
- int bit;
- int value;
- IPAddr_t ip;
- int retcode;
- LASIpTree_t *node;
- LASIpContext_t *context = NULL;
- int rv;
- char ip_str[124];
+ LASIpContext_t *context = NULL;
+ LASIpTree_t *node = NULL;
+ IPAddr_t ip;
+ PRNetAddr *client_addr = NULL;
+ struct in_addr client_inaddr;
+ char ip_str[124];
+ int retcode;
+ int value;
+ int bit;
+ int rc = LAS_EVAL_INVALID;
+ int rv;
*cachable = ACL_INDEF_CACHABLE;
if (strcmp(attr_name, "ip") != 0) {
- nserrGenerate(errp, ACLERRINVAL, ACLERR5200, ACL_Program, 2, XP_GetAdminStr(DBT_lasIpBuildReceivedRequestForAttr_), attr_name);
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5200, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasIpBuildReceivedRequestForAttr_), attr_name);
return LAS_EVAL_INVALID;
}
if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
- nserrGenerate(errp, ACLERRINVAL, ACLERR5210, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalIllegalComparatorDN_), comparator_string(comparator));
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5210, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasipevalIllegalComparatorDN_), comparator_string(comparator));
return LAS_EVAL_INVALID;
}
- /* GET THE IP ADDR FROM THE SESSION CONTEXT AND STORE IT IN THE
- * VARIABLE ip.
+ /*
+ * Get the IP addr from the session context, and store it in "client_addr
*/
#ifndef UTEST
- rv = ACL_GetAttribute(errp, ACL_ATTR_IP, (void **)&ip,
- subject, resource, auth_info, global_auth);
+ rv = ACL_GetAttribute(errp, ACL_ATTR_IP, (void **)&client_addr, subject, resource, auth_info, global_auth);
if (rv != LAS_EVAL_TRUE) {
if (subject || resource) {
/* Don't ereport if called from ACL_CachableAclList */
- char rv_str[16];
- sprintf(rv_str, "%d", rv);
- nserrGenerate(errp, ACLERRINVAL, ACLERR5220, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalUnableToGetSessionAddre_), rv_str);
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5220, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasipevalUnableToGetSessionAddre_), rv_str);
}
- return LAS_EVAL_FAIL;
+ return LAS_EVAL_FAIL;
}
#else
ip = (IPAddr_t)LASIpGetIp();
#endif
- /* If this is the first time through, build the pattern tree first.
+ /*
+ * If this is the first time through, build the pattern tree first.
*/
if (*LAS_cookie == NULL) {
- if (strcspn(attr_pattern, "0123456789.*,+ \t")) {
+ if (strcspn(attr_pattern, "0123456789.*,+ \tABCDEFabcdef:/")) {
return LAS_EVAL_INVALID;
}
ACL_CritEnter();
@@ -503,13 +549,14 @@ int LASIpEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
*LAS_cookie = context =
(LASIpContext_t *)PERM_MALLOC(sizeof(LASIpContext_t));
if (context == NULL) {
- nserrGenerate(errp, ACLERRNOMEM, ACLERR5230, ACL_Program, 1, XP_GetAdminStr(DBT_lasipevalUnableToAllocateContext_));
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR5230, ACL_Program, 1,
+ XP_GetAdminStr(DBT_lasipevalUnableToAllocateContext_));
ACL_CritExit();
return LAS_EVAL_FAIL;
}
context->treetop = NULL;
- retcode = LASIpBuild(errp, attr_name, comparator, attr_pattern,
- &context->treetop);
+ context->treetop_ipv6 = NULL;
+ retcode = LASIpBuild(errp, attr_name, comparator, attr_pattern, context);
if (retcode) {
ACL_CritExit();
return (retcode);
@@ -523,30 +570,194 @@ int LASIpEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
context = (LASIpContext *) *LAS_cookie;
ACL_CritExit();
}
+ /*
+ * Check if IP is ipv4/ipv6
+ */
+ if ( PR_IsNetAddrType( client_addr, PR_IpAddrV4Mapped) || client_addr->raw.family == PR_AF_INET ) {
+ /*
+ * IPv4
+ */
+
+ /* Set the appropriate s_addr for ipv4 or ipv4 mapped to ipv6 */
+ if (client_addr->raw.family == PR_AF_INET) {
+ client_inaddr.s_addr = client_addr->inet.ip;
+ } else {
+ client_inaddr.s_addr = client_addr->ipv6.ip._S6_un._S6_u32[3];
+ }
+
+ node = context->treetop;
+ ip = (IPAddr_t)PR_ntohl( client_inaddr.s_addr );
+
+ if(node == NULL){
+ rc = (comparator == CMP_OP_EQ ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ } else {
+ for (bit = 31; bit >= 0; bit--) {
+ value = (ip & (IPAddr_t) (1 << bit)) ? 1 : 0;
+ if (LAS_IP_IS_CONSTANT(node->action[value])){
+ /* Reached a result, so return it */
+ if (comparator == CMP_OP_EQ){
+ rc = (int)(PRSize)node->action[value];
+ break;
+ } else {
+ rc = ((int)(PRSize)node->action[value] == LAS_EVAL_TRUE) ? LAS_EVAL_FALSE : LAS_EVAL_TRUE;
+ break;
+ }
+ } else {
+ /* Move on to the next bit */
+ node = node->action[value];
+ }
+ }
+ }
+ if(rc == LAS_EVAL_INVALID){
+ sprintf(ip_str, "%x", (unsigned int)ip);
+ nserrGenerate(errp, ACLERRINTERNAL, ACLERR5240, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasipevalReach32BitsWithoutConcl_), ip_str);
+ }
+ } else {
+ /*
+ * IPv6
+ */
+ PRIPv6Addr *ipv6 = &(client_addr->ipv6.ip);
+ LASIpTree_t *node;
+ int bit_position = 15;
+ int field = 0;
+ int addr = 0;
+ int value;
+
+ node = context->treetop_ipv6;
+ if ( node == NULL ) {
+ retcode = (comparator == CMP_OP_EQ ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ } else {
+ addr = PR_ntohs( ipv6->_S6_un._S6_u16[field]);
+ for (bit = 127; bit >= 0 ; bit--, bit_position--) {
+ value = (addr & (1 << bit_position)) ? 1 : 0;
+ if (LAS_IP_IS_CONSTANT(node->action[value])) {
+ /* Reached a result, so return it */
+ if (comparator == CMP_OP_EQ){
+ return(int)(long)node->action[value];
+ } else {
+ return(((int)(long)node->action[value] == LAS_EVAL_TRUE) ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+ } else {
+ node = node->action[value];
+ if ( bit % 16 == 0) {
+ /* Ok, move to the next field in the IPv6 addr: f:f:next:f:f:f:f:f */
+ field++;
+ addr = PR_ntohs( ipv6->_S6_un._S6_u16[field]);
+ bit_position = 15;
+ }
+ }
+ }
+ rc = LAS_EVAL_INVALID;
+ }
+ }
+ return rc;
+}
+
+/*
+ * The ipv6 version of LASIpAddPattern
+ */
+static int
+LASIpAddPatternIPv6(NSErr_t *errp, int netmask, PRIPv6Addr *ipv6, LASIpTree_t **treetop)
+{
+ LASIpTree_t *curptr;
+ LASIpTree_t *newptr;
+ int stopbit;
+ int curbit;
+ int curval;
+ int field = 0; /* (8) 16 bit fields in a IPv6 address: x:x:x:x:x:x:x:x */
+ int addr = 0;
+ int curbit_position = 15; /* 16 bits: 0-15 */
+
+ /* stop at the first 1 in the netmask from low to high */
+ stopbit = 128 - netmask;
- node = context->treetop;
-
- for (bit=31; bit >=0; bit--) {
- value = (ip & (IPAddr_t) (1<<bit)) ? 1 : 0;
- if (LAS_IP_IS_CONSTANT(node->action[value])) {
- /* Reached a result, so return it */
- if (comparator == CMP_OP_EQ)
- return((int)(PRSize)node->action[value]);
- else
- return(((int)(PRSize)node->action[value] ==
- LAS_EVAL_TRUE) ?
- LAS_EVAL_FALSE : LAS_EVAL_TRUE);
-
- } else
- /* Move on to the next bit */
- node = node->action[value];
+ /* Special case if there's no tree. Allocate the first node */
+ if (*treetop == (LASIpTree_t *)NULL) { /* No tree at all */
+ curptr = LASIpTreeAllocNode(errp);
+ if (curptr == NULL) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5100, ACL_Program, 1,
+ XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_));
+ return ACL_RES_ERROR;
+ }
+ *treetop = curptr;
+ }
+
+ addr = PR_ntohs(ipv6->_S6_un._S6_u16[field]);
+ for (curbit = 127, curptr = *treetop; curbit >= 0; curbit--, curbit_position--){
+ /* Is the current bit ON? If so set curval to 1 else 0 */
+ curval = (addr & (1 << curbit_position)) ? 1 : 0;
+
+ /* Are we done, if so remove the rest of the tree */
+ if (curbit == stopbit) {
+ LASIpTreeDealloc(curptr->action[curval]);
+ curptr->action[curval] = (LASIpTree_t *)LAS_EVAL_TRUE;
+ /* This is the normal exit point. Most other exits must be due to errors. */
+ return 0;
+ }
+
+ /* Oops reached the end - must allocate */
+ if (LAS_IP_IS_CONSTANT(curptr->action[curval])) {
+ newptr = LASIpTreeAllocNode(errp);
+ if (newptr == NULL) {
+ LASIpTreeDealloc(*treetop);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5110, ACL_Program, 1,
+ XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_1));
+ return ACL_RES_ERROR;
+ }
+ curptr->action[curval] = newptr;
+ }
+
+ /* Keep going down the tree */
+ curptr = curptr->action[curval];
+
+ if ( curbit % 16 == 0) {
+ /* Ok, move to the next field in the addr */
+ field++;
+ addr = PR_ntohs(ipv6->_S6_un._S6_u16[field]);
+ curbit_position = 15;
+ }
}
+ return ACL_RES_ERROR;
+}
- /* Cannot reach here. Even a 32 bit mismatch has a conclusion in
- * the pattern tree.
+/*
+ * This is very similar to dotdecimal(), but for ipv6 addresses
+ */
+static int
+colonhex_ipv6(char *ipstr, char *netmaskstr, PRIPv6Addr *ipv6, int *netmask)
+{
+ PRNetAddr addr;
+ /*
+ * Validate netmaskstr - can only be digits
+ */
+ if (strcspn(netmaskstr, "0123456789")){
+ return LAS_EVAL_INVALID;
+ }
+ /*
+ * Validate ipstr - can only have digits, colons, hex chars, and dots
+ */
+ if(strcspn(ipstr, "0123456789:ABCDEFabcdef.")){
+ return LAS_EVAL_INVALID;
+ }
+ /*
+ * validate the netmask - must be between 1 and 128
*/
- sprintf(ip_str, "%x", (unsigned int)ip);
- nserrGenerate(errp, ACLERRINTERNAL, ACLERR5240, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalReach32BitsWithoutConcl_), ip_str);
- return LAS_EVAL_INVALID;
+ *netmask = atoi(netmaskstr);
+ if(*netmask < 1 || *netmask > 128){
+ return LAS_EVAL_INVALID;
+ }
+ /*
+ * Get the net addr
+ */
+ if (PR_StringToNetAddr(ipstr, &addr) != PR_SUCCESS){
+ return LAS_EVAL_INVALID;
+ }
+ /*
+ * Set the ipv6 addr
+ */
+ *ipv6 = addr.ipv6.ip;
+
+ return 0;
}
diff --git a/lib/libaccess/lasip.h b/lib/libaccess/lasip.h
index c353d9d..c1fe0fc 100644
--- a/lib/libaccess/lasip.h
+++ b/lib/libaccess/lasip.h
@@ -46,5 +46,6 @@ typedef struct LASIpTree {
} LASIpTree_t;
typedef struct LASIpContext {
- LASIpTree_t *treetop; /* Top of the pattern tree */
+ LASIpTree_t *treetop; /* Top of the pattern tree */
+ LASIpTree_t *treetop_ipv6; /* Top of the IPv6 pattern tree */
} LASIpContext_t;
--
2.4.3