MATCHES_MEMSET( &tmp_matches );
tmp_data = &tmp_matches.dn_data[0];
- if ( a->acl_attrval_style == ACL_STYLE_REGEX )
+ if ( !a || a->acl_attrval_style == ACL_STYLE_REGEX )
tmp_matchesp = matches;
else switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
tmp_matchesp = matches;
break;
}
- /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
+ /* FALLTHRU */
+ /* applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_data[0].rm_so = 0;
bv.bv_val = buf;
/* Expand value regex */
- if ( a->acl_attrval_style == ACL_STYLE_REGEX )
+ if ( !a || a->acl_attrval_style == ACL_STYLE_REGEX )
tmp_matchesp = matches;
else switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
tmp_matchesp = matches;
break;
}
- /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
+ /* FALLTHRU */
+ /* applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_data[0].rm_so = 0;
Operation *op,
Entry *e,
struct berval *val,
- AccessControl *a,
int count,
- AccessControlState *state,
- slap_mask_t *mask,
slap_dn_access *bdn,
struct berval *opndn )
{
return 0;
}
-
-/*
- * slap_acl_mask - modifies mask based upon the given acl and the
- * requested access to entry e, attribute attr, value val. if val
- * is null, access to the whole attribute is assumed (all values).
- *
- * returns 0 access NOT allowed
- * 1 access allowed
- */
-
-static slap_control_t
-slap_acl_mask(
- AccessControl *a,
- AccessControl *prev,
- slap_mask_t *mask,
- Operation *op,
- Entry *e,
- AttributeDescription *desc,
- struct berval *val,
- AclRegexMatches *matches,
- int count,
- AccessControlState *state,
- slap_access_t access )
+int
+acl_check_who(
+ Operation *op,
+ Entry *e,
+ struct berval *val,
+ AccessControl *a,
+ Access *b,
+ AclRegexMatches *matches,
+ int count )
{
- int i;
- Access *b;
-#ifdef LDAP_DEBUG
- char accessmaskbuf[ACCESSMASK_MAXLEN];
-#endif /* DEBUG */
- const char *attr;
-#ifdef SLAP_DYNACL
- slap_mask_t a2pmask = ACL_ACCESS2PRIV( access );
-#endif /* SLAP_DYNACL */
-
- assert( a != NULL );
- assert( mask != NULL );
- assert( desc != NULL );
-
- attr = desc->ad_cname.bv_val;
-
- assert( attr != NULL );
+ if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
+ Debug( LDAP_DEBUG_ACL, "<= check a_dn_pat: %s\n",
+ b->a_dn_pat.bv_val );
+ /*
+ * if access applies to the entry itself, and the
+ * user is bound as somebody in the same namespace as
+ * the entry, OR the given dn matches the dn pattern
+ */
+ /*
+ * NOTE: styles "anonymous", "users" and "self"
+ * have been moved to enum slap_style_t, whose
+ * value is set in a_dn_style; however, the string
+ * is maintained in a_dn_pat.
+ */
- Debug( LDAP_DEBUG_ACL,
- "=> acl_mask: access to entry \"%s\", attr \"%s\" requested\n",
- e->e_dn, attr );
+ if ( acl_mask_dn( op, e, val, a, matches,
+ &b->a_dn, &op->o_ndn ) )
+ {
+ return 1;
+ }
+ }
- Debug( LDAP_DEBUG_ACL,
- "=> acl_mask: to %s by \"%s\", (%s) \n",
- val ? "value" : "all values",
- op->o_ndn.bv_val ? op->o_ndn.bv_val : "",
- accessmask2str( *mask, accessmaskbuf, 1 ) );
+ if ( !BER_BVISEMPTY( &b->a_realdn_pat ) ) {
+ struct berval ndn;
+ Debug( LDAP_DEBUG_ACL, "<= check a_realdn_pat: %s\n",
+ b->a_realdn_pat.bv_val );
+ /*
+ * if access applies to the entry itself, and the
+ * user is bound as somebody in the same namespace as
+ * the entry, OR the given dn matches the dn pattern
+ */
+ /*
+ * NOTE: styles "anonymous", "users" and "self"
+ * have been moved to enum slap_style_t, whose
+ * value is set in a_dn_style; however, the string
+ * is maintained in a_dn_pat.
+ */
- b = a->acl_access;
- i = 1;
+ if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) )
+ {
+ ndn = op->o_conn->c_ndn;
+ } else {
+ ndn = op->o_ndn;
+ }
- for ( ; b != NULL; b = b->a_next, i++ ) {
- slap_mask_t oldmask, modmask;
+ if ( acl_mask_dn( op, e, val, a, matches,
+ &b->a_realdn, &ndn ) )
+ {
+ return 1;
+ }
+ }
- ACL_INVALIDATE( modmask );
+ if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) {
+ if ( ! op->o_conn->c_listener ) {
+ return 1;
+ }
+ Debug( LDAP_DEBUG_ACL, "<= check a_sockurl_pat: %s\n",
+ b->a_sockurl_pat.bv_val );
- /* check for the "self" modifier in the <access> field */
- if ( b->a_dn.a_self ) {
- const char *dummy;
- int rc, match = 0;
+ if ( !ber_bvccmp( &b->a_sockurl_pat, '*' ) ) {
+ if ( b->a_sockurl_style == ACL_STYLE_REGEX) {
+ if ( !regex_matches( &b->a_sockurl_pat, op->o_conn->c_listener_url.bv_val,
+ &e->e_nname, val, matches ) )
+ {
+ return 1;
+ }
- ACL_RECORD_VALUE_STATE;
+ } else if ( b->a_sockurl_style == ACL_STYLE_EXPAND ) {
+ struct berval bv;
+ char buf[ACL_BUF_SIZE];
- /* must have DN syntax */
- if ( desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName &&
- !is_at_syntax( desc->ad_type, SLAPD_NAMEUID_SYNTAX )) continue;
+ bv.bv_len = sizeof( buf ) - 1;
+ bv.bv_val = buf;
+ if ( acl_string_expand( &bv, &b->a_sockurl_pat, &e->e_nname, val, matches ) )
+ {
+ return 1;
+ }
- /* check if the target is an attribute. */
- if ( val == NULL ) continue;
+ if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_listener_url ) != 0 )
+ {
+ return 1;
+ }
- /* a DN must be present */
- if ( BER_BVISEMPTY( &op->o_ndn ) ) {
- continue;
+ } else {
+ if ( ber_bvstrcasecmp( &b->a_sockurl_pat, &op->o_conn->c_listener_url ) != 0 )
+ {
+ return 1;
+ }
}
+ }
+ }
- /* target is attribute, check if the attribute value
- * is the op dn.
- */
- rc = value_match( &match, desc,
- desc->ad_type->sat_equality, 0,
- val, &op->o_ndn, &dummy );
- /* on match error or no match, fail the ACL clause */
- if ( rc != LDAP_SUCCESS || match != 0 )
- continue;
+ if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) {
+ if ( !op->o_conn->c_peer_domain.bv_val ) {
+ return 1;
}
+ Debug( LDAP_DEBUG_ACL, "<= check a_domain_pat: %s\n",
+ b->a_domain_pat.bv_val );
+ if ( !ber_bvccmp( &b->a_domain_pat, '*' ) ) {
+ if ( b->a_domain_style == ACL_STYLE_REGEX) {
+ if ( !regex_matches( &b->a_domain_pat, op->o_conn->c_peer_domain.bv_val,
+ &e->e_nname, val, matches ) )
+ {
+ return 1;
+ }
+ } else {
+ char buf[ACL_BUF_SIZE];
- /* AND <who> clauses */
- if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
- Debug( LDAP_DEBUG_ACL, "<= check a_dn_pat: %s\n",
- b->a_dn_pat.bv_val );
- /*
- * if access applies to the entry itself, and the
- * user is bound as somebody in the same namespace as
- * the entry, OR the given dn matches the dn pattern
- */
- /*
- * NOTE: styles "anonymous", "users" and "self"
- * have been moved to enum slap_style_t, whose
- * value is set in a_dn_style; however, the string
- * is maintained in a_dn_pat.
- */
+ struct berval cmp = op->o_conn->c_peer_domain;
+ struct berval pat = b->a_domain_pat;
- if ( acl_mask_dn( op, e, val, a, matches,
- &b->a_dn, &op->o_ndn ) )
- {
- continue;
- }
- }
+ if ( b->a_domain_expand ) {
+ struct berval bv;
- if ( !BER_BVISEMPTY( &b->a_realdn_pat ) ) {
- struct berval ndn;
+ bv.bv_len = sizeof(buf) - 1;
+ bv.bv_val = buf;
- Debug( LDAP_DEBUG_ACL, "<= check a_realdn_pat: %s\n",
- b->a_realdn_pat.bv_val );
- /*
- * if access applies to the entry itself, and the
- * user is bound as somebody in the same namespace as
- * the entry, OR the given dn matches the dn pattern
- */
- /*
- * NOTE: styles "anonymous", "users" and "self"
- * have been moved to enum slap_style_t, whose
- * value is set in a_dn_style; however, the string
- * is maintained in a_dn_pat.
- */
+ if ( acl_string_expand(&bv, &b->a_domain_pat, &e->e_nname, val, matches) )
+ {
+ return 1;
+ }
+ pat = bv;
+ }
- if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) )
- {
- ndn = op->o_conn->c_ndn;
- } else {
- ndn = op->o_ndn;
- }
+ if ( b->a_domain_style == ACL_STYLE_SUBTREE ) {
+ int offset = cmp.bv_len - pat.bv_len;
+ if ( offset < 0 ) {
+ return 1;
+ }
- if ( acl_mask_dn( op, e, val, a, matches,
- &b->a_realdn, &ndn ) )
- {
- continue;
+ if ( offset == 1 || ( offset > 1 && cmp.bv_val[ offset - 1 ] != '.' ) ) {
+ return 1;
+ }
+
+ /* trim the domain */
+ cmp.bv_val = &cmp.bv_val[ offset ];
+ cmp.bv_len -= offset;
+ }
+
+ if ( ber_bvstrcasecmp( &pat, &cmp ) != 0 ) {
+ return 1;
+ }
}
}
+ }
- if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) {
- if ( ! op->o_conn->c_listener ) {
- continue;
- }
- Debug( LDAP_DEBUG_ACL, "<= check a_sockurl_pat: %s\n",
- b->a_sockurl_pat.bv_val );
+ if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) {
+ if ( !op->o_conn->c_peer_name.bv_val ) {
+ return 1;
+ }
+ Debug( LDAP_DEBUG_ACL, "<= check a_peername_path: %s\n",
+ b->a_peername_pat.bv_val );
+ if ( !ber_bvccmp( &b->a_peername_pat, '*' ) ) {
+ if ( b->a_peername_style == ACL_STYLE_REGEX ) {
+ if ( !regex_matches( &b->a_peername_pat, op->o_conn->c_peer_name.bv_val,
+ &e->e_nname, val, matches ) )
+ {
+ return 1;
+ }
- if ( !ber_bvccmp( &b->a_sockurl_pat, '*' ) ) {
- if ( b->a_sockurl_style == ACL_STYLE_REGEX) {
- if ( !regex_matches( &b->a_sockurl_pat, op->o_conn->c_listener_url.bv_val,
- &e->e_nname, val, matches ) )
- {
- continue;
+ } else {
+ /* 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 ) {
+ return 1;
}
- } else if ( b->a_sockurl_style == ACL_STYLE_EXPAND ) {
+ } else if ( b->a_peername_style == ACL_STYLE_EXPAND ) {
struct berval bv;
char buf[ACL_BUF_SIZE];
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = buf;
- if ( acl_string_expand( &bv, &b->a_sockurl_pat, &e->e_nname, val, matches ) )
+ if ( acl_string_expand( &bv, &b->a_peername_pat, &e->e_nname, val, matches ) )
{
- continue;
+ return 1;
}
- if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_listener_url ) != 0 )
- {
- continue;
+ if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_peer_name ) != 0 ) {
+ return 1;
}
- } else {
- if ( ber_bvstrcasecmp( &b->a_sockurl_pat, &op->o_conn->c_listener_url ) != 0 )
- {
- continue;
- }
- }
- }
- }
+ /* extract IP and try exact match */
+ } else if ( b->a_peername_style == ACL_STYLE_IP ) {
+ char *port;
+ char buf[STRLENOF("255.255.255.255") + 1];
+ struct berval ip;
+ unsigned long addr;
+ int port_number = -1;
+
+ if ( strncasecmp( op->o_conn->c_peer_name.bv_val,
+ acl_bv_ip_eq.bv_val,
+ acl_bv_ip_eq.bv_len ) != 0 )
+ return 1;
- if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) {
- if ( !op->o_conn->c_peer_domain.bv_val ) {
- continue;
- }
- Debug( LDAP_DEBUG_ACL, "<= check a_domain_pat: %s\n",
- b->a_domain_pat.bv_val );
- if ( !ber_bvccmp( &b->a_domain_pat, '*' ) ) {
- if ( b->a_domain_style == ACL_STYLE_REGEX) {
- if ( !regex_matches( &b->a_domain_pat, op->o_conn->c_peer_domain.bv_val,
- &e->e_nname, val, matches ) )
- {
- continue;
+ ip.bv_val = op->o_conn->c_peer_name.bv_val + acl_bv_ip_eq.bv_len;
+ ip.bv_len = op->o_conn->c_peer_name.bv_len - acl_bv_ip_eq.bv_len;
+
+ port = strrchr( ip.bv_val, ':' );
+ if ( port ) {
+ ip.bv_len = port - ip.bv_val;
+ ++port;
+ if ( lutil_atoi( &port_number, port ) != 0 )
+ return 1;
}
- } else {
- char buf[ACL_BUF_SIZE];
- struct berval cmp = op->o_conn->c_peer_domain;
- struct berval pat = b->a_domain_pat;
+ /* the port check can be anticipated here */
+ if ( b->a_peername_port != -1 && port_number != b->a_peername_port )
+ return 1;
- if ( b->a_domain_expand ) {
- struct berval bv;
+ /* address longer than expected? */
+ if ( ip.bv_len >= sizeof(buf) )
+ return 1;
- bv.bv_len = sizeof(buf) - 1;
- bv.bv_val = buf;
+ AC_MEMCPY( buf, ip.bv_val, ip.bv_len );
+ buf[ ip.bv_len ] = '\0';
- if ( acl_string_expand(&bv, &b->a_domain_pat, &e->e_nname, val, matches) )
- {
- continue;
- }
- pat = bv;
- }
+ addr = inet_addr( buf );
- if ( b->a_domain_style == ACL_STYLE_SUBTREE ) {
- int offset = cmp.bv_len - pat.bv_len;
- if ( offset < 0 ) {
- continue;
- }
+ /* unable to convert? */
+ if ( addr == (unsigned long)(-1) )
+ return 1;
- if ( offset == 1 || ( offset > 1 && cmp.bv_val[ offset - 1 ] != '.' ) ) {
- continue;
- }
+ if ( (addr & b->a_peername_mask) != b->a_peername_addr )
+ return 1;
- /* trim the domain */
- cmp.bv_val = &cmp.bv_val[ offset ];
- cmp.bv_len -= offset;
- }
-
- if ( ber_bvstrcasecmp( &pat, &cmp ) != 0 ) {
- continue;
- }
- }
- }
- }
+#ifdef LDAP_PF_INET6
+ /* extract IPv6 and try exact match */
+ } else if ( b->a_peername_style == ACL_STYLE_IPV6 ) {
+ char *port;
+ char buf[STRLENOF("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF") + 1];
+ struct berval ip;
+ struct in6_addr addr;
+ int port_number = -1;
+
+ if ( strncasecmp( op->o_conn->c_peer_name.bv_val,
+ acl_bv_ipv6_eq.bv_val,
+ acl_bv_ipv6_eq.bv_len ) != 0 )
+ return 1;
- if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) {
- if ( !op->o_conn->c_peer_name.bv_val ) {
- continue;
- }
- Debug( LDAP_DEBUG_ACL, "<= check a_peername_path: %s\n",
- b->a_peername_pat.bv_val );
- if ( !ber_bvccmp( &b->a_peername_pat, '*' ) ) {
- if ( b->a_peername_style == ACL_STYLE_REGEX ) {
- if ( !regex_matches( &b->a_peername_pat, op->o_conn->c_peer_name.bv_val,
- &e->e_nname, val, matches ) )
- {
- 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;
- } else {
- /* 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;
- }
+ port = strrchr( ip.bv_val, ']' );
+ if ( port ) {
+ ip.bv_len = port - ip.bv_val;
+ ++port;
+ if ( port[0] == ':' && lutil_atoi( &port_number, ++port ) != 0 )
+ return 1;
+ }
- } else if ( b->a_peername_style == ACL_STYLE_EXPAND ) {
- struct berval bv;
- char buf[ACL_BUF_SIZE];
+ /* the port check can be anticipated here */
+ if ( b->a_peername_port != -1 && port_number != b->a_peername_port )
+ return 1;
- bv.bv_len = sizeof( buf ) - 1;
- bv.bv_val = buf;
- if ( acl_string_expand( &bv, &b->a_peername_pat, &e->e_nname, val, matches ) )
- {
- continue;
- }
+ /* address longer than expected? */
+ if ( ip.bv_len >= sizeof(buf) )
+ return 1;
- if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_peer_name ) != 0 ) {
- continue;
- }
+ AC_MEMCPY( buf, ip.bv_val, ip.bv_len );
+ buf[ ip.bv_len ] = '\0';
- /* extract IP and try exact match */
- } else if ( b->a_peername_style == ACL_STYLE_IP ) {
- char *port;
- char buf[STRLENOF("255.255.255.255") + 1];
- struct berval ip;
- unsigned long addr;
- int port_number = -1;
-
- if ( strncasecmp( op->o_conn->c_peer_name.bv_val,
- acl_bv_ip_eq.bv_val,
- acl_bv_ip_eq.bv_len ) != 0 )
- continue;
+ if ( inet_pton( AF_INET6, buf, &addr ) != 1 )
+ return 1;
- ip.bv_val = op->o_conn->c_peer_name.bv_val + acl_bv_ip_eq.bv_len;
- ip.bv_len = op->o_conn->c_peer_name.bv_len - acl_bv_ip_eq.bv_len;
+ /* check mask */
+ if ( !slap_addr6_mask( &addr, &b->a_peername_mask6, &b->a_peername_addr6 ) )
+ return 1;
+#endif /* LDAP_PF_INET6 */
- port = strrchr( ip.bv_val, ':' );
- if ( port ) {
- ip.bv_len = port - ip.bv_val;
- ++port;
- if ( 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;
+#ifdef LDAP_PF_LOCAL
+ /* extract path and try exact match */
+ } else if ( b->a_peername_style == ACL_STYLE_PATH ) {
+ struct berval path;
- AC_MEMCPY( buf, ip.bv_val, ip.bv_len );
- buf[ ip.bv_len ] = '\0';
+ if ( strncmp( op->o_conn->c_peer_name.bv_val,
+ acl_bv_path_eq.bv_val,
+ acl_bv_path_eq.bv_len ) != 0 )
+ return 1;
- addr = inet_addr( buf );
+ path.bv_val = op->o_conn->c_peer_name.bv_val
+ + acl_bv_path_eq.bv_len;
+ path.bv_len = op->o_conn->c_peer_name.bv_len
+ - acl_bv_path_eq.bv_len;
- /* unable to convert? */
- if ( addr == (unsigned long)(-1) )
- continue;
+ if ( ber_bvcmp( &b->a_peername_pat, &path ) != 0 )
+ return 1;
- 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[STRLENOF("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF") + 1];
- struct berval ip;
- struct in6_addr addr;
- int port_number = -1;
-
- 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 */
- if ( !slap_addr6_mask( &addr, &b->a_peername_mask6, &b->a_peername_addr6 ) )
- continue;
-#endif /* LDAP_PF_INET6 */
-
-#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,
- acl_bv_path_eq.bv_val,
- acl_bv_path_eq.bv_len ) != 0 )
- continue;
-
- path.bv_val = op->o_conn->c_peer_name.bv_val
- + acl_bv_path_eq.bv_len;
- path.bv_len = op->o_conn->c_peer_name.bv_len
- - acl_bv_path_eq.bv_len;
-
- if ( ber_bvcmp( &b->a_peername_pat, &path ) != 0 )
- continue;
-
-#endif /* LDAP_PF_LOCAL */
+#endif /* LDAP_PF_LOCAL */
/* exact match (very unlikely...) */
- } else if ( ber_bvcmp( &op->o_conn->c_peer_name, &b->a_peername_pat ) != 0 ) {
- continue;
- }
+ } else if ( ber_bvcmp( &op->o_conn->c_peer_name, &b->a_peername_pat ) != 0 ) {
+ return 1;
}
}
}
+ }
- if ( !BER_BVISEMPTY( &b->a_sockname_pat ) ) {
- if ( BER_BVISNULL( &op->o_conn->c_sock_name ) ) {
- continue;
- }
- Debug( LDAP_DEBUG_ACL, "<= check a_sockname_path: %s\n",
+ if ( !BER_BVISEMPTY( &b->a_sockname_pat ) ) {
+ if ( BER_BVISNULL( &op->o_conn->c_sock_name ) ) {
+ return 1;
+ }
+ Debug( LDAP_DEBUG_ACL, "<= check a_sockname_path: %s\n",
b->a_sockname_pat.bv_val );
- if ( !ber_bvccmp( &b->a_sockname_pat, '*' ) ) {
- if ( b->a_sockname_style == ACL_STYLE_REGEX) {
- if ( !regex_matches( &b->a_sockname_pat, op->o_conn->c_sock_name.bv_val,
- &e->e_nname, val, matches ) )
- {
- continue;
- }
+ if ( !ber_bvccmp( &b->a_sockname_pat, '*' ) ) {
+ if ( b->a_sockname_style == ACL_STYLE_REGEX) {
+ if ( !regex_matches( &b->a_sockname_pat, op->o_conn->c_sock_name.bv_val,
+ &e->e_nname, val, matches ) )
+ {
+ return 1;
+ }
- } else if ( b->a_sockname_style == ACL_STYLE_EXPAND ) {
- struct berval bv;
- char buf[ACL_BUF_SIZE];
+ } else if ( b->a_sockname_style == ACL_STYLE_EXPAND ) {
+ struct berval bv;
+ char buf[ACL_BUF_SIZE];
- bv.bv_len = sizeof( buf ) - 1;
- bv.bv_val = buf;
- if ( acl_string_expand( &bv, &b->a_sockname_pat, &e->e_nname, val, matches ) )
- {
- continue;
- }
+ bv.bv_len = sizeof( buf ) - 1;
+ bv.bv_val = buf;
+ if ( acl_string_expand( &bv, &b->a_sockname_pat, &e->e_nname, val, matches ) )
+ {
+ return 1;
+ }
- if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_sock_name ) != 0 ) {
- continue;
- }
+ if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_sock_name ) != 0 ) {
+ return 1;
+ }
- } else {
- if ( ber_bvstrcasecmp( &b->a_sockname_pat, &op->o_conn->c_sock_name ) != 0 ) {
- continue;
- }
+ } else {
+ if ( ber_bvstrcasecmp( &b->a_sockname_pat, &op->o_conn->c_sock_name ) != 0 ) {
+ return 1;
}
}
}
+ }
- if ( b->a_dn_at != NULL ) {
- if ( acl_mask_dnattr( op, e, val, a,
- count, state, mask,
- &b->a_dn, &op->o_ndn ) )
- {
- continue;
- }
+ if ( b->a_dn_at != NULL ) {
+ if ( acl_mask_dnattr( op, e, val, count, &b->a_dn, &op->o_ndn ) )
+ {
+ return 1;
}
+ }
- if ( b->a_realdn_at != NULL ) {
- struct berval ndn;
+ if ( b->a_realdn_at != NULL ) {
+ struct berval ndn;
- if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) )
- {
- ndn = op->o_conn->c_ndn;
- } else {
- ndn = op->o_ndn;
- }
+ if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) )
+ {
+ ndn = op->o_conn->c_ndn;
+ } else {
+ ndn = op->o_ndn;
+ }
- if ( acl_mask_dnattr( op, e, val, a,
- count, state, mask,
- &b->a_realdn, &ndn ) )
- {
- continue;
- }
+ if ( acl_mask_dnattr( op, e, val, count, &b->a_realdn, &ndn ) )
+ {
+ return 1;
}
+ }
- if ( !BER_BVISEMPTY( &b->a_group_pat ) ) {
- struct berval bv;
- struct berval ndn = BER_BVNULL;
- int rc;
+ if ( !BER_BVISEMPTY( &b->a_group_pat ) ) {
+ struct berval bv;
+ struct berval ndn = BER_BVNULL;
+ int rc;
- if ( op->o_ndn.bv_len == 0 ) {
- continue;
- }
+ if ( op->o_ndn.bv_len == 0 ) {
+ return 1;
+ }
- Debug( LDAP_DEBUG_ACL, "<= check a_group_pat: %s\n",
+ Debug( LDAP_DEBUG_ACL, "<= check a_group_pat: %s\n",
b->a_group_pat.bv_val );
- /* b->a_group is an unexpanded entry name, expanded it should be an
- * entry with objectclass group* and we test to see if odn is one of
- * the values in the attribute group
- */
- /* see if asker is listed in dnattr */
- if ( b->a_group_style == ACL_STYLE_EXPAND ) {
- char buf[ACL_BUF_SIZE];
- AclRegexMatches tmp_matches,
- *tmp_matchesp = &tmp_matches;
- regmatch_t *tmp_data;
+ /* b->a_group is an unexpanded entry name, expanded it should be an
+ * entry with objectclass group* and we test to see if odn is one of
+ * the values in the attribute group
+ */
+ /* see if asker is listed in dnattr */
+ if ( b->a_group_style == ACL_STYLE_EXPAND ) {
+ char buf[ACL_BUF_SIZE];
+ AclRegexMatches tmp_matches,
+ *tmp_matchesp = &tmp_matches;
+ regmatch_t *tmp_data;
- MATCHES_MEMSET( &tmp_matches );
- tmp_data = &tmp_matches.dn_data[0];
+ MATCHES_MEMSET( &tmp_matches );
+ tmp_data = &tmp_matches.dn_data[0];
- bv.bv_len = sizeof(buf) - 1;
- bv.bv_val = buf;
+ bv.bv_len = sizeof(buf) - 1;
+ bv.bv_val = buf;
- rc = 0;
+ rc = 0;
- if ( a->acl_attrval_style == ACL_STYLE_REGEX )
- tmp_matchesp = matches;
- else switch ( a->acl_dn_style ) {
+ if ( !a || a->acl_attrval_style == ACL_STYLE_REGEX )
+ tmp_matchesp = matches;
+ else switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
break;
}
- /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
+ /* FALLTHRU */
+ /* applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_data[0].rm_so = 0;
tmp_data[0].rm_eo = e->e_nname.bv_len;
/* error */
rc = 1;
break;
- }
+ }
- if ( rc ) {
- continue;
- }
-
- if ( acl_string_expand( &bv, &b->a_group_pat,
+ if ( rc ) {
+ return 1;
+ }
+
+ if ( acl_string_expand( &bv, &b->a_group_pat,
&e->e_nname, val,
tmp_matchesp ) )
- {
- continue;
- }
+ {
+ return 1;
+ }
- if ( dnNormalize( 0, NULL, NULL, &bv, &ndn,
+ if ( dnNormalize( 0, NULL, NULL, &bv, &ndn,
op->o_tmpmemctx ) != LDAP_SUCCESS )
- {
- /* did not expand to a valid dn */
- continue;
- }
+ {
+ /* did not expand to a valid dn */
+ return 1;
+ }
- bv = ndn;
+ bv = ndn;
- } else {
- bv = b->a_group_pat;
- }
+ } else {
+ bv = b->a_group_pat;
+ }
- rc = backend_group( op, e, &bv, &op->o_ndn,
+ rc = backend_group( op, e, &bv, &op->o_ndn,
b->a_group_oc, b->a_group_at );
- if ( ndn.bv_val ) {
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
- }
+ if ( ndn.bv_val ) {
+ slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+ }
- if ( rc != 0 ) {
- continue;
- }
+ if ( rc != 0 ) {
+ return 1;
}
+ }
- if ( !BER_BVISEMPTY( &b->a_set_pat ) ) {
- struct berval bv;
- char buf[ACL_BUF_SIZE];
+ if ( !BER_BVISEMPTY( &b->a_set_pat ) ) {
+ struct berval bv;
+ char buf[ACL_BUF_SIZE];
- Debug( LDAP_DEBUG_ACL, "<= check a_set_pat: %s\n",
+ Debug( LDAP_DEBUG_ACL, "<= check a_set_pat: %s\n",
b->a_set_pat.bv_val );
- if ( b->a_set_style == ACL_STYLE_EXPAND ) {
- AclRegexMatches tmp_matches,
- *tmp_matchesp = &tmp_matches;
- int rc = 0;
- regmatch_t *tmp_data;
+ if ( b->a_set_style == ACL_STYLE_EXPAND ) {
+ AclRegexMatches tmp_matches,
+ *tmp_matchesp = &tmp_matches;
+ int rc = 0;
+ regmatch_t *tmp_data;
- MATCHES_MEMSET( &tmp_matches );
- tmp_data = &tmp_matches.dn_data[0];
+ MATCHES_MEMSET( &tmp_matches );
+ tmp_data = &tmp_matches.dn_data[0];
- bv.bv_len = sizeof( buf ) - 1;
- bv.bv_val = buf;
+ bv.bv_len = sizeof( buf ) - 1;
+ bv.bv_val = buf;
- rc = 0;
+ rc = 0;
- if ( a->acl_attrval_style == ACL_STYLE_REGEX )
- tmp_matchesp = matches;
- else switch ( a->acl_dn_style ) {
+ if ( !a || a->acl_attrval_style == ACL_STYLE_REGEX )
+ tmp_matchesp = matches;
+ else switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
break;
}
- /* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
+ /* FALLTHRU */
+ /* applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_data[0].rm_so = 0;
tmp_data[0].rm_eo = e->e_nname.bv_len;
/* error */
rc = 1;
break;
- }
+ }
- if ( rc ) {
- continue;
- }
-
- if ( acl_string_expand( &bv, &b->a_set_pat,
+ if ( rc ) {
+ return 1;
+ }
+
+ if ( acl_string_expand( &bv, &b->a_set_pat,
&e->e_nname, val,
tmp_matchesp ) )
- {
- continue;
- }
-
- } else {
- bv = b->a_set_pat;
- }
-
- if ( acl_match_set( &bv, op, e, NULL ) == 0 ) {
- continue;
+ {
+ return 1;
}
+
+ } else {
+ bv = b->a_set_pat;
}
- if ( b->a_authz.sai_ssf ) {
- Debug( LDAP_DEBUG_ACL, "<= check a_authz.sai_ssf: ACL %u > OP %u\n",
+ if ( acl_match_set( &bv, op, e, NULL ) == 0 ) {
+ return 1;
+ }
+ }
+
+ if ( b->a_authz.sai_ssf ) {
+ Debug( LDAP_DEBUG_ACL, "<= check a_authz.sai_ssf: ACL %u > OP %u\n",
b->a_authz.sai_ssf, op->o_ssf );
- if ( b->a_authz.sai_ssf > op->o_ssf ) {
- continue;
- }
+ if ( b->a_authz.sai_ssf > op->o_ssf ) {
+ return 1;
}
+ }
- if ( b->a_authz.sai_transport_ssf ) {
- Debug( LDAP_DEBUG_ACL,
+ if ( b->a_authz.sai_transport_ssf ) {
+ Debug( LDAP_DEBUG_ACL,
"<= check a_authz.sai_transport_ssf: ACL %u > OP %u\n",
b->a_authz.sai_transport_ssf, op->o_transport_ssf );
- if ( b->a_authz.sai_transport_ssf > op->o_transport_ssf ) {
- continue;
- }
+ if ( b->a_authz.sai_transport_ssf > op->o_transport_ssf ) {
+ return 1;
}
+ }
- if ( b->a_authz.sai_tls_ssf ) {
- Debug( LDAP_DEBUG_ACL,
+ if ( b->a_authz.sai_tls_ssf ) {
+ Debug( LDAP_DEBUG_ACL,
"<= check a_authz.sai_tls_ssf: ACL %u > OP %u\n",
b->a_authz.sai_tls_ssf, op->o_tls_ssf );
- if ( b->a_authz.sai_tls_ssf > op->o_tls_ssf ) {
- continue;
- }
+ if ( b->a_authz.sai_tls_ssf > op->o_tls_ssf ) {
+ return 1;
}
+ }
- if ( b->a_authz.sai_sasl_ssf ) {
- Debug( LDAP_DEBUG_ACL,
+ if ( b->a_authz.sai_sasl_ssf ) {
+ Debug( LDAP_DEBUG_ACL,
"<= check a_authz.sai_sasl_ssf: ACL %u > OP %u\n",
b->a_authz.sai_sasl_ssf, op->o_sasl_ssf );
- if ( b->a_authz.sai_sasl_ssf > op->o_sasl_ssf ) {
+ if ( b->a_authz.sai_sasl_ssf > op->o_sasl_ssf ) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * slap_acl_mask - modifies mask based upon the given acl and the
+ * requested access to entry e, attribute attr, value val. if val
+ * is null, access to the whole attribute is assumed (all values).
+ *
+ * returns 0 access NOT allowed
+ * 1 access allowed
+ */
+
+static slap_control_t
+slap_acl_mask(
+ AccessControl *a,
+ AccessControl *prev,
+ slap_mask_t *mask,
+ Operation *op,
+ Entry *e,
+ AttributeDescription *desc,
+ struct berval *val,
+ AclRegexMatches *matches,
+ int count,
+ AccessControlState *state,
+ slap_access_t access )
+{
+ int i;
+ Access *b;
+#ifdef LDAP_DEBUG
+ char accessmaskbuf[ACCESSMASK_MAXLEN];
+#endif /* DEBUG */
+ const char *attr;
+#ifdef SLAP_DYNACL
+ slap_mask_t a2pmask = ACL_ACCESS2PRIV( access );
+#endif /* SLAP_DYNACL */
+
+ assert( a != NULL );
+ assert( mask != NULL );
+ assert( desc != NULL );
+
+ attr = desc->ad_cname.bv_val;
+
+ assert( attr != NULL );
+
+ Debug( LDAP_DEBUG_ACL,
+ "=> acl_mask: access to entry \"%s\", attr \"%s\" requested\n",
+ e->e_dn, attr );
+
+ Debug( LDAP_DEBUG_ACL,
+ "=> acl_mask: to %s by \"%s\", (%s) \n",
+ val ? "value" : "all values",
+ op->o_ndn.bv_val ? op->o_ndn.bv_val : "",
+ accessmask2str( *mask, accessmaskbuf, 1 ) );
+
+
+ b = a->acl_access;
+ i = 1;
+
+ for ( ; b != NULL; b = b->a_next, i++ ) {
+ slap_mask_t oldmask, modmask;
+
+ ACL_INVALIDATE( modmask );
+
+ /* check for the "self" modifier in the <access> field */
+ if ( b->a_dn.a_self ) {
+ const char *dummy;
+ int rc, match = 0;
+
+ ACL_RECORD_VALUE_STATE;
+
+ /* must have DN syntax */
+ if ( desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName &&
+ !is_at_syntax( desc->ad_type, SLAPD_NAMEUID_SYNTAX )) continue;
+
+ /* check if the target is an attribute. */
+ if ( val == NULL ) continue;
+
+ /* a DN must be present */
+ if ( BER_BVISEMPTY( &op->o_ndn ) ) {
continue;
}
+
+ /* target is attribute, check if the attribute value
+ * is the op dn.
+ */
+ rc = value_match( &match, desc,
+ desc->ad_type->sat_equality, 0,
+ val, &op->o_ndn, &dummy );
+ /* on match error or no match, fail the ACL clause */
+ if ( rc != LDAP_SUCCESS || match != 0 )
+ continue;
+ }
+
+ /* check <who> clauses */
+ if ( acl_check_who( op, e, val, a, b, matches, count ) ) {
+ continue;
}
#ifdef SLAP_DYNACL
}
int
-parse_acl(
+acl_parse_who(
struct config_args_s *c,
- int pos )
+ Access *b,
+ char **argv,
+ int argc,
+ int *pos,
+ char **current )
{
- int i;
- char *left, *right, *style;
struct berval bv;
- AccessControl *a = NULL;
- Access *b = NULL;
- int rc;
+ char *left, *right, *style;
const char *text;
Backend *be = c->be;
- const char *fname = c->fname;
- int lineno = c->lineno;
- int argc = c->argc;
- char **argv = c->argv;
+ int rc, i = *pos;
+
+ for ( ; i < argc; i++ ) {
+ slap_style_t sty = ACL_STYLE_REGEX;
+ char *style_modifier = NULL;
+ char *style_level = NULL;
+ int level = 0;
+ int expand = 0;
+ slap_dn_access *bdn = &b->a_dn;
+ int is_realdn = 0;
+
+ split( argv[i], '=', &left, &right );
+ split( left, '.', &left, &style );
+ if ( style ) {
+ split( style, ',', &style, &style_modifier );
+
+ if ( strncasecmp( style, "level", STRLENOF( "level" ) ) == 0 ) {
+ split( style, '{', &style, &style_level );
+ if ( style_level != NULL ) {
+ char *p = strchr( style_level, '}' );
+ if ( p == NULL ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "premature eol: expecting closing '}' in \"level{n}\"");
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ } else if ( p == style_level ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "empty level in \"level{n}\"");
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ p[0] = '\0';
+ }
+ }
+ }
- for ( i = 1; i < argc; i++ ) {
- /* to clause - select which entries are protected */
- if ( strcasecmp( argv[i], "to" ) == 0 ) {
- if ( a != NULL ) {
+ if ( style == NULL || *style == '\0' ||
+ strcasecmp( style, "exact" ) == 0 ||
+ strcasecmp( style, "baseObject" ) == 0 ||
+ strcasecmp( style, "base" ) == 0 )
+ {
+ sty = ACL_STYLE_BASE;
+
+ } else if ( strcasecmp( style, "onelevel" ) == 0 ||
+ strcasecmp( style, "one" ) == 0 )
+ {
+ sty = ACL_STYLE_ONE;
+
+ } else if ( strcasecmp( style, "subtree" ) == 0 ||
+ strcasecmp( style, "sub" ) == 0 )
+ {
+ sty = ACL_STYLE_SUBTREE;
+
+ } else if ( strcasecmp( style, "children" ) == 0 ) {
+ sty = ACL_STYLE_CHILDREN;
+
+ } else if ( strcasecmp( style, "level" ) == 0 )
+ {
+ if ( lutil_atoi( &level, style_level ) != 0 ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "only one to clause allowed in access line" );
+ "unable to parse level in \"level{n}\"");
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- a = (AccessControl *) ch_calloc( 1, sizeof(AccessControl) );
- a->acl_attrval_style = ACL_STYLE_NONE;
- for ( ++i; i < argc; i++ ) {
- if ( strcasecmp( argv[i], "by" ) == 0 ) {
- i--;
- break;
- }
- if ( strcasecmp( argv[i], "*" ) == 0 ) {
- if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
- a->acl_dn_style != ACL_STYLE_REGEX )
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "dn pattern already specified in to clause." );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ sty = ACL_STYLE_LEVEL;
- ber_str2bv( "*", STRLENOF( "*" ), 1, &a->acl_dn_pat );
- continue;
- }
+ } else if ( strcasecmp( style, "regex" ) == 0 ) {
+ sty = ACL_STYLE_REGEX;
- split( argv[i], '=', &left, &right );
- split( left, '.', &left, &style );
+ } else if ( strcasecmp( style, "expand" ) == 0 ) {
+ sty = ACL_STYLE_EXPAND;
- if ( right == NULL ) {
+ } else if ( strcasecmp( style, "ip" ) == 0 ) {
+ sty = ACL_STYLE_IP;
+
+ } else if ( strcasecmp( style, "ipv6" ) == 0 ) {
+#ifndef LDAP_PF_INET6
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "IPv6 not supported");
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+#endif /* ! LDAP_PF_INET6 */
+ sty = ACL_STYLE_IPV6;
+
+ } else if ( strcasecmp( style, "path" ) == 0 ) {
+ sty = ACL_STYLE_PATH;
+#ifndef LDAP_PF_LOCAL
+ snprintf( c->cr_msg, sizeof( c->cr_msg),
+ "\"path\" style modifier is useless without local");
+ Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+#endif /* LDAP_PF_LOCAL */
+
+ } else {
+ snprintf( c->cr_msg, sizeof ( c->cr_msg ),
+ "unknown style \"%s\" in by clause", style );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+
+ if ( style_modifier &&
+ strcasecmp( style_modifier, "expand" ) == 0 )
+ {
+ switch ( sty ) {
+ case ACL_STYLE_REGEX:
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "missing \"=\" in \"%s\" in to clause", left );
+ "\"regex\" style implies \"expand\" modifier" );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
- }
-
- if ( strcasecmp( left, "dn" ) == 0 ) {
- if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
- a->acl_dn_style != ACL_STYLE_REGEX )
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg),
- "dn pattern already specified in to clause" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ break;
- if ( style == NULL || *style == '\0' ||
- strcasecmp( style, "baseObject" ) == 0 ||
- strcasecmp( style, "base" ) == 0 ||
- strcasecmp( style, "exact" ) == 0 )
- {
- a->acl_dn_style = ACL_STYLE_BASE;
- ber_str2bv( right, 0, 1, &a->acl_dn_pat );
+ case ACL_STYLE_EXPAND:
+ break;
- } else if ( strcasecmp( style, "oneLevel" ) == 0 ||
- strcasecmp( style, "one" ) == 0 )
- {
- a->acl_dn_style = ACL_STYLE_ONE;
- ber_str2bv( right, 0, 1, &a->acl_dn_pat );
+ default:
+ /* we'll see later if it's pertinent */
+ expand = 1;
+ break;
+ }
+ }
- } else if ( strcasecmp( style, "subtree" ) == 0 ||
- strcasecmp( style, "sub" ) == 0 )
- {
- if( *right == '\0' ) {
- ber_str2bv( "*", STRLENOF( "*" ), 1, &a->acl_dn_pat );
+ if ( strncasecmp( left, "real", STRLENOF( "real" ) ) == 0 ) {
+ is_realdn = 1;
+ bdn = &b->a_realdn;
+ left += STRLENOF( "real" );
+ }
- } else {
- a->acl_dn_style = ACL_STYLE_SUBTREE;
- ber_str2bv( right, 0, 1, &a->acl_dn_pat );
- }
+ if ( strcasecmp( left, "*" ) == 0 ) {
+ if ( is_realdn ) {
+ goto fail;
+ }
- } else if ( strcasecmp( style, "children" ) == 0 ) {
- a->acl_dn_style = ACL_STYLE_CHILDREN;
- ber_str2bv( right, 0, 1, &a->acl_dn_pat );
+ ber_str2bv( "*", STRLENOF( "*" ), 1, &bv );
+ sty = ACL_STYLE_REGEX;
- } else if ( strcasecmp( style, "regex" ) == 0 ) {
- a->acl_dn_style = ACL_STYLE_REGEX;
+ } else if ( strcasecmp( left, "anonymous" ) == 0 ) {
+ ber_str2bv("anonymous", STRLENOF( "anonymous" ), 1, &bv);
+ sty = ACL_STYLE_ANONYMOUS;
- if ( *right == '\0' ) {
- /* empty regex should match empty DN */
- a->acl_dn_style = ACL_STYLE_BASE;
- ber_str2bv( right, 0, 1, &a->acl_dn_pat );
+ } else if ( strcasecmp( left, "users" ) == 0 ) {
+ ber_str2bv("users", STRLENOF( "users" ), 1, &bv);
+ sty = ACL_STYLE_USERS;
- } else if ( strcmp(right, "*") == 0
- || strcmp(right, ".*") == 0
- || strcmp(right, ".*$") == 0
- || strcmp(right, "^.*") == 0
- || strcmp(right, "^.*$") == 0
- || strcmp(right, ".*$$") == 0
- || strcmp(right, "^.*$$") == 0 )
- {
- ber_str2bv( "*", STRLENOF("*"), 1, &a->acl_dn_pat );
+ } else if ( strcasecmp( left, "self" ) == 0 ) {
+ ber_str2bv("self", STRLENOF( "self" ), 1, &bv);
+ sty = ACL_STYLE_SELF;
- } else {
- acl_regex_normalized_dn( right, &a->acl_dn_pat );
- }
+ } else if ( strcasecmp( left, "dn" ) == 0 ) {
+ if ( sty == ACL_STYLE_REGEX ) {
+ bdn->a_style = ACL_STYLE_REGEX;
+ if ( right == NULL ) {
+ /* no '=' */
+ ber_str2bv("users",
+ STRLENOF( "users" ),
+ 1, &bv);
+ bdn->a_style = ACL_STYLE_USERS;
+
+ } else if (*right == '\0' ) {
+ /* dn="" */
+ ber_str2bv("anonymous",
+ STRLENOF( "anonymous" ),
+ 1, &bv);
+ bdn->a_style = ACL_STYLE_ANONYMOUS;
+
+ } else if ( strcmp( right, "*" ) == 0 ) {
+ /* dn=* */
+ /* any or users? users for now */
+ ber_str2bv("users",
+ STRLENOF( "users" ),
+ 1, &bv);
+ bdn->a_style = ACL_STYLE_USERS;
+
+ } else if ( strcmp( right, ".+" ) == 0
+ || strcmp( right, "^.+" ) == 0
+ || strcmp( right, ".+$" ) == 0
+ || strcmp( right, "^.+$" ) == 0
+ || strcmp( right, ".+$$" ) == 0
+ || strcmp( right, "^.+$$" ) == 0 )
+ {
+ ber_str2bv("users",
+ STRLENOF( "users" ),
+ 1, &bv);
+ bdn->a_style = ACL_STYLE_USERS;
+
+ } else if ( strcmp( right, ".*" ) == 0
+ || strcmp( right, "^.*" ) == 0
+ || strcmp( right, ".*$" ) == 0
+ || strcmp( right, "^.*$" ) == 0
+ || strcmp( right, ".*$$" ) == 0
+ || strcmp( right, "^.*$$" ) == 0 )
+ {
+ ber_str2bv("*",
+ STRLENOF( "*" ),
+ 1, &bv);
- } else {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unknown dn style \"%s\" in to clause", style );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
+ } else {
+ acl_regex_normalized_dn( right, &bv );
+ if ( !ber_bvccmp( &bv, '*' ) ) {
+ if ( regtest( c, bv.bv_val ) != 0)
+ goto fail;
}
-
- continue;
}
- if ( strcasecmp( left, "filter" ) == 0 ) {
- if ( (a->acl_filter = str2filter( right )) == NULL ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "bad filter \"%s\" in to clause", right );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ } else if ( right == NULL || *right == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "missing \"=\" in (or value after) \"%s\" in by clause", left );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
- } else if ( strcasecmp( left, "attr" ) == 0 /* TOLERATED */
- || strcasecmp( left, "attrs" ) == 0 ) /* DOCUMENTED */
- {
- if ( strcasecmp( left, "attr" ) == 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "\"attr\" is deprecated (and undocumented); "
- "use \"attrs\" instead");
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- }
+ } else {
+ ber_str2bv( right, 0, 1, &bv );
+ }
- a->acl_attrs = str2anlist( a->acl_attrs,
- right, "," );
- if ( a->acl_attrs == NULL ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unknown attr \"%s\" in to clause", right );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ } else {
+ BER_BVZERO( &bv );
+ }
- } else if ( strncasecmp( left, "val", 3 ) == 0 ) {
- struct berval bv;
- char *mr;
+ if ( !BER_BVISNULL( &bv ) ) {
+ if ( !BER_BVISEMPTY( &bdn->a_pat ) ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "dn pattern already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( !BER_BVISEMPTY( &a->acl_attrval ) ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "attr val already specified in to clause" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- if ( a->acl_attrs == NULL || !BER_BVISEMPTY( &a->acl_attrs[1].an_name ) )
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "attr val requires a single attribute");
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
+ if ( sty != ACL_STYLE_REGEX &&
+ sty != ACL_STYLE_ANONYMOUS &&
+ sty != ACL_STYLE_USERS &&
+ sty != ACL_STYLE_SELF &&
+ expand == 0 )
+ {
+ rc = dnNormalize(0, NULL, NULL,
+ &bv, &bdn->a_pat, NULL);
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "bad DN \"%s\" in by DN clause", bv.bv_val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ free( bv.bv_val );
+ if ( sty == ACL_STYLE_BASE
+ && be != NULL
+ && !BER_BVISNULL( &be->be_rootndn )
+ && dn_match( &bdn->a_pat, &be->be_rootndn ) )
+ {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "rootdn is always granted unlimited privileges" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ }
+
+ } else {
+ bdn->a_pat = bv;
+ }
+ bdn->a_style = sty;
+ if ( expand ) {
+ char *exp;
+ int gotit = 0;
+
+ for ( exp = strchr( bdn->a_pat.bv_val, '$' );
+ exp && (ber_len_t)(exp - bdn->a_pat.bv_val)
+ < bdn->a_pat.bv_len;
+ exp = strchr( exp, '$' ) )
+ {
+ if ( ( isdigit( (unsigned char) exp[ 1 ] ) ||
+ exp[ 1 ] == '{' ) ) {
+ gotit = 1;
+ break;
}
+ }
- ber_str2bv( right, 0, 0, &bv );
- a->acl_attrval_style = ACL_STYLE_BASE;
+ if ( gotit == 1 ) {
+ bdn->a_expand = expand;
- mr = strchr( left, '/' );
- if ( mr != NULL ) {
- mr[ 0 ] = '\0';
- mr++;
+ } else {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "\"expand\" used with no expansions in \"pattern\"");
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ }
+ if ( sty == ACL_STYLE_SELF ) {
+ bdn->a_self_level = level;
- a->acl_attrval_mr = mr_find( mr );
- if ( a->acl_attrval_mr == NULL ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "invalid matching rule \"%s\"", mr);
- Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
- goto fail;
- }
+ } else {
+ if ( level < 0 ) {
+ snprintf( c->cr_msg, sizeof( c ->cr_msg ),
+ "bad negative level \"%d\" in by DN clause", level );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ } else if ( level == 1 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "\"onelevel\" should be used instead of \"level{1}\" in by DN clause" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ } else if ( level == 0 && sty == ACL_STYLE_LEVEL ) {
+ snprintf ( c->cr_msg, sizeof( c->cr_msg ),
+ "\"base\" should be used instead of \"level{0}\" in by DN clause" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ }
- if( !mr_usable_with_at( a->acl_attrval_mr, a->acl_attrs[ 0 ].an_desc->ad_type ) )
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "matching rule \"%s\" use " "with attr \"%s\" not appropriate",
- mr,
- a->acl_attrs[0].an_name.bv_val );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c-> log, c->cr_msg );
- goto fail;
- }
- }
+ bdn->a_level = level;
+ }
+ continue;
+ }
- if ( style != NULL ) {
- if ( strcasecmp( style, "regex" ) == 0 ) {
- int e = regcomp( &a->acl_attrval_re, bv.bv_val,
- REG_EXTENDED | REG_ICASE );
- if ( e ) {
- char err[SLAP_TEXT_BUFLEN];
+ if ( strcasecmp( left, "dnattr" ) == 0 ) {
+ if ( right == NULL || right[0] == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "missing \"=\" in (or value after) \"%s\" in by clause", left );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- regerror( e, &a->acl_attrval_re, err, sizeof( err ) );
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "regular expression \"%s\" bad because of %s",
- right, err );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- a->acl_attrval_style = ACL_STYLE_REGEX;
+ if( bdn->a_at != NULL ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "dnattr already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- } else {
- /* FIXME: if the attribute has DN syntax, we might
- * allow one, subtree and children styles as well */
- if ( !strcasecmp( style, "base" ) ||
- !strcasecmp( style, "exact" ) ) {
- a->acl_attrval_style = ACL_STYLE_BASE;
+ rc = slap_str2ad( right, &bdn->a_at, &text );
- } else if ( a->acl_attrs[0].an_desc->ad_type->
- sat_syntax == slap_schema.si_syn_distinguishedName )
- {
- if ( !strcasecmp( style, "baseObject" ) ||
- !strcasecmp( style, "base" ) )
- {
- a->acl_attrval_style = ACL_STYLE_BASE;
- } else if ( !strcasecmp( style, "onelevel" ) ||
- !strcasecmp( style, "one" ) )
- {
- a->acl_attrval_style = ACL_STYLE_ONE;
- } else if ( !strcasecmp( style, "subtree" ) ||
- !strcasecmp( style, "sub" ) )
- {
- a->acl_attrval_style = ACL_STYLE_SUBTREE;
- } else if ( !strcasecmp( style, "children" ) ) {
- a->acl_attrval_style = ACL_STYLE_CHILDREN;
- } else {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unknown val.<style> \"%s\" for attributeType \"%s\" " "with DN syntax",
- style,
- a->acl_attrs[0].an_desc->ad_cname.bv_val );
- Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if( rc != LDAP_SUCCESS ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "dnattr \"%s\": %s", right, text );
+ Debug(LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- rc = dnNormalize( 0, NULL, NULL, &bv, &a->acl_attrval, NULL );
- if ( rc != LDAP_SUCCESS ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unable to normalize DN \"%s\" " "for attributeType \"%s\" (%d)",
- bv.bv_val,
- a->acl_attrs[0].an_desc->ad_cname.bv_val,
- rc );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- } else {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unknown val.<style> \"%s\" for attributeType \"%s\"",
- fname,
- a->acl_attrs[0].an_desc->ad_cname.bv_val );
- Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- }
- }
+ if( !is_at_syntax( bdn->a_at->ad_type,
+ SLAPD_DN_SYNTAX ) &&
+ !is_at_syntax( bdn->a_at->ad_type,
+ SLAPD_NAMEUID_SYNTAX ))
+ {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "dnattr \"%s\": " "inappropriate syntax: %s",
+ right, bdn->a_at->ad_type->sat_syntax_oid );
+ Debug(LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- /* Check for appropriate matching rule */
- if ( a->acl_attrval_style == ACL_STYLE_REGEX ) {
- ber_dupbv( &a->acl_attrval, &bv );
+ if( bdn->a_at->ad_type->sat_equality == NULL ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "dnattr \"%s\": inappropriate matching (no EQUALITY)", right );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- } else if ( BER_BVISNULL( &a->acl_attrval ) ) {
- int rc;
- const char *text;
+ continue;
+ }
- if ( a->acl_attrval_mr == NULL ) {
- a->acl_attrval_mr = a->acl_attrs[ 0 ].an_desc->ad_type->sat_equality;
- }
+ if ( strncasecmp( left, "group", STRLENOF( "group" ) ) == 0 ) {
+ char *name = NULL;
+ char *value = NULL;
+ char *attr_name = SLAPD_GROUP_ATTR;
- if ( a->acl_attrval_mr == NULL ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "attr \"%s\" does not have an EQUALITY matching rule",
- a->acl_attrs[ 0 ].an_name.bv_val );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ switch ( sty ) {
+ case ACL_STYLE_REGEX:
+ /* legacy, tolerated */
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "deprecated group style \"regex\"; use \"expand\" instead" );
+ Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, "%s: %s.\n", c->log, c->cr_msg );
+ sty = ACL_STYLE_EXPAND;
+ break;
- rc = asserted_value_validate_normalize(
- a->acl_attrs[ 0 ].an_desc,
- a->acl_attrval_mr,
- SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
- &bv,
- &a->acl_attrval,
- &text,
- NULL );
- if ( rc != LDAP_SUCCESS ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "attr \"%s\" normalization failed (%d: %s).\n",
- a->acl_attrs[0].an_name.bv_val,
- rc, text );
- Debug(LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- }
+ case ACL_STYLE_BASE:
+ /* legal, traditional */
+ case ACL_STYLE_EXPAND:
+ /* legal, substring expansion; supersedes regex */
+ break;
- } else {
+ default:
+ /* unknown */
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "expecting <what> got \"%s\"",
- left );
+ "inappropriate style \"%s\" in by clause", style );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
- }
}
- if ( !BER_BVISNULL( &a->acl_dn_pat ) &&
- ber_bvccmp( &a->acl_dn_pat, '*' ) )
- {
- free( a->acl_dn_pat.bv_val );
- BER_BVZERO( &a->acl_dn_pat );
- a->acl_dn_style = ACL_STYLE_REGEX;
+ if ( right == NULL || right[0] == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "missing \"=\" in (or value after) \"%s\" in by clause", left );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
}
- if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
- a->acl_dn_style != ACL_STYLE_REGEX )
- {
- if ( a->acl_dn_style != ACL_STYLE_REGEX ) {
- struct berval bv;
- rc = dnNormalize( 0, NULL, NULL, &a->acl_dn_pat, &bv, NULL);
- if ( rc != LDAP_SUCCESS ) {
- snprintf( c->cr_msg, sizeof(c->cr_msg ),
- "bad DN \"%s\" in to DN clause",
- a->acl_dn_pat.bv_val );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- free( a->acl_dn_pat.bv_val );
- a->acl_dn_pat = bv;
+ if ( !BER_BVISEMPTY( &b->a_group_pat ) ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "group pattern already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- } else {
- int e = regcomp( &a->acl_dn_re, a->acl_dn_pat.bv_val,
- REG_EXTENDED | REG_ICASE );
- if ( e ) {
- char err[ SLAP_TEXT_BUFLEN ];
+ /* format of string is
+ "group/objectClassValue/groupAttrName" */
+ if ( ( value = strchr(left, '/') ) != NULL ) {
+ *value++ = '\0';
+ if ( *value && ( name = strchr( value, '/' ) ) != NULL ) {
+ *name++ = '\0';
+ }
+ }
- regerror( e, &a->acl_dn_re, err, sizeof( err ) );
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "regular expression \"%s\" bad because of %s",
- right, err );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ b->a_group_style = sty;
+ if ( sty == ACL_STYLE_EXPAND ) {
+ acl_regex_normalized_dn( right, &bv );
+ if ( !ber_bvccmp( &bv, '*' ) ) {
+ if ( regtest( c, bv.bv_val ) != 0)
goto fail;
- }
+ }
+ b->a_group_pat = bv;
+
+ } else {
+ ber_str2bv( right, 0, 0, &bv );
+ rc = dnNormalize( 0, NULL, NULL, &bv,
+ &b->a_group_pat, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg),
+ "bad DN \"%s\"", right );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
}
}
- /* by clause - select who has what access to entries */
- } else if ( strcasecmp( argv[i], "by" ) == 0 ) {
- if ( a == NULL ) {
+ if ( value && *value ) {
+ b->a_group_oc = oc_find( value );
+ *--value = '/';
+
+ if ( b->a_group_oc == NULL ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "group objectclass \"%s\" unknown", value );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+
+ } else {
+ b->a_group_oc = oc_find( SLAPD_GROUP_CLASS );
+
+ if( b->a_group_oc == NULL ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "group default objectclass \"%s\" unknown", SLAPD_GROUP_CLASS );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ }
+
+ if ( is_object_subclass( slap_schema.si_oc_referral,
+ b->a_group_oc ) )
+ {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "to clause required before by clause in access line");
+ "group objectclass \"%s\" is subclass of referral", value );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- /*
- * by clause consists of <who> and <access>
- */
-
- if ( ++i == argc ) {
+ if ( is_object_subclass( slap_schema.si_oc_alias,
+ b->a_group_oc ) )
+ {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "premature EOL: expecting <who>");
+ "group objectclass \"%s\" is subclass of alias", value );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- b = (Access *) ch_calloc( 1, sizeof(Access) );
-
- ACL_INVALIDATE( b->a_access_mask );
-
- /* get <who> */
- for ( ; i < argc; i++ ) {
- slap_style_t sty = ACL_STYLE_REGEX;
- char *style_modifier = NULL;
- char *style_level = NULL;
- int level = 0;
- int expand = 0;
- slap_dn_access *bdn = &b->a_dn;
- int is_realdn = 0;
-
- split( argv[i], '=', &left, &right );
- split( left, '.', &left, &style );
- if ( style ) {
- split( style, ',', &style, &style_modifier );
-
- if ( strncasecmp( style, "level", STRLENOF( "level" ) ) == 0 ) {
- split( style, '{', &style, &style_level );
- if ( style_level != NULL ) {
- char *p = strchr( style_level, '}' );
- if ( p == NULL ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "premature eol: expecting closing '}' in \"level{n}\"");
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- } else if ( p == style_level ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "empty level in \"level{n}\"");
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- p[0] = '\0';
- }
- }
- }
+ if ( name && *name ) {
+ attr_name = name;
+ *--name = '/';
- if ( style == NULL || *style == '\0' ||
- strcasecmp( style, "exact" ) == 0 ||
- strcasecmp( style, "baseObject" ) == 0 ||
- strcasecmp( style, "base" ) == 0 )
- {
- sty = ACL_STYLE_BASE;
+ }
- } else if ( strcasecmp( style, "onelevel" ) == 0 ||
- strcasecmp( style, "one" ) == 0 )
- {
- sty = ACL_STYLE_ONE;
+ rc = slap_str2ad( attr_name, &b->a_group_at, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "group \"%s\": %s", right, text );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- } else if ( strcasecmp( style, "subtree" ) == 0 ||
- strcasecmp( style, "sub" ) == 0 )
- {
- sty = ACL_STYLE_SUBTREE;
+ if ( !is_at_syntax( b->a_group_at->ad_type,
+ SLAPD_DN_SYNTAX ) /* e.g. "member" */
+ && !is_at_syntax( b->a_group_at->ad_type,
+ SLAPD_NAMEUID_SYNTAX ) /* e.g. memberUID */
+ && !is_at_subtype( b->a_group_at->ad_type,
+ slap_schema.si_ad_labeledURI->ad_type ) /* e.g. memberURL */ )
+ {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "group \"%s\" attr \"%s\": inappropriate syntax: %s; " "must be " SLAPD_DN_SYNTAX " (DN), " SLAPD_NAMEUID_SYNTAX " (NameUID) " "or a subtype of labeledURI",
+ right, attr_name, at_syntax(b->a_group_at->ad_type) );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- } else if ( strcasecmp( style, "children" ) == 0 ) {
- sty = ACL_STYLE_CHILDREN;
- } else if ( strcasecmp( style, "level" ) == 0 )
- {
- if ( lutil_atoi( &level, style_level ) != 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unable to parse level in \"level{n}\"");
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ {
+ int rc;
+ ObjectClass *ocs[2];
- sty = ACL_STYLE_LEVEL;
+ ocs[0] = b->a_group_oc;
+ ocs[1] = NULL;
- } else if ( strcasecmp( style, "regex" ) == 0 ) {
- sty = ACL_STYLE_REGEX;
+ rc = oc_check_allowed( b->a_group_at->ad_type,
+ ocs, NULL );
- } else if ( strcasecmp( style, "expand" ) == 0 ) {
- sty = ACL_STYLE_EXPAND;
+ if( rc != 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "group: \"%s\" not allowed by \"%s\".\n",
+ b->a_group_at->ad_cname.bv_val,
+ b->a_group_oc->soc_oid );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ }
+ continue;
+ }
- } else if ( strcasecmp( style, "ip" ) == 0 ) {
- sty = ACL_STYLE_IP;
+ if ( strcasecmp( left, "peername" ) == 0 ) {
+ switch ( sty ) {
+ case ACL_STYLE_REGEX:
+ case ACL_STYLE_BASE:
+ /* legal, traditional */
+ 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;
- } else if ( strcasecmp( style, "ipv6" ) == 0 ) {
-#ifndef LDAP_PF_INET6
+ default:
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "IPv6 not supported");
+ "inappropriate style \"%s\" in by clause", style );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
-#endif /* ! LDAP_PF_INET6 */
- sty = ACL_STYLE_IPV6;
+ goto fail;
+ }
- } else if ( strcasecmp( style, "path" ) == 0 ) {
- sty = ACL_STYLE_PATH;
-#ifndef LDAP_PF_LOCAL
- snprintf( c->cr_msg, sizeof( c->cr_msg),
- "\"path\" style modifier is useless without local");
- Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
-#endif /* LDAP_PF_LOCAL */
+ if ( right == NULL || right[0] == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "missing \"=\" in (or value after) \"%s\" in by clause", left);
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- } else {
- snprintf( c->cr_msg, sizeof ( c->cr_msg ),
- "unknown style \"%s\" in by clause", style );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "peername pattern already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( style_modifier &&
- strcasecmp( style_modifier, "expand" ) == 0 )
- {
- switch ( sty ) {
- case ACL_STYLE_REGEX:
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "\"regex\" style implies \"expand\" modifier" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ b->a_peername_style = sty;
+ if ( sty == ACL_STYLE_REGEX ) {
+ acl_regex_normalized_dn( right, &bv );
+ if ( !ber_bvccmp( &bv, '*' ) ) {
+ if ( regtest( c, bv.bv_val ) != 0)
goto fail;
- break;
-
- case ACL_STYLE_EXPAND:
- break;
-
- default:
- /* we'll see later if it's pertinent */
- expand = 1;
- break;
- }
- }
-
- if ( strncasecmp( left, "real", STRLENOF( "real" ) ) == 0 ) {
- is_realdn = 1;
- bdn = &b->a_realdn;
- left += STRLENOF( "real" );
}
+ b->a_peername_pat = bv;
- if ( strcasecmp( left, "*" ) == 0 ) {
- if ( is_realdn ) {
- goto fail;
- }
-
- ber_str2bv( "*", STRLENOF( "*" ), 1, &bv );
- sty = ACL_STYLE_REGEX;
-
- } else if ( strcasecmp( left, "anonymous" ) == 0 ) {
- ber_str2bv("anonymous", STRLENOF( "anonymous" ), 1, &bv);
- sty = ACL_STYLE_ANONYMOUS;
-
- } else if ( strcasecmp( left, "users" ) == 0 ) {
- ber_str2bv("users", STRLENOF( "users" ), 1, &bv);
- sty = ACL_STYLE_USERS;
-
- } else if ( strcasecmp( left, "self" ) == 0 ) {
- ber_str2bv("self", STRLENOF( "self" ), 1, &bv);
- sty = ACL_STYLE_SELF;
-
- } else if ( strcasecmp( left, "dn" ) == 0 ) {
- if ( sty == ACL_STYLE_REGEX ) {
- bdn->a_style = ACL_STYLE_REGEX;
- if ( right == NULL ) {
- /* no '=' */
- ber_str2bv("users",
- STRLENOF( "users" ),
- 1, &bv);
- bdn->a_style = ACL_STYLE_USERS;
-
- } else if (*right == '\0' ) {
- /* dn="" */
- ber_str2bv("anonymous",
- STRLENOF( "anonymous" ),
- 1, &bv);
- bdn->a_style = ACL_STYLE_ANONYMOUS;
-
- } else if ( strcmp( right, "*" ) == 0 ) {
- /* dn=* */
- /* any or users? users for now */
- ber_str2bv("users",
- STRLENOF( "users" ),
- 1, &bv);
- bdn->a_style = ACL_STYLE_USERS;
-
- } else if ( strcmp( right, ".+" ) == 0
- || strcmp( right, "^.+" ) == 0
- || strcmp( right, ".+$" ) == 0
- || strcmp( right, "^.+$" ) == 0
- || strcmp( right, ".+$$" ) == 0
- || strcmp( right, "^.+$$" ) == 0 )
- {
- ber_str2bv("users",
- STRLENOF( "users" ),
- 1, &bv);
- bdn->a_style = ACL_STYLE_USERS;
-
- } else if ( strcmp( right, ".*" ) == 0
- || strcmp( right, "^.*" ) == 0
- || strcmp( right, ".*$" ) == 0
- || strcmp( right, "^.*$" ) == 0
- || strcmp( right, ".*$$" ) == 0
- || strcmp( right, "^.*$$" ) == 0 )
- {
- ber_str2bv("*",
- STRLENOF( "*" ),
- 1, &bv);
-
- } else {
- acl_regex_normalized_dn( right, &bv );
- if ( !ber_bvccmp( &bv, '*' ) ) {
- if ( regtest( c, bv.bv_val ) != 0)
- goto fail;
- }
- }
-
- } else if ( right == NULL || *right == '\0' ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "missing \"=\" in (or value after) \"%s\" in by clause", left );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
+ } else {
+ ber_str2bv( right, 0, 1, &b->a_peername_pat );
- } else {
- ber_str2bv( right, 0, 1, &bv );
- }
+ if ( sty == ACL_STYLE_IP ) {
+ char *addr = NULL,
+ *mask = NULL,
+ *port = NULL;
- } else {
- BER_BVZERO( &bv );
- }
+ split( right, '{', &addr, &port );
+ split( addr, '%', &addr, &mask );
- if ( !BER_BVISNULL( &bv ) ) {
- if ( !BER_BVISEMPTY( &bdn->a_pat ) ) {
+ b->a_peername_addr = inet_addr( addr );
+ if ( b->a_peername_addr == (unsigned long)(-1) ) {
+ /* illegal address */
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "dn pattern already specified" );
+ "illegal peername address \"%s\"", addr );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- if ( sty != ACL_STYLE_REGEX &&
- sty != ACL_STYLE_ANONYMOUS &&
- sty != ACL_STYLE_USERS &&
- sty != ACL_STYLE_SELF &&
- expand == 0 )
- {
- rc = dnNormalize(0, NULL, NULL,
- &bv, &bdn->a_pat, NULL);
- if ( rc != LDAP_SUCCESS ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "bad DN \"%s\" in by DN clause", bv.bv_val );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- free( bv.bv_val );
- if ( sty == ACL_STYLE_BASE
- && be != NULL
- && !BER_BVISNULL( &be->be_rootndn )
- && dn_match( &bdn->a_pat, &be->be_rootndn ) )
+ 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 */
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "rootdn is always granted unlimited privileges" );
+ "illegal peername address mask \"%s\"", mask );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
}
-
- } else {
- bdn->a_pat = bv;
}
- bdn->a_style = sty;
- if ( expand ) {
- char *exp;
- int gotit = 0;
-
- for ( exp = strchr( bdn->a_pat.bv_val, '$' );
- exp && (ber_len_t)(exp - bdn->a_pat.bv_val)
- < bdn->a_pat.bv_len;
- exp = strchr( exp, '$' ) )
- {
- if ( ( isdigit( (unsigned char) exp[ 1 ] ) ||
- exp[ 1 ] == '{' ) ) {
- gotit = 1;
- break;
- }
- }
- if ( gotit == 1 ) {
- bdn->a_expand = expand;
+ b->a_peername_port = -1;
+ if ( port ) {
+ char *end = NULL;
- } else {
+ b->a_peername_port = strtol( port, &end, 10 );
+ if ( end == port || end[0] != '}' ) {
+ /* illegal port */
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "\"expand\" used with no expansions in \"pattern\"");
+ "illegal peername port specification \"{%s}\"", port );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
}
- if ( sty == ACL_STYLE_SELF ) {
- bdn->a_self_level = level;
- } else {
- if ( level < 0 ) {
- snprintf( c->cr_msg, sizeof( c ->cr_msg ),
- "bad negative level \"%d\" in by DN clause", level );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- } else if ( level == 1 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "\"onelevel\" should be used instead of \"level{1}\" in by DN clause" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- } else if ( level == 0 && sty == ACL_STYLE_LEVEL ) {
- snprintf ( c->cr_msg, sizeof( c->cr_msg ),
- "\"base\" should be used instead of \"level{0}\" in by DN clause" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- }
+#ifdef LDAP_PF_INET6
+ } else if ( sty == ACL_STYLE_IPV6 ) {
+ char *addr = NULL,
+ *mask = NULL,
+ *port = NULL;
- bdn->a_level = level;
- }
- continue;
- }
+ split( right, '{', &addr, &port );
+ split( addr, '%', &addr, &mask );
- if ( strcasecmp( left, "dnattr" ) == 0 ) {
- if ( right == NULL || right[0] == '\0' ) {
+ if ( inet_pton( AF_INET6, addr, &b->a_peername_addr6 ) != 1 ) {
+ /* illegal address */
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "missing \"=\" in (or value after) \"%s\" in by clause", left );
+ "illegal peername address \"%s\"", addr );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- if( bdn->a_at != NULL ) {
+ 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 */
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "dnattr already specified" );
+ "illegal peername address mask \"%s\"", mask );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- rc = slap_str2ad( right, &bdn->a_at, &text );
+ b->a_peername_port = -1;
+ if ( port ) {
+ char *end = NULL;
- if( rc != LDAP_SUCCESS ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "dnattr \"%s\": %s", right, text );
- Debug(LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
+ b->a_peername_port = strtol( port, &end, 10 );
+ if ( end == port || end[0] != '}' ) {
+ /* illegal port */
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "illegal peername port specification \"{%s}\"", port );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
}
+#endif /* LDAP_PF_INET6 */
+ }
+ }
+ continue;
+ }
+ if ( strcasecmp( left, "sockname" ) == 0 ) {
+ switch ( sty ) {
+ case ACL_STYLE_REGEX:
+ case ACL_STYLE_BASE:
+ /* legal, traditional */
+ case ACL_STYLE_EXPAND:
+ /* cheap replacement to regex for simple expansion */
+ break;
- if( !is_at_syntax( bdn->a_at->ad_type,
- SLAPD_DN_SYNTAX ) &&
- !is_at_syntax( bdn->a_at->ad_type,
- SLAPD_NAMEUID_SYNTAX ))
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "dnattr \"%s\": " "inappropriate syntax: %s",
- right, bdn->a_at->ad_type->sat_syntax_oid );
- Debug(LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ default:
+ /* unknown */
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "inappropriate style \"%s\" in by clause", style );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if( bdn->a_at->ad_type->sat_equality == NULL ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "dnattr \"%s\": inappropriate matching (no EQUALITY)", right );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( right == NULL || right[0] == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "missing \"=\" in (or value after) \"%s\" in by clause", left );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- continue;
- }
+ if ( !BER_BVISNULL( &b->a_sockname_pat ) ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "sockname pattern already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( strncasecmp( left, "group", STRLENOF( "group" ) ) == 0 ) {
- char *name = NULL;
- char *value = NULL;
- char *attr_name = SLAPD_GROUP_ATTR;
+ b->a_sockname_style = sty;
+ if ( sty == ACL_STYLE_REGEX ) {
+ acl_regex_normalized_dn( right, &bv );
+ if ( !ber_bvccmp( &bv, '*' ) ) {
+ if ( regtest( c, bv.bv_val ) != 0)
+ goto fail;
+ }
+ b->a_sockname_pat = bv;
- switch ( sty ) {
- case ACL_STYLE_REGEX:
- /* legacy, tolerated */
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "deprecated group style \"regex\"; use \"expand\" instead" );
- Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, "%s: %s.\n", c->log, c->cr_msg );
- sty = ACL_STYLE_EXPAND;
- break;
+ } else {
+ ber_str2bv( right, 0, 1, &b->a_sockname_pat );
+ }
+ continue;
+ }
- case ACL_STYLE_BASE:
- /* legal, traditional */
- case ACL_STYLE_EXPAND:
- /* legal, substring expansion; supersedes regex */
- break;
+ if ( strcasecmp( left, "domain" ) == 0 ) {
+ switch ( sty ) {
+ case ACL_STYLE_REGEX:
+ case ACL_STYLE_BASE:
+ case ACL_STYLE_SUBTREE:
+ /* legal, traditional */
+ break;
- default:
- /* unknown */
+ case ACL_STYLE_EXPAND:
+ /* tolerated: means exact,expand */
+ if ( expand ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "inappropriate style \"%s\" in by clause", style );
+ "\"expand\" modifier with \"expand\" style" );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
}
+ sty = ACL_STYLE_BASE;
+ expand = 1;
+ break;
- if ( right == NULL || right[0] == '\0' ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "missing \"=\" in (or value after) \"%s\" in by clause", left );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ default:
+ /* unknown */
+ snprintf( c->cr_msg, sizeof( c->cr_msg),
+ "inappropriate style \"%s\" in by clause", style );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( !BER_BVISEMPTY( &b->a_group_pat ) ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "group pattern already specified" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( right == NULL || right[0] == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "missing \"=\" in (or value after) \"%s\" in by clause", left );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- /* format of string is
- "group/objectClassValue/groupAttrName" */
- if ( ( value = strchr(left, '/') ) != NULL ) {
- *value++ = '\0';
- if ( *value && ( name = strchr( value, '/' ) ) != NULL ) {
- *name++ = '\0';
- }
- }
+ if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "domain pattern already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- b->a_group_style = sty;
- if ( sty == ACL_STYLE_EXPAND ) {
- acl_regex_normalized_dn( right, &bv );
- if ( !ber_bvccmp( &bv, '*' ) ) {
- if ( regtest( c, bv.bv_val ) != 0)
- goto fail;
- }
- b->a_group_pat = bv;
+ b->a_domain_style = sty;
+ b->a_domain_expand = expand;
+ if ( sty == ACL_STYLE_REGEX ) {
+ acl_regex_normalized_dn( right, &bv );
+ if ( !ber_bvccmp( &bv, '*' ) ) {
+ if ( regtest( c, bv.bv_val ) != 0)
+ goto fail;
+ }
+ b->a_domain_pat = bv;
- } else {
- ber_str2bv( right, 0, 0, &bv );
- rc = dnNormalize( 0, NULL, NULL, &bv,
- &b->a_group_pat, NULL );
- if ( rc != LDAP_SUCCESS ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg),
- "bad DN \"%s\"", right );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- }
+ } else {
+ ber_str2bv( right, 0, 1, &b->a_domain_pat );
+ }
+ continue;
+ }
- if ( value && *value ) {
- b->a_group_oc = oc_find( value );
- *--value = '/';
+ if ( strcasecmp( left, "sockurl" ) == 0 ) {
+ switch ( sty ) {
+ case ACL_STYLE_REGEX:
+ case ACL_STYLE_BASE:
+ /* legal, traditional */
+ case ACL_STYLE_EXPAND:
+ /* cheap replacement to regex for simple expansion */
+ break;
- if ( b->a_group_oc == NULL ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "group objectclass \"%s\" unknown", value );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ default:
+ /* unknown */
+ snprintf( c->cr_msg, sizeof( c->cr_msg),
+ "inappropriate style \"%s\" in by clause", style );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- } else {
- b->a_group_oc = oc_find( SLAPD_GROUP_CLASS );
+ if ( right == NULL || right[0] == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "missing \"=\" in (or value after) \"%s\" in by clause", left );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if( b->a_group_oc == NULL ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "group default objectclass \"%s\" unknown", SLAPD_GROUP_CLASS );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- }
+ if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "sockurl pattern already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( is_object_subclass( slap_schema.si_oc_referral,
- b->a_group_oc ) )
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "group objectclass \"%s\" is subclass of referral", value );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ b->a_sockurl_style = sty;
+ if ( sty == ACL_STYLE_REGEX ) {
+ acl_regex_normalized_dn( right, &bv );
+ if ( !ber_bvccmp( &bv, '*' ) ) {
+ if ( regtest( c, bv.bv_val ) != 0)
goto fail;
- }
+ }
+ b->a_sockurl_pat = bv;
- if ( is_object_subclass( slap_schema.si_oc_alias,
- b->a_group_oc ) )
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "group objectclass \"%s\" is subclass of alias", value );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ } else {
+ ber_str2bv( right, 0, 1, &b->a_sockurl_pat );
+ }
+ continue;
+ }
- if ( name && *name ) {
- attr_name = name;
- *--name = '/';
+ if ( strcasecmp( left, "set" ) == 0 ) {
+ switch ( sty ) {
+ /* deprecated */
+ case ACL_STYLE_REGEX:
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "deprecated set style "
+ "\"regex\" in <by> clause; "
+ "use \"expand\" instead" );
+ Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, "%s: %s.\n", c->log, c->cr_msg );
+ sty = ACL_STYLE_EXPAND;
+ /* FALLTHRU */
- }
+ case ACL_STYLE_BASE:
+ case ACL_STYLE_EXPAND:
+ break;
- rc = slap_str2ad( attr_name, &b->a_group_at, &text );
- if ( rc != LDAP_SUCCESS ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "group \"%s\": %s", right, text );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ default:
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "inappropriate style \"%s\" in by clause", style );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( !is_at_syntax( b->a_group_at->ad_type,
- SLAPD_DN_SYNTAX ) /* e.g. "member" */
- && !is_at_syntax( b->a_group_at->ad_type,
- SLAPD_NAMEUID_SYNTAX ) /* e.g. memberUID */
- && !is_at_subtype( b->a_group_at->ad_type,
- slap_schema.si_ad_labeledURI->ad_type ) /* e.g. memberURL */ )
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "group \"%s\" attr \"%s\": inappropriate syntax: %s; " "must be " SLAPD_DN_SYNTAX " (DN), " SLAPD_NAMEUID_SYNTAX " (NameUID) " "or a subtype of labeledURI",
- right, attr_name, at_syntax(b->a_group_at->ad_type) );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( !BER_BVISEMPTY( &b->a_set_pat ) ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "set attribute already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+
+ if ( right == NULL || *right == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "no set is defined" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ b->a_set_style = sty;
+ ber_str2bv( right, 0, 1, &b->a_set_pat );
- {
- int rc;
- ObjectClass *ocs[2];
+ continue;
+ }
- ocs[0] = b->a_group_oc;
- ocs[1] = NULL;
+#ifdef SLAP_DYNACL
+ {
+ char *name = NULL,
+ *opts = NULL;
- rc = oc_check_allowed( b->a_group_at->ad_type,
- ocs, NULL );
+#if 1 /* tolerate legacy "aci" <who> */
+ if ( strcasecmp( left, "aci" ) == 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "undocumented deprecated \"aci\" directive "
+ "is superseded by \"dynacl/aci\"" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ name = "aci";
- if( rc != 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "group: \"%s\" not allowed by \"%s\".\n",
- b->a_group_at->ad_cname.bv_val,
- b->a_group_oc->soc_oid );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ } else
+#endif /* tolerate legacy "aci" <who> */
+ if ( strncasecmp( left, "dynacl/", STRLENOF( "dynacl/" ) ) == 0 ) {
+ name = &left[ STRLENOF( "dynacl/" ) ];
+ opts = strchr( name, '/' );
+ if ( opts ) {
+ opts[ 0 ] = '\0';
+ opts++;
}
- continue;
}
- if ( strcasecmp( left, "peername" ) == 0 ) {
- switch ( sty ) {
- case ACL_STYLE_REGEX:
- case ACL_STYLE_BASE:
- /* legal, traditional */
- 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;
-
- default:
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "inappropriate style \"%s\" in by clause", style );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
-
- if ( right == NULL || right[0] == '\0' ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "missing \"=\" in (or value after) \"%s\" in by clause", left);
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
-
- if ( !BER_BVISEMPTY( &b->a_peername_pat ) ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "peername pattern already specified" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
-
- b->a_peername_style = sty;
- if ( sty == ACL_STYLE_REGEX ) {
- acl_regex_normalized_dn( right, &bv );
- if ( !ber_bvccmp( &bv, '*' ) ) {
- if ( regtest( c, bv.bv_val ) != 0)
- goto fail;
- }
- b->a_peername_pat = bv;
-
- } else {
- ber_str2bv( right, 0, 1, &b->a_peername_pat );
+ if ( name ) {
+ if ( slap_dynacl_config( c, b, name, opts, sty, right ) ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unable to configure dynacl \"%s\"", name );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( sty == ACL_STYLE_IP ) {
- char *addr = NULL,
- *mask = NULL,
- *port = NULL;
+ continue;
+ }
+ }
+#endif /* SLAP_DYNACL */
- split( right, '{', &addr, &port );
- split( addr, '%', &addr, &mask );
+ if ( strcasecmp( left, "ssf" ) == 0 ) {
+ if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "inappropriate style \"%s\" in by clause", style );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- b->a_peername_addr = inet_addr( addr );
- if ( b->a_peername_addr == (unsigned long)(-1) ) {
- /* illegal address */
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "illegal peername address \"%s\"", addr );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( b->a_authz.sai_ssf ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "ssf attribute already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- 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 */
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "illegal peername address mask \"%s\"", mask );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- }
+ if ( right == NULL || *right == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "no ssf is defined" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- b->a_peername_port = -1;
- if ( port ) {
- char *end = NULL;
+ if ( lutil_atou( &b->a_authz.sai_ssf, right ) != 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unable to parse ssf value (%s)", right );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- b->a_peername_port = strtol( port, &end, 10 );
- if ( end == port || end[0] != '}' ) {
- /* illegal port */
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "illegal peername port specification \"{%s}\"", port );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- }
+ if ( !b->a_authz.sai_ssf ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "invalid ssf value (%s)", right );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ continue;
+ }
-#ifdef LDAP_PF_INET6
- } else if ( sty == ACL_STYLE_IPV6 ) {
- char *addr = NULL,
- *mask = NULL,
- *port = NULL;
+ if ( strcasecmp( left, "transport_ssf" ) == 0 ) {
+ if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "inappropriate style \"%s\" in by clause", style );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- split( right, '{', &addr, &port );
- split( addr, '%', &addr, &mask );
+ if ( b->a_authz.sai_transport_ssf ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "transport_ssf attribute already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( inet_pton( AF_INET6, addr, &b->a_peername_addr6 ) != 1 ) {
- /* illegal address */
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "illegal peername address \"%s\"", addr );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( right == NULL || *right == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "no transport_ssf is defined" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( mask == NULL ) {
- mask = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF";
- }
+ if ( lutil_atou( &b->a_authz.sai_transport_ssf, right ) != 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unable to parse transport_ssf value (%s)", right );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( inet_pton( AF_INET6, mask, &b->a_peername_mask6 ) != 1 ) {
- /* illegal mask */
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "illegal peername address mask \"%s\"", mask );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( !b->a_authz.sai_transport_ssf ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "invalid transport_ssf value (%s)", right );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ continue;
+ }
- b->a_peername_port = -1;
- if ( port ) {
- char *end = NULL;
+ if ( strcasecmp( left, "tls_ssf" ) == 0 ) {
+ if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "inappropriate style \"%s\" in by clause", style );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- b->a_peername_port = strtol( port, &end, 10 );
- if ( end == port || end[0] != '}' ) {
- /* illegal port */
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "illegal peername port specification \"{%s}\"", port );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- }
-#endif /* LDAP_PF_INET6 */
- }
- }
- continue;
- }
+ if ( b->a_authz.sai_tls_ssf ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "tls_ssf attribute already specified" );
+ goto fail;
+ }
- if ( strcasecmp( left, "sockname" ) == 0 ) {
- switch ( sty ) {
- case ACL_STYLE_REGEX:
- case ACL_STYLE_BASE:
- /* legal, traditional */
- case ACL_STYLE_EXPAND:
- /* cheap replacement to regex for simple expansion */
- break;
+ if ( right == NULL || *right == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "no tls_ssf is defined" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- default:
- /* unknown */
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "inappropriate style \"%s\" in by clause", style );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( lutil_atou( &b->a_authz.sai_tls_ssf, right ) != 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unable to parse tls_ssf value (%s)", right );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( right == NULL || right[0] == '\0' ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "missing \"=\" in (or value after) \"%s\" in by clause", left );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( !b->a_authz.sai_tls_ssf ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "invalid tls_ssf value (%s)", right );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ continue;
+ }
- if ( !BER_BVISNULL( &b->a_sockname_pat ) ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "sockname pattern already specified" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( strcasecmp( left, "sasl_ssf" ) == 0 ) {
+ if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "inappropriate style \"%s\" in by clause", style );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- b->a_sockname_style = sty;
- if ( sty == ACL_STYLE_REGEX ) {
- acl_regex_normalized_dn( right, &bv );
- if ( !ber_bvccmp( &bv, '*' ) ) {
- if ( regtest( c, bv.bv_val ) != 0)
- goto fail;
- }
- b->a_sockname_pat = bv;
+ if ( b->a_authz.sai_sasl_ssf ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "sasl_ssf attribute already specified" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- } else {
- ber_str2bv( right, 0, 1, &b->a_sockname_pat );
- }
- continue;
- }
+ if ( right == NULL || *right == '\0' ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "no sasl_ssf is defined" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( strcasecmp( left, "domain" ) == 0 ) {
- switch ( sty ) {
- case ACL_STYLE_REGEX:
- case ACL_STYLE_BASE:
- case ACL_STYLE_SUBTREE:
- /* legal, traditional */
- break;
+ if ( lutil_atou( &b->a_authz.sai_sasl_ssf, right ) != 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unable to parse sasl_ssf value (%s)", right );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- case ACL_STYLE_EXPAND:
- /* tolerated: means exact,expand */
- if ( expand ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "\"expand\" modifier with \"expand\" style" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- }
- sty = ACL_STYLE_BASE;
- expand = 1;
- break;
+ if ( !b->a_authz.sai_sasl_ssf ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "invalid sasl_ssf value (%s)", right );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ continue;
+ }
- default:
- /* unknown */
- snprintf( c->cr_msg, sizeof( c->cr_msg),
- "inappropriate style \"%s\" in by clause", style );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( right != NULL ) {
+ /* unsplit */
+ right[-1] = '=';
+ }
+ break;
+ }
- if ( right == NULL || right[0] == '\0' ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "missing \"=\" in (or value after) \"%s\" in by clause", left );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ *pos = i;
+ *current = left;
+ return 0;
- if ( !BER_BVISEMPTY( &b->a_domain_pat ) ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "domain pattern already specified" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+fail:
+ *pos = i;
+ return 1;
+}
- b->a_domain_style = sty;
- b->a_domain_expand = expand;
- if ( sty == ACL_STYLE_REGEX ) {
- acl_regex_normalized_dn( right, &bv );
- if ( !ber_bvccmp( &bv, '*' ) ) {
- if ( regtest( c, bv.bv_val ) != 0)
- goto fail;
- }
- b->a_domain_pat = bv;
+int
+parse_acl(
+ struct config_args_s *c,
+ int pos )
+{
+ int i;
+ char *left, *right, *style;
+ AccessControl *a = NULL;
+ Access *b = NULL;
+ int rc;
+ Backend *be = c->be;
+ const char *fname = c->fname;
+ int lineno = c->lineno;
+ int argc = c->argc;
+ char **argv = c->argv;
- } else {
- ber_str2bv( right, 0, 1, &b->a_domain_pat );
- }
- continue;
+ for ( i = 1; i < argc; i++ ) {
+ /* to clause - select which entries are protected */
+ if ( strcasecmp( argv[i], "to" ) == 0 ) {
+ if ( a != NULL ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "only one to clause allowed in access line" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ a = (AccessControl *) ch_calloc( 1, sizeof(AccessControl) );
+ a->acl_attrval_style = ACL_STYLE_NONE;
+ for ( ++i; i < argc; i++ ) {
+ if ( strcasecmp( argv[i], "by" ) == 0 ) {
+ i--;
+ break;
}
- if ( strcasecmp( left, "sockurl" ) == 0 ) {
- switch ( sty ) {
- case ACL_STYLE_REGEX:
- case ACL_STYLE_BASE:
- /* legal, traditional */
- case ACL_STYLE_EXPAND:
- /* cheap replacement to regex for simple expansion */
- break;
-
- default:
- /* unknown */
- snprintf( c->cr_msg, sizeof( c->cr_msg),
- "inappropriate style \"%s\" in by clause", style );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
-
- if ( right == NULL || right[0] == '\0' ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "missing \"=\" in (or value after) \"%s\" in by clause", left );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
-
- if ( !BER_BVISEMPTY( &b->a_sockurl_pat ) ) {
+ if ( strcasecmp( argv[i], "*" ) == 0 ) {
+ if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
+ a->acl_dn_style != ACL_STYLE_REGEX )
+ {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "sockurl pattern already specified" );
+ "dn pattern already specified in to clause." );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- b->a_sockurl_style = sty;
- if ( sty == ACL_STYLE_REGEX ) {
- acl_regex_normalized_dn( right, &bv );
- if ( !ber_bvccmp( &bv, '*' ) ) {
- if ( regtest( c, bv.bv_val ) != 0)
- goto fail;
- }
- b->a_sockurl_pat = bv;
-
- } else {
- ber_str2bv( right, 0, 1, &b->a_sockurl_pat );
- }
+ ber_str2bv( "*", STRLENOF( "*" ), 1, &a->acl_dn_pat );
continue;
}
- if ( strcasecmp( left, "set" ) == 0 ) {
- switch ( sty ) {
- /* deprecated */
- case ACL_STYLE_REGEX:
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "deprecated set style "
- "\"regex\" in <by> clause; "
- "use \"expand\" instead" );
- Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, "%s: %s.\n", c->log, c->cr_msg );
- sty = ACL_STYLE_EXPAND;
- /* FALLTHRU */
-
- case ACL_STYLE_BASE:
- case ACL_STYLE_EXPAND:
- break;
-
- default:
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "inappropriate style \"%s\" in by clause", style );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ split( argv[i], '=', &left, &right );
+ split( left, '.', &left, &style );
- if ( !BER_BVISEMPTY( &b->a_set_pat ) ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "set attribute already specified" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( right == NULL ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "missing \"=\" in \"%s\" in to clause", left );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
- if ( right == NULL || *right == '\0' ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "no set is defined" );
+ if ( strcasecmp( left, "dn" ) == 0 ) {
+ if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
+ a->acl_dn_style != ACL_STYLE_REGEX )
+ {
+ snprintf( c->cr_msg, sizeof( c->cr_msg),
+ "dn pattern already specified in to clause" );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- b->a_set_style = sty;
- ber_str2bv( right, 0, 1, &b->a_set_pat );
-
- continue;
- }
-
-#ifdef SLAP_DYNACL
- {
- char *name = NULL,
- *opts = NULL;
+ if ( style == NULL || *style == '\0' ||
+ strcasecmp( style, "baseObject" ) == 0 ||
+ strcasecmp( style, "base" ) == 0 ||
+ strcasecmp( style, "exact" ) == 0 )
+ {
+ a->acl_dn_style = ACL_STYLE_BASE;
+ ber_str2bv( right, 0, 1, &a->acl_dn_pat );
-#if 1 /* tolerate legacy "aci" <who> */
- if ( strcasecmp( left, "aci" ) == 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "undocumented deprecated \"aci\" directive "
- "is superseded by \"dynacl/aci\"" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- name = "aci";
+ } else if ( strcasecmp( style, "oneLevel" ) == 0 ||
+ strcasecmp( style, "one" ) == 0 )
+ {
+ a->acl_dn_style = ACL_STYLE_ONE;
+ ber_str2bv( right, 0, 1, &a->acl_dn_pat );
- } else
-#endif /* tolerate legacy "aci" <who> */
- if ( strncasecmp( left, "dynacl/", STRLENOF( "dynacl/" ) ) == 0 ) {
- name = &left[ STRLENOF( "dynacl/" ) ];
- opts = strchr( name, '/' );
- if ( opts ) {
- opts[ 0 ] = '\0';
- opts++;
- }
- }
+ } else if ( strcasecmp( style, "subtree" ) == 0 ||
+ strcasecmp( style, "sub" ) == 0 )
+ {
+ if( *right == '\0' ) {
+ ber_str2bv( "*", STRLENOF( "*" ), 1, &a->acl_dn_pat );
- if ( name ) {
- if ( slap_dynacl_config( c, b, name, opts, sty, right ) ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unable to configure dynacl \"%s\"", name );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
+ } else {
+ a->acl_dn_style = ACL_STYLE_SUBTREE;
+ ber_str2bv( right, 0, 1, &a->acl_dn_pat );
}
- continue;
- }
- }
-#endif /* SLAP_DYNACL */
-
- if ( strcasecmp( left, "ssf" ) == 0 ) {
- if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "inappropriate style \"%s\" in by clause", style );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
-
- if ( b->a_authz.sai_ssf ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "ssf attribute already specified" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
-
- if ( right == NULL || *right == '\0' ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "no ssf is defined" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
-
- if ( lutil_atou( &b->a_authz.sai_ssf, right ) != 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unable to parse ssf value (%s)", right );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
-
- if ( !b->a_authz.sai_ssf ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "invalid ssf value (%s)", right );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
- continue;
- }
+ } else if ( strcasecmp( style, "children" ) == 0 ) {
+ a->acl_dn_style = ACL_STYLE_CHILDREN;
+ ber_str2bv( right, 0, 1, &a->acl_dn_pat );
- if ( strcasecmp( left, "transport_ssf" ) == 0 ) {
- if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "inappropriate style \"%s\" in by clause", style );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ } else if ( strcasecmp( style, "regex" ) == 0 ) {
+ a->acl_dn_style = ACL_STYLE_REGEX;
- if ( b->a_authz.sai_transport_ssf ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "transport_ssf attribute already specified" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ if ( *right == '\0' ) {
+ /* empty regex should match empty DN */
+ a->acl_dn_style = ACL_STYLE_BASE;
+ ber_str2bv( right, 0, 1, &a->acl_dn_pat );
- if ( right == NULL || *right == '\0' ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "no transport_ssf is defined" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ } else if ( strcmp(right, "*") == 0
+ || strcmp(right, ".*") == 0
+ || strcmp(right, ".*$") == 0
+ || strcmp(right, "^.*") == 0
+ || strcmp(right, "^.*$") == 0
+ || strcmp(right, ".*$$") == 0
+ || strcmp(right, "^.*$$") == 0 )
+ {
+ ber_str2bv( "*", STRLENOF("*"), 1, &a->acl_dn_pat );
- if ( lutil_atou( &b->a_authz.sai_transport_ssf, right ) != 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unable to parse transport_ssf value (%s)", right );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
- }
+ } else {
+ acl_regex_normalized_dn( right, &a->acl_dn_pat );
+ }
- if ( !b->a_authz.sai_transport_ssf ) {
+ } else {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "invalid transport_ssf value (%s)", right );
+ "unknown dn style \"%s\" in to clause", style );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
+
continue;
}
- if ( strcasecmp( left, "tls_ssf" ) == 0 ) {
- if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
+ if ( strcasecmp( left, "filter" ) == 0 ) {
+ if ( (a->acl_filter = str2filter( right )) == NULL ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "inappropriate style \"%s\" in by clause", style );
+ "bad filter \"%s\" in to clause", right );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- if ( b->a_authz.sai_tls_ssf ) {
+ } else if ( strcasecmp( left, "attr" ) == 0 /* TOLERATED */
+ || strcasecmp( left, "attrs" ) == 0 ) /* DOCUMENTED */
+ {
+ if ( strcasecmp( left, "attr" ) == 0 ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "tls_ssf attribute already specified" );
- goto fail;
+ "\"attr\" is deprecated (and undocumented); "
+ "use \"attrs\" instead");
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
}
- if ( right == NULL || *right == '\0' ) {
+ a->acl_attrs = str2anlist( a->acl_attrs,
+ right, "," );
+ if ( a->acl_attrs == NULL ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "no tls_ssf is defined" );
+ "unknown attr \"%s\" in to clause", right );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- if ( lutil_atou( &b->a_authz.sai_tls_ssf, right ) != 0 ) {
+ } else if ( strncasecmp( left, "val", 3 ) == 0 ) {
+ struct berval bv;
+ char *mr;
+
+ if ( !BER_BVISEMPTY( &a->acl_attrval ) ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unable to parse tls_ssf value (%s)", right );
+ "attr val already specified in to clause" );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
-
- if ( !b->a_authz.sai_tls_ssf ) {
+ if ( a->acl_attrs == NULL || !BER_BVISEMPTY( &a->acl_attrs[1].an_name ) )
+ {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "invalid tls_ssf value (%s)", right );
+ "attr val requires a single attribute");
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- continue;
- }
- if ( strcasecmp( left, "sasl_ssf" ) == 0 ) {
- if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "inappropriate style \"%s\" in by clause", style );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
+ ber_str2bv( right, 0, 0, &bv );
+ a->acl_attrval_style = ACL_STYLE_BASE;
+
+ mr = strchr( left, '/' );
+ if ( mr != NULL ) {
+ mr[ 0 ] = '\0';
+ mr++;
+
+ a->acl_attrval_mr = mr_find( mr );
+ if ( a->acl_attrval_mr == NULL ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "invalid matching rule \"%s\"", mr);
+ Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
+ goto fail;
+ }
+
+ if( !mr_usable_with_at( a->acl_attrval_mr, a->acl_attrs[ 0 ].an_desc->ad_type ) )
+ {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "matching rule \"%s\" use " "with attr \"%s\" not appropriate",
+ mr,
+ a->acl_attrs[0].an_name.bv_val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c-> log, c->cr_msg );
+ goto fail;
+ }
}
- if ( b->a_authz.sai_sasl_ssf ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "sasl_ssf attribute already specified" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
+ if ( style != NULL ) {
+ if ( strcasecmp( style, "regex" ) == 0 ) {
+ int e = regcomp( &a->acl_attrval_re, bv.bv_val,
+ REG_EXTENDED | REG_ICASE );
+ if ( e ) {
+ char err[SLAP_TEXT_BUFLEN];
+
+ regerror( e, &a->acl_attrval_re, err, sizeof( err ) );
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "regular expression \"%s\" bad because of %s",
+ right, err );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ a->acl_attrval_style = ACL_STYLE_REGEX;
+
+ } else {
+ /* FIXME: if the attribute has DN syntax, we might
+ * allow one, subtree and children styles as well */
+ if ( !strcasecmp( style, "base" ) ||
+ !strcasecmp( style, "exact" ) ) {
+ a->acl_attrval_style = ACL_STYLE_BASE;
+
+ } else if ( a->acl_attrs[0].an_desc->ad_type->
+ sat_syntax == slap_schema.si_syn_distinguishedName )
+ {
+ if ( !strcasecmp( style, "baseObject" ) ||
+ !strcasecmp( style, "base" ) )
+ {
+ a->acl_attrval_style = ACL_STYLE_BASE;
+ } else if ( !strcasecmp( style, "onelevel" ) ||
+ !strcasecmp( style, "one" ) )
+ {
+ a->acl_attrval_style = ACL_STYLE_ONE;
+ } else if ( !strcasecmp( style, "subtree" ) ||
+ !strcasecmp( style, "sub" ) )
+ {
+ a->acl_attrval_style = ACL_STYLE_SUBTREE;
+ } else if ( !strcasecmp( style, "children" ) ) {
+ a->acl_attrval_style = ACL_STYLE_CHILDREN;
+ } else {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unknown val.<style> \"%s\" for attributeType \"%s\" " "with DN syntax",
+ style,
+ a->acl_attrs[0].an_desc->ad_cname.bv_val );
+ Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+
+ rc = dnNormalize( 0, NULL, NULL, &bv, &a->acl_attrval, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unable to normalize DN \"%s\" " "for attributeType \"%s\" (%d)",
+ bv.bv_val,
+ a->acl_attrs[0].an_desc->ad_cname.bv_val,
+ rc );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+
+ } else {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unknown val.<style> \"%s\" for attributeType \"%s\"",
+ fname,
+ a->acl_attrs[0].an_desc->ad_cname.bv_val );
+ Debug( LDAP_DEBUG_CONFIG | LDAP_DEBUG_ACL, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ }
}
- if ( right == NULL || *right == '\0' ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "no sasl_ssf is defined" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto fail;
+ /* Check for appropriate matching rule */
+ if ( a->acl_attrval_style == ACL_STYLE_REGEX ) {
+ ber_dupbv( &a->acl_attrval, &bv );
+
+ } else if ( BER_BVISNULL( &a->acl_attrval ) ) {
+ int rc;
+ const char *text;
+
+ if ( a->acl_attrval_mr == NULL ) {
+ a->acl_attrval_mr = a->acl_attrs[ 0 ].an_desc->ad_type->sat_equality;
+ }
+
+ if ( a->acl_attrval_mr == NULL ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "attr \"%s\" does not have an EQUALITY matching rule",
+ a->acl_attrs[ 0 ].an_name.bv_val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+
+ rc = asserted_value_validate_normalize(
+ a->acl_attrs[ 0 ].an_desc,
+ a->acl_attrval_mr,
+ SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
+ &bv,
+ &a->acl_attrval,
+ &text,
+ NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "attr \"%s\" normalization failed (%d: %s).\n",
+ a->acl_attrs[0].an_name.bv_val,
+ rc, text );
+ Debug(LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
}
- if ( lutil_atou( &b->a_authz.sai_sasl_ssf, right ) != 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "unable to parse sasl_ssf value (%s)", right );
+ } else {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "expecting <what> got \"%s\"",
+ left );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+ }
+
+ if ( !BER_BVISNULL( &a->acl_dn_pat ) &&
+ ber_bvccmp( &a->acl_dn_pat, '*' ) )
+ {
+ free( a->acl_dn_pat.bv_val );
+ BER_BVZERO( &a->acl_dn_pat );
+ a->acl_dn_style = ACL_STYLE_REGEX;
+ }
+
+ if ( !BER_BVISEMPTY( &a->acl_dn_pat ) ||
+ a->acl_dn_style != ACL_STYLE_REGEX )
+ {
+ if ( a->acl_dn_style != ACL_STYLE_REGEX ) {
+ struct berval bv;
+ rc = dnNormalize( 0, NULL, NULL, &a->acl_dn_pat, &bv, NULL);
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->cr_msg, sizeof(c->cr_msg ),
+ "bad DN \"%s\" in to DN clause",
+ a->acl_dn_pat.bv_val );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
+ free( a->acl_dn_pat.bv_val );
+ a->acl_dn_pat = bv;
+
+ } else {
+ int e = regcomp( &a->acl_dn_re, a->acl_dn_pat.bv_val,
+ REG_EXTENDED | REG_ICASE );
+ if ( e ) {
+ char err[ SLAP_TEXT_BUFLEN ];
- if ( !b->a_authz.sai_sasl_ssf ) {
+ regerror( e, &a->acl_dn_re, err, sizeof( err ) );
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "invalid sasl_ssf value (%s)", right );
+ "regular expression \"%s\" bad because of %s",
+ right, err );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
goto fail;
}
- continue;
}
+ }
- if ( right != NULL ) {
- /* unsplit */
- right[-1] = '=';
- }
- break;
+ /* by clause - select who has what access to entries */
+ } else if ( strcasecmp( argv[i], "by" ) == 0 ) {
+ if ( a == NULL ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "to clause required before by clause in access line");
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+
+ /*
+ * by clause consists of <who> and <access>
+ */
+
+ if ( ++i == argc ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "premature EOL: expecting <who>");
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
+ goto fail;
+ }
+
+ b = (Access *) ch_calloc( 1, sizeof(Access) );
+
+ ACL_INVALIDATE( b->a_access_mask );
+
+ /* get <who> */
+ if ( acl_parse_who( c, b, argv, argc, &i, &left ) ) {
+ goto fail;
}
if ( i == argc || ( strcasecmp( left, "stop" ) == 0 ) ) {
}
static char *
-access2text( Access *b, char *ptr )
+acl_who2text( Access *b, char *ptr )
{
- char maskbuf[ACCESSMASK_MAXLEN];
-
- ptr = acl_safe_strcopy( ptr, "\tby" );
-
if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
ptr = dnaccess2text( &b->a_dn, ptr, 0 );
}
}
ptr = acl_safe_strcopy( ptr, " " );
+ return ptr;
+}
+
+static char *
+access2text( Access *b, char *ptr )
+{
+ char maskbuf[ACCESSMASK_MAXLEN];
+
+ ptr = acl_safe_strcopy( ptr, "\tby" );
+
+ ptr = acl_who2text( b, ptr );
+
if ( b->a_dn_self ) {
ptr = acl_safe_strcopy( ptr, "self" );
} else if ( b->a_realdn_self ) {