*
[dn[.<dnstyle>]=<DN>]
[filter=<ldapfilter>]
- [attrs=<attrlist>]
+ [attrs=<attrlist>[ val[.<style>]=<attrval>]]
.fi
.LP
The wildcard
indicating access to the entry's children. ObjectClass names may also
be specified in this list, which will affect all the attributes that
are required and/or allowed by that objectClass.
+Actually, names in
+.B <attrlist>
+that are prefixed by
+.B +
+are directly treated as objectClass names, while names that
+do not correspond to an attribute type are also searched
+in the objectclass set.
+This latter behavior is deprecated and might not be supported
+in future releases.
+A name prefixed by
+.B !
+is also treated as an objectClass, but in this case the access rule
+affects the attributes that are not required nor allowed
+by that objectClass.
.LP
Using the form
.B attrs=<attr> val[.<style>]=<value>
of
.B exact
(the default) uses the attribute's equality matching rule to compare the
-value. If the
+value. If the value
.B <style>
is
.BR regex ,
the provided value is used as a regular expression pattern.
+If the attribute has DN syntax, the value
+.B <style>
+can be any of
+.BR base ,
+.BR onelevel ,
+.B subtree
+or
+.BR children ,
+resulting in base, onelevel, subtree or children match, respectively.
.LP
The dn, filter, and attrs statements are additive; they can be used in sequence
to select entities the access rule applies to based on naming context,
"acl_get: val %s\n",
a->acl_attrval.bv_val, 0, 0 );
#endif
- if (value_match( &match, desc,
- desc->ad_type->sat_equality, 0,
- val, &a->acl_attrval, &text ) != LDAP_SUCCESS ||
- match )
- return ACL_BREAK;
+
+ if ( a->acl_attrs[0].an_desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
+ if (value_match( &match, desc,
+ desc->ad_type->sat_equality, 0,
+ val, &a->acl_attrval, &text ) != LDAP_SUCCESS ||
+ match )
+ return ACL_BREAK;
+
+ } else {
+ int patlen, vdnlen, rc, got_match = 0;
+ struct berval vdn = { 0, NULL };
+
+ /* it is a DN */
+ assert( a->acl_attrs[0].an_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName );
+
+ rc = dnNormalize( 0, NULL, NULL, val, &vdn,
+ op->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ /* error */
+ return ACL_BREAK;
+ }
+
+ patlen = a->acl_attrval.bv_len;
+ vdnlen = vdn.bv_len;
+
+ if ( vdnlen < patlen )
+ goto attrval_cleanup;
+
+ if ( a->acl_dn_style == ACL_STYLE_BASE ) {
+ if ( vdnlen > patlen )
+ goto attrval_cleanup;
+
+ } else if ( a->acl_dn_style == ACL_STYLE_ONE ) {
+ int rdnlen = -1;
+
+ if ( !DN_SEPARATOR( vdn.bv_val[vdnlen - patlen - 1] ) )
+ goto attrval_cleanup;
+
+ rdnlen = dn_rdnlen( NULL, &vdn );
+ if ( rdnlen != vdnlen - patlen - 1 )
+ goto attrval_cleanup;
+
+ } else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) {
+ if ( vdnlen > patlen && !DN_SEPARATOR( vdn.bv_val[vdnlen - patlen - 1] ) )
+ goto attrval_cleanup;
+
+ } else if ( a->acl_dn_style == ACL_STYLE_CHILDREN ) {
+ if ( vdnlen <= patlen )
+ goto attrval_cleanup;
+
+ if ( !DN_SEPARATOR( vdn.bv_val[vdnlen - patlen - 1] ) )
+ goto attrval_cleanup;
+ }
+
+ got_match = strcmp( a->acl_attrval.bv_val, vdn.bv_val + vdnlen - patlen );
+
+attrval_cleanup:;
+ if ( vdn.bv_val )
+ free( vdn.bv_val );
+
+ if ( !got_match )
+ return ACL_BREAK;
+
+ }
}
}
}
a->acl_attrval_style = ACL_STYLE_REGEX;
} else {
- a->acl_attrval_style = ACL_STYLE_BASE;
+ /* FIXME: if the attribute has DN syntax,
+ * we might allow subtree and children styles as well */
+ if ( !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, "base" ) ) {
+ a->acl_attrval_style = ACL_STYLE_BASE;
+ } else if ( !strcasecmp( style, "children" ) ) {
+ a->acl_attrval_style = ACL_STYLE_CHILDREN;
+ } 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 {
+ fprintf( stderr,
+ "%s: line %d: unknown val.<style>, got \"%s\" (ignored)\n",
+ fname, lineno, style );
+ a->acl_attrval_style = ACL_STYLE_BASE;
+ }
+
+ } else {
+ fprintf( stderr,
+ "%s: line %d: unknown val.<style>, got \"%s\" (ignored)\n",
+ fname, lineno, style );
+ a->acl_attrval_style = ACL_STYLE_BASE;
+ }
}
} else {
if ( ! first ) {
fprintf( stderr, "," );
}
+ if (an->an_oc) {
+ fputc( an->an_oc_exclude ? '!' : '+', stderr);
+ }
fputs( an->an_name.bv_val, stderr );
first = 0;
}
oc = attrs->an_oc;
if( oc == NULL && attrs->an_name.bv_val ) {
switch( attrs->an_name.bv_val[0] ) {
- case '+': { /* new way */
+ case '+': /* new way */
+ case '!': { /* exclude */
struct berval ocname;
ocname.bv_len = attrs->an_name.bv_len - 1;
ocname.bv_val = &attrs->an_name.bv_val[1];
oc = oc_bvfind( &ocname );
+ attrs->an_oc_exclude = 0;
+ if ( oc && attrs->an_name.bv_val[0] == '!' ) {
+ attrs->an_oc_exclude = 1;
+ }
} break;
+
default: /* old (deprecated) way */
oc = oc_bvfind( &attrs->an_name );
}
* add on to an existing list if it was given. If the string
* is not a valid attribute name, if a '-' is prepended it is
* skipped and the remaining name is tried again; if a '+' is
- * prepended, an objectclass name is searched instead.
+ * prepended, an objectclass name is searched instead; if a
+ * '!' is prepended, the objectclass name is negated.
*
* NOTE: currently, if a valid attribute name is not found,
* the same string is also checked as valid objectclass name;
{
anew->an_desc = NULL;
anew->an_oc = NULL;
+ anew->an_oc_exclude = 0;
ber_str2bv(s, 0, 1, &anew->an_name);
slap_bv2ad(&anew->an_name, &anew->an_desc, &text);
if ( !anew->an_desc ) {
}
} break;
- case '+': {
+ case '+':
+ case '!': {
struct berval ocname;
ocname.bv_len = anew->an_name.bv_len - 1;
ocname.bv_val = &anew->an_name.bv_val[1];
strcpy( in, s );
return NULL;
}
+
+ if ( anew->an_name.bv_val[0] == '!' ) {
+ anew->an_oc_exclude = 1;
+ }
} break;
default:
null_attr.an_desc = NULL;
null_attr.an_oc = NULL;
+ null_attr.an_oc_exclude = 0;
null_attr.an_name.bv_len = 0;
null_attr.an_name.bv_val = NULL;
attrs = uuid_attr;
attrs[0].an_desc = NULL;
attrs[0].an_oc = NULL;
+ attrs[0].an_oc_exclude = 0;
attrs[0].an_name.bv_len = 0;
attrs[0].an_name.bv_val = NULL;
}
}
for( i=0; i<siz; i++ ) {
- const char *dummy;
+ int rc = LDAP_SUCCESS;
+ const char *dummy = NULL;
+
an[i].an_desc = NULL;
an[i].an_oc = NULL;
- slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
+ an[i].an_oc_exclude = 0;
+ rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
+ if ( rc != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
+ rs->sr_text = dummy ? dummy : "postread control: unknown attributeType";
+ return rc;
+ }
}
op->o_preread = ctrl->ldctl_iscritical
}
for( i=0; i<siz; i++ ) {
- const char *dummy;
+ int rc = LDAP_SUCCESS;
+ const char *dummy = NULL;
+
an[i].an_desc = NULL;
an[i].an_oc = NULL;
- slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
+ an[i].an_oc_exclude = 0;
+ rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
+ if ( rc != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
+ rs->sr_text = dummy ? dummy : "postread control: unknown attributeType";
+ return rc;
+ }
}
op->o_postread = ctrl->ldctl_iscritical
if ( ( !is_in && !ri->ri_exclude ) || ( is_in && ri->ri_exclude ) ) {
continue;
}
+
/* If the list includes objectClass names,
* only include those classes in the
* objectClass attribute
for ( an = ri->ri_attrs; an->an_name.bv_val; an++ ) {
if ( an->an_oc ) {
int i;
+
+ /* FIXME: need to
+ * handle
+ * an_oc_exclude */
for ( i=0; a->a_vals[i].bv_val; i++ ) {
- if ( a->a_vals[i].bv_len == an->an_name.bv_len
- && !strcasecmp(a->a_vals[i].bv_val,
- an->an_name.bv_val ) ) {
- ocs = 1;
+ if ( an->an_oc_exclude ) {
+ if ( a->a_vals[i].bv_len != an->an_name.bv_len
+ || strcasecmp(a->a_vals[i].bv_val,
+ an->an_name.bv_val ) ) {
+ ocs = 1;
+ }
+
+ } else {
+ if ( a->a_vals[i].bv_len == an->an_name.bv_len
+ && !strcasecmp(a->a_vals[i].bv_val,
+ an->an_name.bv_val ) ) {
+ ocs = 1;
+ }
+ }
+
+ if ( ocs ) {
vals[0] = an->an_name;
print_vals( fp, &a->a_desc->ad_cname, vals );
break;
const char *dummy; /* ignore msgs from bv2ad */
op->ors_attrs[i].an_desc = NULL;
op->ors_attrs[i].an_oc = NULL;
+ op->ors_attrs[i].an_oc_exclude = 0;
slap_bv2ad(&op->ors_attrs[i].an_name, &op->ors_attrs[i].an_desc, &dummy);
}
uuid_attr[0].an_desc = NULL;
uuid_attr[0].an_oc = NULL;
+ uuid_attr[0].an_oc_exclude = NULL;
uuid_attr[0].an_name.bv_len = 0;
uuid_attr[0].an_name.bv_val = NULL;
e.e_attrs = NULL;
typedef struct slap_attr_name {
struct berval an_name;
AttributeDescription *an_desc;
+ int an_oc_exclude;
ObjectClass *an_oc;
} AttributeName;
for (i = 0; attrs[i] != 0; i++) {
an[i].an_desc = NULL;
an[i].an_oc = NULL;
+ an[i].an_oc_exclude = 0;
an[i].an_name.bv_val = slapi_ch_strdup(attrs[i]);
an[i].an_name.bv_len = strlen(attrs[i]);
slap_bv2ad( &an[i].an_name, &an[i].an_desc, &text );