]> git.sur5r.net Git - openldap/commitdiff
initial commit of "level" styles for "dn" and "self" by clauses (ITS#3615)
authorPierangelo Masarati <ando@openldap.org>
Thu, 31 Mar 2005 18:10:11 +0000 (18:10 +0000)
committerPierangelo Masarati <ando@openldap.org>
Thu, 31 Mar 2005 18:10:11 +0000 (18:10 +0000)
doc/man/man5/slapd.access.5
servers/slapd/acl.c
servers/slapd/aclparse.c
servers/slapd/slap.h

index feae8d2b9c412c05540e60f31baa7e3090e751b8..058239b9fb9c549b0249b58a9994395b735dc6e1 100644 (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
index cbf1b677f248bec2c72820b018f6aedc869d1d4c..29e348494fe009c9439d06a61d0695c3ab44dae9 100644 (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 ) {
index 064267970b66caffaf95d96479398d2e29cdd3f2..b72ad12d4a84d3f940b6e30d3ac9c98d60db3325 100644 (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 );
index 28b63a4c9cb0baad70c9cbc64e874e6551831c9f..2768a8face1315ae457a925015a1e665ba828813 100644 (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;