mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-01-06 10:46:21 +08:00
initial commit of "level" styles for "dn" and "self" by clauses (ITS#3615)
This commit is contained in:
parent
26c1524163
commit
584b21d20b
@ -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
|
||||
|
@ -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 ) {
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user