From 584b21d20bec36baa7f2f8fcb3ab2a64a7b938ba Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati <ando@openldap.org> Date: Thu, 31 Mar 2005 18:10:11 +0000 Subject: [PATCH] initial commit of "level" styles for "dn" and "self" by clauses (ITS#3615) --- doc/man/man5/slapd.access.5 | 38 ++++++++++++++--- servers/slapd/acl.c | 57 +++++++++++++++++++++++-- servers/slapd/aclparse.c | 83 ++++++++++++++++++++++++++++++++++++- servers/slapd/slap.h | 3 ++ 4 files changed, 171 insertions(+), 10 deletions(-) diff --git a/doc/man/man5/slapd.access.5 b/doc/man/man5/slapd.access.5 index feae8d2b9c..058239b9fb 100644 --- a/doc/man/man5/slapd.access.5 +++ b/doc/man/man5/slapd.access.5 @@ -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 diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index cbf1b677f2..29e348494f 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -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 ) { diff --git a/servers/slapd/aclparse.c b/servers/slapd/aclparse.c index 064267970b..b72ad12d4a 100644 --- a/servers/slapd/aclparse.c +++ b/servers/slapd/aclparse.c @@ -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 ); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 28b63a4c9c..2768a8face 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -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; -- GitLab