]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
implement full IPv6 support in ACLs; use URL notation (as suggested by Howard) to...
authorPierangelo Masarati <ando@openldap.org>
Fri, 15 Dec 2006 01:11:11 +0000 (01:11 +0000)
committerPierangelo Masarati <ando@openldap.org>
Fri, 15 Dec 2006 01:11:11 +0000 (01:11 +0000)
servers/slapd/acl.c
servers/slapd/aclparse.c
servers/slapd/daemon.c
servers/slapd/slap.h

index 8a4c43e496233960fbd05db26fc5e135afa9ebce..39857052f8244932f2286658f8f3640c1cfc8031 100644 (file)
@@ -40,6 +40,9 @@
 #define ACL_BUF_SIZE   1024    /* use most appropriate size */
 
 static const struct berval     acl_bv_ip_eq = BER_BVC( "IP=" );
+#ifdef LDAP_PF_INET6
+static const struct berval     acl_bv_ipv6_eq = BER_BVC( "IP=[" );
+#endif /* LDAP_PF_INET6 */
 #ifdef LDAP_PF_LOCAL
 static const struct berval     acl_bv_path_eq = BER_BVC("PATH=");
 #endif /* LDAP_PF_LOCAL */
@@ -242,7 +245,6 @@ slap_access_allowed(
                        }
                }
 
-vd_access:
                control = slap_acl_mask( a, &mask, op,
                        e, desc, val, MAXREMATCHES, matches, count, state );
 
@@ -1317,6 +1319,58 @@ slap_acl_mask(
                                                if ( (addr & b->a_peername_mask) != b->a_peername_addr )
                                                        continue;
 
+#ifdef LDAP_PF_INET6
+                                       /* extract IPv6 and try exact match */
+                                       } else if ( b->a_peername_style == ACL_STYLE_IPV6 ) {
+                                               char            *port;
+                                               char            buf[] = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF";
+                                               struct berval   ip;
+                                               struct in6_addr addr;
+                                               int             port_number = -1, i;
+                                               
+                                               if ( strncasecmp( op->o_conn->c_peer_name.bv_val, 
+                                                                       acl_bv_ipv6_eq.bv_val,
+                                                                       acl_bv_ipv6_eq.bv_len ) != 0 ) 
+                                                       continue;
+
+                                               ip.bv_val = op->o_conn->c_peer_name.bv_val + acl_bv_ipv6_eq.bv_len;
+                                               ip.bv_len = op->o_conn->c_peer_name.bv_len - acl_bv_ipv6_eq.bv_len;
+
+                                               port = strrchr( ip.bv_val, ']' );
+                                               if ( port ) {
+                                                       ip.bv_len = port - ip.bv_val;
+                                                       ++port;
+                                                       if ( port[0] == ':' && lutil_atoi( &port_number, ++port ) != 0 )
+                                                               continue;
+                                               }
+                                               
+                                               /* the port check can be anticipated here */
+                                               if ( b->a_peername_port != -1 && port_number != b->a_peername_port )
+                                                       continue;
+                                               
+                                               /* address longer than expected? */
+                                               if ( ip.bv_len >= sizeof(buf) )
+                                                       continue;
+
+                                               AC_MEMCPY( buf, ip.bv_val, ip.bv_len );
+                                               buf[ ip.bv_len ] = '\0';
+
+                                               if ( inet_pton( AF_INET6, buf, &addr ) != 1 )
+                                                       continue;
+
+                                               /* check mask */
+                                               for ( i = 0; i < 4; i++ ) {
+                                                       if ( ( addr.s6_addr32[i] & b->a_peername_mask6.s6_addr32[i] )
+                                                               != b->a_peername_addr6.s6_addr32[i] )
+                                                       {
+                                                               break;
+                                                       }
+                                               }
+
+                                               if ( i != 4 )
+                                                       continue;
+#endif /* LDAP_PF_INET6 */
+
 #ifdef LDAP_PF_LOCAL
                                        /* extract path and try exact match */
                                        } else if ( b->a_peername_style == ACL_STYLE_PATH ) {
index d5bdf1b6e1839f374875b4d6221ca00dfc546f57..e151d10e812ef8e1bb67a94647d5cc3138d29703 100644 (file)
@@ -804,6 +804,14 @@ parse_acl(
                                } else if ( strcasecmp( style, "ip" ) == 0 ) {
                                        sty = ACL_STYLE_IP;
 
+                               } else if ( strcasecmp( style, "ipv6" ) == 0 ) {
+#ifndef LDAP_PF_INET6
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "%s: line %d: IPv6 not supported\n",
+                                               fname, lineno, 0 );
+#endif /* ! LDAP_PF_INET6 */
+                                       sty = ACL_STYLE_IPV6;
+
                                } else if ( strcasecmp( style, "path" ) == 0 ) {
                                        sty = ACL_STYLE_PATH;
 #ifndef LDAP_PF_LOCAL
@@ -1301,6 +1309,7 @@ parse_acl(
                                        case ACL_STYLE_EXPAND:
                                                /* cheap replacement to regex for simple expansion */
                                        case ACL_STYLE_IP:
+                                       case ACL_STYLE_IPV6:
                                        case ACL_STYLE_PATH:
                                                /* legal, peername specific */
                                                break;
@@ -1384,6 +1393,52 @@ parse_acl(
                                                                        goto fail;
                                                                }
                                                        }
+
+#ifdef LDAP_PF_INET6
+                                               } else if ( sty == ACL_STYLE_IPV6 ) {
+                                                       char            *addr = NULL,
+                                                                       *mask = NULL,
+                                                                       *port = NULL;
+
+                                                       split( right, '{', &addr, &port );
+                                                       split( addr, '%', &addr, &mask );
+
+                                                       if ( inet_pton( AF_INET6, addr, &b->a_peername_addr6 ) != 1 ) {
+                                                               /* illegal address */
+                                                               Debug( LDAP_DEBUG_ANY, "%s: line %d: "
+                                                                       "illegal peername address \"%s\".\n",
+                                                                       fname, lineno, addr );
+                                                               goto fail;
+                                                       }
+
+                                                       if ( mask == NULL ) {
+                                                               mask = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF";
+                                                       }
+
+                                                       if ( inet_pton( AF_INET6, mask, &b->a_peername_mask6 ) != 1 ) {
+                                                               /* illegal mask */
+                                                               Debug( LDAP_DEBUG_ANY, "%s: line %d: "
+                                                                       "illegal peername address mask "
+                                                                       "\"%s\".\n",
+                                                                       fname, lineno, mask );
+                                                               goto fail;
+                                                       }
+
+                                                       b->a_peername_port = -1;
+                                                       if ( port ) {
+                                                               char    *end = NULL;
+
+                                                               b->a_peername_port = strtol( port, &end, 10 );
+                                                               if ( end == port || end[0] != '}' ) {
+                                                                       /* illegal port */
+                                                                       Debug( LDAP_DEBUG_ANY, "%s: line %d: "
+                                                                               "illegal peername port specification "
+                                                                               "\"{%s}\".\n",
+                                                                               fname, lineno, port );
+                                                                       goto fail;
+                                                               }
+                                                       }
+#endif /* LDAP_PF_INET6 */
                                                }
                                        }
                                        continue;
