initial commit of "level" styles for "dn" and "self" by clauses (ITS#3615)

This commit is contained in:
Pierangelo Masarati 2005-03-31 18:10:11 +00:00
parent 26c1524163
commit 584b21d20b
4 changed files with 171 additions and 10 deletions

View File

@ -229,7 +229,7 @@ It can have the forms
*
anonymous
users
self
self[.<selfstyle>]
dn[.<dnstyle>[,<modifier>]]=<DN>
dnattr=<attrname>
@ -253,8 +253,9 @@ with
.LP
.nf
<style>={exact|regex|expand}
<selfstyle>={level{<n>}}
<dnstyle>={{exact|base(object)}|regex
|one(level)|sub(tree)|children}
|one(level)|sub(tree)|children|level{<n>}}
<groupstyle>={exact|expand}
<peernamestyle>={<style>|ip|path}
<domainstyle>={exact|regex|sub(tree)}
@ -286,6 +287,18 @@ The keyword
.B self
means access to an entry is allowed to the entry itself (e.g. the entry
being accessed and the requesting entry must be the same).
It allows the
.B level{<n>}
style, where \fI<n>\fP indicates what ancestor of the DN
is to be used in matches.
A positive value indicates that the <n>-th ancestor of the user's DN
is to be considered; a negative value indicates that the <n>-th ancestor
of the target is to be considered.
For example, a "\fIby self.level{1} ...\fP" clause would match
when the object "\fIdc=example,dc=com\fP" is accessed
by "\fIcn=User,dc=example,dc=com\fP".
A "\fIby self.level{-1} ...\fP" clause would match when the same user
accesses the object "\fIou=Address Book,cn=User,dc=example,dc=com\fP".
.LP
The statement
.B dn=<DN>
@ -360,7 +373,7 @@ the
the
.BR one(level) ,
and the
.B children
.BR children
forms provide
.B $0
as the match of the entire string.
@ -369,7 +382,7 @@ The
the
.BR one(level) ,
and the
.B children
.BR children
forms also provide
.B $1
as the match of the rightmost part of the DN as defined in the
@ -387,6 +400,14 @@ which means that only access to entries that appear in the DN of the
.B <by>
clause is allowed.
.LP
The
.BR level{<n>}
form is an extension and a generalization of the
.BR onelevel
form, which matches all DNs whose <n>-th ancestor is the pattern.
So, \fIlevel{1}\fP is equivalent to \fIonelevel\fP,
and \fIlevel{0}\fP is equivalent to \fIbase\fP.
.LP
It is perfectly useless to give any access privileges to a DN
that exactly matches the
.B rootdn
@ -804,10 +825,15 @@ is set to 1.
.LP
The
.B search
operation, for each entry, requires
operation, requires
.B search (=s)
privileges on the
.B entry
pseudo-attribute of the searchBase (NOTE: this was introduced with 2.3).
Then, for each entry, it requires
.B search (=s)
privileges on the attributes that are defined in the filter.
Then, the resulting entries are tested for
The resulting entries are finally tested for
.B read (=r)
privileges on the pseudo-attribute
.B entry

View File

