#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 */
}
}
-vd_access:
control = slap_acl_mask( a, &mask, op,
e, desc, val, MAXREMATCHES, matches, count, state );
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 ) {
} 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
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;
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;
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;
#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 */
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 ) );
}
# 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:
ACL_STYLE_USERS,
ACL_STYLE_SELF,
ACL_STYLE_IP,
+ ACL_STYLE_IPV6,
ACL_STYLE_PATH
} slap_style_t;
/* 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;