add to 'val[.<style>=<value>' ACLs special match styles for DN-valued attributes; add negated objectClass to attribute name lists for ACLs and partial replication

This commit is contained in:
Pierangelo Masarati 2003-12-16 00:49:10 +00:00
parent 6e6bef8f56
commit ee34f3fb64
11 changed files with 180 additions and 19 deletions

View File

@ -74,7 +74,7 @@ It can have the forms
*
[dn[.<dnstyle>]=<DN>]
[filter=<ldapfilter>]
[attrs=<attrlist>]
[attrs=<attrlist>[ val[.<style>]=<attrval>]]
.fi
.LP
The wildcard
@ -124,6 +124,20 @@ indicating access to the entry itself, and
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>
@ -133,11 +147,20 @@ In this case, only a single attribute type may be given. A 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,

View File

@ -668,11 +668,70 @@ acl_mask(
"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;
}
}
}

View File

@ -279,7 +279,33 @@ parse_acl(
}
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 {
@ -1692,6 +1718,9 @@ print_acl( Backend *be, AccessControl *a )
if ( ! first ) {
fprintf( stderr, "," );
}
if (an->an_oc) {
fputc( an->an_oc_exclude ? '!' : '+', stderr);
}
fputs( an->an_name.bv_val, stderr );
first = 0;
}

View File

@ -537,12 +537,18 @@ int ad_inlist(
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 );
}
@ -689,7 +695,8 @@ an_find(
* 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;
@ -727,6 +734,7 @@ str2anlist( AttributeName *an, char *in, const char *brkstr )
{
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 ) {
@ -747,7 +755,8 @@ str2anlist( AttributeName *an, char *in, const char *brkstr )
}
} 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];
@ -761,6 +770,10 @@ str2anlist( AttributeName *an, char *in, const char *brkstr )
strcpy( in, s );
return NULL;
}
if ( anew->an_name.bv_val[0] == '!' ) {
anew->an_oc_exclude = 1;
}
} break;
default:

View File

@ -481,6 +481,7 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop,
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;
@ -493,6 +494,7 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop,
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;
}

View File

@ -1018,10 +1018,17 @@ static int parsePreRead (
}
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
@ -1067,10 +1074,17 @@ static int parsePostRead (
}
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

View File

@ -344,6 +344,7 @@ replog1(
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
@ -357,11 +358,27 @@ replog1(
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;

View File

@ -177,6 +177,7 @@ do_search(
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);
}

View File

@ -45,6 +45,7 @@ slap_send_session_log(
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;

View File

@ -720,6 +720,7 @@ typedef struct slap_attr_desc {
typedef struct slap_attr_name {
struct berval an_name;
AttributeDescription *an_desc;
int an_oc_exclude;
ObjectClass *an_oc;
} AttributeName;

View File

@ -1152,6 +1152,7 @@ slapi_search_internal_bind(
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 );