implement full IPv6 support in ACLs; use URL notation (as suggested by Howard) to disambiguate parsing (ITS#4756)

This commit is contained in:
Pierangelo Masarati 2006-12-15 01:11:11 +00:00
parent 3164c73276
commit 97e6225cc9
4 changed files with 126 additions and 9 deletions

View 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 ) {

View 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;

View 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:

View 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;