index ccafda3a12bfab3202c8d9efe297d93d8fe9d715..fb07060016e6216047d58765f8d82acb903c11d4 100644 (file)
@@ -1388,9 +1388,9 @@ slap_open_listener(
                        inet_ntop( AF_INET6, &((struct sockaddr_in6 *)*sal)->sin6_addr,
                                addr, sizeof addr);
                        port = ntohs( ((struct sockaddr_in6 *)*sal)->sin6_port );
-                       l.sl_name.bv_len = strlen(addr) + sizeof("IP= 65535");
+                       l.sl_name.bv_len = strlen(addr) + sizeof("IP=[]:65535");
                        l.sl_name.bv_val = ber_memalloc( l.sl_name.bv_len );
-                       snprintf( l.sl_name.bv_val, l.sl_name.bv_len, "IP=%s %d", 
+                       snprintf( l.sl_name.bv_val, l.sl_name.bv_len, "IP=[%s]:%d", 
                                addr, port );
                        l.sl_name.bv_len = strlen( l.sl_name.bv_val );
                } break;
@@ -1595,7 +1595,7 @@ slap_listener(
 #ifdef LDAP_PF_LOCAL
        char peername[MAXPATHLEN + sizeof("PATH=")];
 #elif defined(LDAP_PF_INET6)
-       char peername[sizeof("IP=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535")];
+       char peername[sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535")];
 #else /* ! LDAP_PF_LOCAL && ! LDAP_PF_INET6 */
        char peername[sizeof("IP=255.255.255.255:65336")];
 #endif /* LDAP_PF_LOCAL */
@@ -1759,7 +1759,7 @@ slap_listener(
                peeraddr = (char *) inet_ntop( AF_INET6,
                                      &from.sa_in6_addr.sin6_addr,
                                      addr, sizeof addr );
-               sprintf( peername, "IP=%s %d",
+               sprintf( peername, "IP=[%s]:%d",
                         peeraddr != NULL ? peeraddr : SLAP_STRING_UNKNOWN,
                         (unsigned) ntohs( from.sa_in6_addr.sin6_port ) );
        }
@@ -1767,10 +1767,10 @@ slap_listener(
 #  endif /* LDAP_PF_INET6 */
 
        case AF_INET:
-       peeraddr = inet_ntoa( from.sa_in_addr.sin_addr );
-       sprintf( peername, "IP=%s:%d",
-               peeraddr != NULL ? peeraddr : SLAP_STRING_UNKNOWN,
-               (unsigned) ntohs( from.sa_in_addr.sin_port ) );
+               peeraddr = inet_ntoa( from.sa_in_addr.sin_addr );
+               sprintf( peername, "IP=%s:%d",
+                       peeraddr != NULL ? peeraddr : SLAP_STRING_UNKNOWN,
+                       (unsigned) ntohs( from.sa_in_addr.sin_port ) );
                break;
 
        default:
index e985b78519545cca389d78cf40a2a673e3835ce2..091ab673f9d4f13f6452702522794596fd21f2e1 100644 (file)
@@ -1231,6 +1231,7 @@ typedef enum slap_style_e {
        ACL_STYLE_USERS,
        ACL_STYLE_SELF,
        ACL_STYLE_IP,
+       ACL_STYLE_IPV6,
        ACL_STYLE_PATH
 } slap_style_t;
 
@@ -1398,8 +1399,15 @@ typedef struct slap_access {
        /* connection related stuff */
        slap_style_t a_peername_style;
        struct berval   a_peername_pat;
+#ifdef LDAP_PF_INET6
+       struct in6_addr a_peername_addr6,
+                       a_peername_mask6;
+#define        a_peername_addr a_peername_addr6.s6_addr32[0]
+#define        a_peername_mask a_peername_mask6.s6_addr32[0]
+#else /* ! LDAP_PF_INET6 */
        unsigned long   a_peername_addr,
                        a_peername_mask;
+#endif /* ! LDAP_PF_INET6 */
        int             a_peername_port;
 
        slap_style_t a_sockname_style;