aci_bv_set_ref = BER_BVC("set-ref"),
aci_bv_grant = BER_BVC("grant"),
aci_bv_deny = BER_BVC("deny"),
+
+ aci_bv_ip_eq = BER_BVC("IP="),
+#ifdef LDAP_PF_LOCAL
+ aci_bv_path_eq = BER_BVC("PATH="),
+ aci_bv_dirsep = BER_BVC(LDAP_DIRSEP),
+#endif /* LDAP_PF_LOCAL */
aci_bv_group_class = BER_BVC(SLAPD_GROUP_CLASS),
aci_bv_group_attr = BER_BVC(SLAPD_GROUP_ATTR),
{
continue;
}
+
} else {
- if ( ber_bvstrcasecmp( &b->a_peername_pat, &op->o_conn->c_peer_name ) != 0 )
- continue;
+ /* try exact match */
+ if ( b->a_peername_style == ACL_STYLE_BASE ) {
+ if ( ber_bvstrcasecmp( &b->a_peername_pat, &op->o_conn->c_peer_name ) != 0 )
+ continue;
+
+ /* extract IP and try exact match */
+ } else if ( b->a_peername_style == ACL_STYLE_IP ) {
+ char *port;
+ char buf[] = "255.255.255.255";
+ struct berval ip;
+ unsigned long addr;
+ int port_number = -1;
+
+ if ( strncasecmp( op->o_conn->c_peer_name.bv_val,
+ aci_bv_ip_eq.bv_val, aci_bv_ip_eq.bv_len ) != 0 )
+ continue;
+
+ ip.bv_val = op->o_conn->c_peer_name.bv_val + aci_bv_ip_eq.bv_len;
+ ip.bv_len = op->o_conn->c_peer_name.bv_len - aci_bv_ip_eq.bv_len;
+
+ port = strrchr( ip.bv_val, ':' );
+ if ( port ) {
+ char *next;
+
+ ip.bv_len = port - ip.bv_val;
+ ++port;
+ port_number = strtol( port, &next, 10 );
+ if ( next[0] != '\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';
+
+ addr = inet_addr( buf );
+
+ /* unable to convert? */
+ if ( addr == (unsigned long)(-1) )
+ continue;
+
+ if ( (addr & b->a_peername_mask) != b->a_peername_addr )
+ continue;
+
+#ifdef LDAP_PF_LOCAL
+ /* extract path and try exact match */
+ } else if ( b->a_peername_style == ACL_STYLE_PATH ) {
+ struct berval path;
+
+ if ( strncmp( op->o_conn->c_peer_name.bv_val,
+ aci_bv_path_eq.bv_val, aci_bv_path_eq.bv_len ) != 0 )
+ continue;
+
+ path.bv_val = op->o_conn->c_peer_name.bv_val + aci_bv_path_eq.bv_len;
+ path.bv_len = op->o_conn->c_peer_name.bv_len - aci_bv_path_eq.bv_len;
+
+ if ( ber_bvcmp( &b->a_peername_pat, &path ) != 0 )
+ continue;
+
+#endif /* LDAP_PF_LOCAL */
+
+ /* exact match (very unlikely...) */
+ } else if ( ber_bvcmp( &op->o_conn->c_peer_name, &b->a_peername_pat ) != 0 ) {
+ continue;
+ }
}
}
}
#include "lber_pvt.h"
#include "lutil.h"
-static char *style_strings[] = { "regex",
- "base", "one", "subtree", "children", NULL };
+static char *style_strings[] = {
+ "regex",
+ "base",
+ "one",
+ "subtree",
+ "children",
+ "attrof",
+ "ip",
+ "path",
+ NULL
+};
static void split(char *line, int splitchar, char **left, char **right);
static void access_append(Access **l, Access *a);
} else if ( strcasecmp( style, "regex" ) == 0 ) {
sty = ACL_STYLE_REGEX;
+ } else if ( strcasecmp( style, "ip" ) == 0 ) {
+ sty = ACL_STYLE_IP;
+
+ } else if ( strcasecmp( style, "path" ) == 0 ) {
+ sty = ACL_STYLE_PATH;
+#ifndef LDAP_PF_LOCAL
+ fprintf( stderr, "%s: line %d: "
+ "path style modifier is useless without local\n",
+ fname, lineno );
+#endif /* LDAP_PF_LOCAL */
+
} else {
fprintf( stderr,
"%s: line %d: unknown style \"%s\" in by clause\n",
}
if ( strcasecmp( left, "peername" ) == 0 ) {
- if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) {
+ switch (sty) {
+ case ACL_STYLE_REGEX:
+ case ACL_STYLE_BASE:
+ case ACL_STYLE_IP:
+ case ACL_STYLE_PATH:
+ break;
+
+ default:
fprintf( stderr, "%s: line %d: "
"inappropriate style \"%s\" in by clause\n",
fname, lineno, style );
regtest(fname, lineno, bv.bv_val);
}
b->a_peername_pat = bv;
+
} else {
ber_str2bv( right, 0, 1, &b->a_peername_pat );
+
+ if ( sty == ACL_STYLE_IP ) {
+ char *addr = NULL,
+ *mask = NULL,
+ *port = NULL;
+
+ split( right, '{', &addr, &port );
+ split( addr, '%', &addr, &mask );
+
+ b->a_peername_addr = inet_addr( addr );
+ if ( b->a_peername_addr == (unsigned long)(-1)) {
+ /* illegal address */
+ fprintf( stderr, "%s: line %d: "
+ "illegal peername address \"%s\".\n",
+ fname, lineno, addr );
+ acl_usage();
+ }
+
+ b->a_peername_mask = (unsigned long)(-1);
+ if ( mask != NULL ) {
+ b->a_peername_mask = inet_addr( mask );
+ if ( b->a_peername_mask == (unsigned long)(-1)) {
+ /* illegal mask */
+ fprintf( stderr, "%s: line %d: "
+ "illegal peername address mask \"%s\".\n",
+ fname, lineno, mask );
+ acl_usage();
+ }
+ }
+
+ b->a_peername_port = -1;
+ if ( port ) {
+ char *end = NULL;
+
+ b->a_peername_port = strtol( port, &end, 10 );
+ if ( end[ 0 ] != '}' ) {
+ /* illegal port */
+ fprintf( stderr, "%s: line %d: "
+ "illegal peername port specification \"{%s}\".\n",
+ fname, lineno, port );
+ acl_usage();
+ }
+ }
+ }
}
continue;
}
"<who> ::= [ * | anonymous | users | self | dn[.<dnstyle>]=<DN> ]\n"
"\t[dnattr=<attrname>]\n"
"\t[group[/<objectclass>[/<attrname>]][.<style>]=<group>]\n"
- "\t[peername[.<style>]=<peer>] [sockname[.<style>]=<name>]\n",
- "\t[domain[.<style>]=<domain>] [sockurl[.<style>]=<url>]\n"
+ "\t[peername[.<peernamestyle>]=<peer>] [sockname[.<style>]=<name>]\n",
+ "\t[domain[.<domainstyle>]=<domain>] [sockurl[.<style>]=<url>]\n"
#ifdef SLAPD_ACI_ENABLED
"\t[aci=<attrname>]\n"
#endif
"\t[ssf=<n>] [transport_ssf=<n>] [tls_ssf=<n>] [sasl_ssf=<n>]\n"
- "<dnstyle> ::= base | exact | one | subtree | children | regex\n"
+ "<dnstyle> ::= base | exact | one(level) | sub(tree) | children | regex\n"
"<style> ::= regex | base | exact\n"
+ "<peernamestyle> ::= regex | exact | ip | path\n"
+ "<domainstyle> ::= regex | base | exact | sub(tree)\n"
"<access> ::= [self]{<level>|<priv>}\n"
"<level> ::= none | auth | compare | search | read | write\n"
"<priv> ::= {=|+|-}{w|r|s|c|x|0}+\n"