@ -726,11 +726,33 @@ acl_mask(
}
} else if ( b->a_dn_style == ACL_STYLE_SELF ) {
if ( BER_BVISEMPTY( &op->o_ndn ) ) {
struct berval ndn, selfndn;
int level;
if ( BER_BVISEMPTY( &op->o_ndn ) || BER_BVISNULL( &e->e_nname ) ) {
continue;
}
level = b->a_dn_self_level;
if ( level < 0 ) {
selfndn = op->o_ndn;
ndn = e->e_nname;
level = -level;
} else {
ndn = op->o_ndn;
selfndn = e->e_nname;
}
for ( ; level > 0; level-- ) {
if ( BER_BVISEMPTY( &ndn ) ) {
break;
}
dnParent( &ndn, &ndn );
}
if ( e->e_dn == NULL || !dn_match( &e->e_nname, &op->o_ndn ) ) {
if ( BER_BVISEMPTY( &ndn ) || !dn_match( &ndn, &selfndn ) )
{
continue;
}
@ -901,9 +923,38 @@ acl_mask(
if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
} else if ( b->a_dn_style == ACL_STYLE_LEVEL ) {
int level;
struct berval ndn;
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( level > 0 && !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) )
{
goto dn_match_cleanup;
}
level = b->a_dn_level;
ndn = op->o_ndn;
for ( ; level > 0; level-- ) {
if ( BER_BVISEMPTY( &ndn ) ) {
goto dn_match_cleanup;
}
dnParent( &ndn, &ndn );
if ( ndn.bv_len < patlen ) {
goto dn_match_cleanup;
}
}
if ( ndn.bv_len != patlen ) {
goto dn_match_cleanup;
}
}
got_match = !strcmp( pat.bv_val, op->o_ndn.bv_val + odnlen - patlen );
got_match = !strcmp( pat.bv_val, &op->o_ndn.bv_val[ odnlen - patlen ] );
dn_match_cleanup:;
if ( pat.bv_val != b->a_dn_pat.bv_val ) {

View File

@ -45,7 +45,11 @@ static char *style_strings[] = {
"one",
"subtree",
"children",
"level",
"attrof",
"anonymous",
"users",
"self",
"ip",
"path",
NULL
@ -587,12 +591,35 @@ parse_acl(
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;
split( argv[i], '=', &left, &right );
split( left, '.', &left, &style );
if ( style ) {
split( style, ',', &style, &style_modifier);
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 ) {
fprintf( stderr,
"%s: line %d: premature eol: "
"expecting closing '}' in \"level{n}\"\n",
fname, lineno );
acl_usage();
} else if ( p == style_level ) {
fprintf( stderr,
"%s: line %d: empty level "
"in \"level{n}\"\n",
fname, lineno );
acl_usage();
}
p[0] = '\0';
}
}
}
if ( style == NULL || *style == '\0' ||
@ -615,6 +642,21 @@ parse_acl(
} else if ( strcasecmp( style, "children" ) == 0 ) {
sty = ACL_STYLE_CHILDREN;
} else if ( strcasecmp( style, "level" ) == 0 )
{
char *next;
level = strtol( style_level, &next, 10 );
if ( next[0] != '\0' ) {
fprintf( stderr,
"%s: line %d: unable to parse level "
"in \"level{n}\"\n",
fname, lineno );
acl_usage();
}
sty = ACL_STYLE_LEVEL;
} else if ( strcasecmp( style, "regex" ) == 0 ) {
sty = ACL_STYLE_REGEX;
@ -794,6 +836,30 @@ parse_acl(
}
b->a_dn_style = sty;
b->a_dn_expand = expand;
if ( sty == ACL_STYLE_SELF ) {
b->a_dn_self_level = level;
} else {
if ( level < 0 ) {
fprintf( stderr,
"%s: line %d: bad negative level \"%d\" "
"in by DN clause\n",
fname, lineno, level );
acl_usage();
} else if ( level == 1 ) {
fprintf( stderr,
"%s: line %d: \"onelevel\" should be used "
"instead of \"level{1}\" in by DN clause\n",
fname, lineno, 0 );
} else if ( level == 0 && sty == ACL_STYLE_LEVEL ) {
fprintf( stderr,
"%s: line %d: \"base\" should be used "
"instead of \"level{0}\" in by DN clause\n",
fname, lineno, 0 );
}
b->a_dn_level = level;
}
continue;
}
@ -2160,10 +2226,25 @@ access2text( Access *b, char *ptr )
b->a_dn_style == ACL_STYLE_SELF )
{
ptr = lutil_strcopy( ptr, b->a_dn_pat.bv_val );
if ( b->a_dn_style == ACL_STYLE_SELF && b->a_dn_self_level != 0 ) {
int n = sprintf( ptr, ".level{%d}", b->a_dn_self_level );
if ( n > 0 ) {
ptr += n;
} /* else ? */
}
} else {
ptr = lutil_strcopy( ptr, "dn." );
ptr = lutil_strcopy( ptr, style_strings[b->a_dn_style] );
if ( b->a_dn_style == ACL_STYLE_LEVEL ) {
int n = sprintf( ptr, "{%d}", b->a_dn_level );
if ( n > 0 ) {
ptr += n;
} /* else ? */
}
if ( b->a_dn_expand ) {
ptr = lutil_strcopy( ptr, ",expand" );
}
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, b->a_dn_pat.bv_val );

View File

@ -1173,6 +1173,7 @@ typedef enum slap_style_e {
ACL_STYLE_ONE,
ACL_STYLE_SUBTREE,
ACL_STYLE_CHILDREN,
ACL_STYLE_LEVEL,
ACL_STYLE_ATTROF,
ACL_STYLE_ANONYMOUS,
ACL_STYLE_USERS,
@ -1302,6 +1303,8 @@ typedef struct slap_access {
#define a_dn_pat a_authz.sai_dn
slap_style_t a_dn_style;
int a_dn_level;
int a_dn_self_level;
AttributeDescription *a_dn_at;
int a_dn_self;
int a_dn_expand;