andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 4 months ago
Clone
Blob Blame History Raw
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