]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
Initial commit of new ACL engine. Engine supports descrete access
authorKurt Zeilenga <kurt@openldap.org>
Thu, 21 Oct 1999 17:53:56 +0000 (17:53 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Thu, 21 Oct 1999 17:53:56 +0000 (17:53 +0000)
privs, additive/substractive rules, and rule continuation.  Existing
rules that use 'defaultaccess none' should be 100% compatible.  Rules
that rely other defaultaccess settings will require addition of
explicit clauses granting the access.
Needs additional testing and tuning of logs

doc/man/man5/slapd.conf.5
servers/slapd/acl.c
servers/slapd/aclparse.c
servers/slapd/back-bdb2/modify.c
servers/slapd/back-ldbm/modify.c
servers/slapd/backend.c
servers/slapd/config.c
servers/slapd/proto-slap.h
servers/slapd/result.c
servers/slapd/slap.h
servers/slapd/slapd.conf

index 2ebec753ac7be440d187d7208a0eca3d0245faff..321cce1099ca88b9969a1b44498d17d1d766c923 100644 (file)
@@ -67,13 +67,11 @@ overridden in a backend definition. Arguments that should be replaced by
 actual text are shown in brackets <>.
 .TP
 .B
-access to <what> [ by <who> <accesslevel> ]+
-Grant access (specified by <accesslevel>) to a set of entries and/or
+access to <what> [ by <who> <access> <control> ]+
+Grant access (specified by <access>) to a set of entries and/or
 attributes (specified by <what>) by one or more requestors (specified
-by <who>).  Refer to "The SLAPD and SLURPD Administrator's Guide" for
-information on using the
-.B slapd
-access-control mechanisms.
+by <who>).
+See Developer's FAQ (http://www.openldap.org/faq/) for details.
 .TP
 .B
 attributetype ( <oid> [NAME <name>] [DESC <description>] [OBSOLETE] \
@@ -136,9 +134,13 @@ distinguished name
 .RE
 .TP
 .B
-defaultaccess [self]{ none | compare | search | read | write }
-Specify the default access to grant requestors not matched by 
-any other access line.  The default behavior is to grant read access.
+defaultaccess { none | auth | compare | search | read | write }
+Specify the default access level to grant requestors when
+no access directives were provided for the database.
+The default behavior is to grant 'read' access.  It is
+recommended that
+.B access
+directives be used instead.
 .TP
 .B idletimeout <integer>
 Specify the number of seconds to wait before forcibly closing
index 1558fc7330ae043b11673b54e1c710836e1e9d7e..904fcb6a9cb9c0d4b10f996a05a5f8eec06a2faa 100644 (file)
 
 #include "slap.h"
 
+static AccessControl * acl_get(
+       AccessControl *ac, int *count,
+       Backend *be, Operation *op,
+       Entry *e, char *attr,
+       int nmatches, regmatch_t *matches );
+
+static slap_control_t acl_mask(
+       AccessControl *ac, slap_access_mask_t *mask,
+       Backend *be, Connection *conn, Operation *op,
+       Entry *e, char *attr, struct berval *val,
+       regmatch_t *matches );
+
 #ifdef SLAPD_ACI_ENABLED
-int aci_access_allowed (struct berval *aci, char *attr, Backend *be, Entry *e,
-                                       Operation *op, int access, char *edn, regmatch_t *matches);
+static int aci_access_allowed(
+       Backend *be,
+       Operation *op,
+       Entry *e, char *attr, struct berval *aci,
+       regmatch_t *matches );
 #endif
 
 static int     regex_matches(char *pat, char *str, char *buf, regmatch_t *matches);
@@ -28,12 +43,16 @@ static void string_expand(char *newbuf, int bufsiz, char *pattern,
 /*
  * access_allowed - check whether op->o_ndn is allowed the requested access
  * to entry e, attribute attr, value val.  if val is null, access to
- * the whole attribute is assumed (all values).  this routine finds
- * the applicable acl and calls acl_access_allowed() to make the
- * decision.
+ * the whole attribute is assumed (all values).
  *
- * returns     0       access NOT allowed
- *             1       access allowed
+ * This routine loops through all access controls and calls
+ * acl_mask() on each applicable access control.
+ * The loop exits when a definitive answer is reached or
+ * or no more controls remain.
+ *
+ * returns:
+ *             0       access denied
+ *             1       access granted
  */
 
 int
@@ -44,138 +63,167 @@ access_allowed(
     Entry              *e,
     char               *attr,
     struct berval      *val,
-    int                        access
+    slap_access_t      access
 )
 {
-       int                             rc;
+       int                             count;
        AccessControl   *a;
-       char            *edn;
+       slap_access_mask_t mask;
+       slap_control_t control;
 
        regmatch_t       matches[MAXREMATCHES];
-       int              i;
-       int              n;
 
-       if ( be == NULL ) {
-               return( 0 );
-       }
+       Debug( LDAP_DEBUG_ACL,
+               "=> access_allowed: %s access to \"%s\" \"%s\" requested\n",
+           access2str( access ),
+               e->e_dn, attr );
 
-       edn = e->e_ndn;
+       assert( be != NULL );
+       assert( e != NULL );
+       assert( attr != NULL );
+       assert( access > ACL_NONE );
 
-       Debug( LDAP_DEBUG_ACL, "\n=> access_allowed: entry (%s) attr (%s)\n",
-               e->e_dn, attr, 0 );
+       /* grant database root access */
+       if ( be != NULL && be_isroot( be, op->o_ndn ) ) {
+               Debug( LDAP_DEBUG_ACL,
+                   "<= root access granted\n",
+                       0, 0, 0 );
+               return 1;
+       }
 
-       /* the lastmod attributes are ignored by ACL checking */
+       /* no user modify operational attributes are ignored by ACL checking */
        if ( oc_check_no_usermod_attr( attr ) ) {
-               Debug( LDAP_DEBUG_ACL, "Operational attribute: %s access allowed\n",
+               Debug( LDAP_DEBUG_ACL, "NoUserMod Operational attribute:"
+                       " %s access granted\n",
                        attr, 0, 0 );
-               return(1);
+               return 1;
        }
 
+       /* use backend default access if no backend acls */
+       if( be != NULL && be->be_acl == NULL ) {
+               Debug( LDAP_DEBUG_ACL,
+                       "=> access_allowed: backend default %s access %s to \"%s\"\n",
+                       access2str( access ),
+                       be->be_dfltaccess >= access ? "granted" : "denied", op->o_dn );
+
+               return be->be_dfltaccess >= access;
+
+#ifdef notdef
+       /* be is always non-NULL */
+       /* use global default access if no global acls */
+       } else if ( be == NULL && global_acl == NULL ) {
+               Debug( LDAP_DEBUG_ACL,
+                       "=> access_allowed: global default %s access %s to \"%s\"\n",
+                       access2str( access ),
+                       global_default_access >= access ? "granted" : "denied", op->o_dn );
+
+               return global_default_access >= access;
+#endif
+       }
+
+       ACL_INIT(mask);
        memset(matches, 0, sizeof(matches));
+       
+       control = ACL_BREAK;
+       a = NULL;
+       count = 0;
 
-       a = acl_get_applicable( be, op, e, attr, MAXREMATCHES, matches );
+       while( a = acl_get( a, &count, be, op, e, attr, MAXREMATCHES, matches ) )
+       {
+               int i;
 
-       if (a) {
                for (i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++) {
-                       Debug( LDAP_DEBUG_ARGS, "=> match[%d]: %d %d ", i,
+                       Debug( LDAP_DEBUG_ACL, "=> match[%d]: %d %d ", i,
                               (int)matches[i].rm_so, (int)matches[i].rm_eo );
 
                        if( matches[i].rm_so <= matches[0].rm_eo ) {
+                               int n;
                                for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++) {
-                                       Debug( LDAP_DEBUG_ARGS, "%c", edn[n], 0, 0 );
+                                       Debug( LDAP_DEBUG_ACL, "%c", e->e_ndn[n], 0, 0 );
                                }
                        }
                        Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
                }
+
+               control = acl_mask( a, &mask, be, conn, op,
+                       e, attr, val, matches );
+
+               if ( control != ACL_BREAK ) {
+                       break;
+               }
+
+               memset(matches, 0, sizeof(matches));
        }
 
-       rc = acl_access_allowed( a, attr, be, conn, e, val, op, access, edn, matches );
+       if ( ACL_IS_INVALID( mask ) ) {
+               Debug( LDAP_DEBUG_ACL,
+                       "=> access_allowed: \"%s\" (%s) invalid!\n",
+                       e->e_dn, attr, 0 );
+               ACL_INIT( mask );
+
+       } else if ( control == ACL_BREAK ) {
+               Debug( LDAP_DEBUG_ACL,
+                       "=> access_allowed: no more rules\n", 0, 0, 0);
+               ACL_INIT( mask );
+       }
 
-       Debug( LDAP_DEBUG_ACL, "\n=> access_allowed: exit (%s) attr (%s)\n",
-               e->e_dn, attr, 0);
+       Debug( LDAP_DEBUG_ACL,
+               "=> access_allowed: %s access %s to \"%s\"\n",
+               access2str( access ),
+               ACL_GRANT(mask, access) ? "granted" : "denied", op->o_dn );
 
-       return( rc );
+       return ACL_GRANT(mask, access);
 }
 
 /*
- * acl_get_applicable - return the acl applicable to entry e, attribute
+ * acl_get - return the acl applicable to entry e, attribute
  * attr.  the acl returned is suitable for use in subsequent calls to
  * acl_access_allowed().
  */
 
-AccessControl *
-acl_get_applicable(
+static AccessControl *
+acl_get(
+       AccessControl *a,
+       int                     *count,
     Backend            *be,
-    Operation          *op,
+    Operation  *op,
     Entry              *e,
     char               *attr,
     int                        nmatch,
     regmatch_t *matches
 )
 {
-       int             i;
-       AccessControl   *a;
-    char               *edn;
-
-       Debug( LDAP_DEBUG_ACL, "\n=> acl_get: entry (%s) attr (%s)\n",
-               e->e_dn, attr, 0 );
-
-       if ( be_isroot( be, op->o_ndn ) ) {
-               Debug( LDAP_DEBUG_ACL,
-                   "<= acl_get: no acl applicable to database root\n", 0, 0,
-                   0 );
-               return( NULL );
-       }
+       AccessControl   *next;
 
-    edn = e->e_ndn;
-
-       Debug( LDAP_DEBUG_ARGS, "=> acl_get: edn %s\n", edn, 0, 0 );
-
-       /* check for a backend-specific acl that matches the entry */
-       for ( i = 1, a = be->be_acl; a != NULL; a = a->acl_next, i++ ) {
-               if (a->acl_dn_pat != NULL) {
-                       Debug( LDAP_DEBUG_TRACE, "=> dnpat: [%d] %s nsub: %d\n", 
-                               i, a->acl_dn_pat, (int) a->acl_dn_re.re_nsub);
-
-                       if (regexec(&a->acl_dn_re, edn, nmatch, matches, 0)) {
-                               continue;
-
-                       } else {
-                               Debug( LDAP_DEBUG_TRACE, "=> acl_get:[%d]  backend ACL match\n",
-                                       i, 0, 0);
-                       }
-               }
+       assert( e != NULL );
+       assert( count != NULL );
 
-               if ( a->acl_filter != NULL ) {
-                       if ( test_filter( NULL, NULL, NULL, e, a->acl_filter ) != 0 ) {
-                               continue;
-                       }
+       if( a == NULL ) {
+               if( be == NULL ) {
+                       a = global_acl;
+               } else {
+                       a = be->be_acl;
                }
 
-        Debug( LDAP_DEBUG_ARGS, "=> acl_get: [%d] check attr %s\n", i, attr, 0);
+               assert( a != NULL );
 
-               if ( attr == NULL || a->acl_attrs == NULL ||
-                       charray_inlist( a->acl_attrs, attr ) )
-               {
-                       Debug( LDAP_DEBUG_ACL, "<= acl_get: [%d] backend acl %s attr: %s\n",
-                               i, e->e_dn, attr );
-                       return( a );
-               }
-               matches[0].rm_so = matches[0].rm_eo = -1;
+       } else {
+               a = a->acl_next;
        }
 
-       /* check for a global acl that matches the entry */
-       for ( i = 1, a = global_acl; a != NULL; a = a->acl_next, i++ ) {
+       for ( ; a != NULL; a = a->acl_next ) {
+               (*count) ++;
+
                if (a->acl_dn_pat != NULL) {
-                       Debug( LDAP_DEBUG_TRACE, "=> dn pat: [%d] %s nsub: %d\n", 
-                               i, a->acl_dn_pat, (int) a->acl_dn_re.re_nsub);
+                       Debug( LDAP_DEBUG_ACL, "=> dnpat: [%d] %s nsub: %d\n", 
+                               *count, a->acl_dn_pat, (int) a->acl_dn_re.re_nsub );
 
-                       if (regexec(&a->acl_dn_re, edn, nmatch, matches, 0)) {
+                       if (regexec(&a->acl_dn_re, e->e_ndn, nmatch, matches, 0)) {
                                continue;
 
                        } else {
-                               Debug( LDAP_DEBUG_TRACE, "=> acl_get: [%d] global ACL match\n",
-                                       i, 0, 0);
+                               Debug( LDAP_DEBUG_ACL, "=> acl_get: ACL [%d] matched\n",
+                                       *count, 0, 0);
                        }
                }
 
@@ -185,25 +233,27 @@ acl_get_applicable(
                        }
                }
 
-               Debug( LDAP_DEBUG_ARGS, "=> acl_get: [%d] check attr\n", i, 0, 0);
+        Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] check attr %s\n",
+                       *count, attr, 0);
 
                if ( attr == NULL || a->acl_attrs == NULL ||
                        charray_inlist( a->acl_attrs, attr ) )
                {
-                       Debug( LDAP_DEBUG_ACL, "<= acl_get: [%d] global acl %s attr: %s\n",
-                               i, e->e_dn, attr );
-                       return( a );
+                       Debug( LDAP_DEBUG_ACL,
+                               "<= acl_get: [%d] acl %s attr: %s\n",
+                               *count, e->e_dn, attr );
+                       return a;
                }
-
                matches[0].rm_so = matches[0].rm_eo = -1;
        }
 
-       Debug( LDAP_DEBUG_ACL, "<= acl_get: no match\n", 0, 0, 0 );
+       Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 );
        return( NULL );
 }
 
+
 /*
- * acl_access_allowed - check whether the given acl allows dn the
+ * acl_mask - modifies mask based upon the given acl and the
  * requested access to entry e, attribute attr, value val.  if val
  * is null, access to the whole attribute is assumed (all values).
  *
@@ -211,54 +261,43 @@ acl_get_applicable(
  *             1       access allowed
  */
 
-int
-acl_access_allowed(
+static slap_control_t
+acl_mask(
     AccessControl      *a,
-    char               *attr,
+       slap_access_mask_t *mask,
     Backend            *be,
-    Connection         *conn,
+    Connection *conn,
+    Operation  *op,
     Entry              *e,
+    char               *attr,
     struct berval      *val,
-    Operation          *op,
-    int                        access,
-       char            *edn,
        regmatch_t      *matches
 )
 {
        int             i;
        Access  *b;
-       int             default_access;
+
+       assert( a != NULL );
+       assert( mask != NULL );
 
        Debug( LDAP_DEBUG_ACL,
-               "\n=> acl_access_allowed: %s access to entry \"%s\"\n",
-               access2str( access ), e->e_dn, 0 );
+               "=> acl_mask: access to entry \"%s\", attr \"%s\"\n requested\n",
+               e->e_dn, attr, 0 );
 
        Debug( LDAP_DEBUG_ACL,
-               "\n=> acl_access_allowed: %s access to value \"%s\" by \"%s\"\n",
-           access2str( access ),
+               "=> acl_mask: to value \"%s\" by \"%s\", (%s) \n",
                val ? val->bv_val : "any",
-               op->o_ndn ?  op->o_ndn : "" );
-
-       if ( be_isroot( be, op->o_ndn ) ) {
-               Debug( LDAP_DEBUG_ACL,
-                       "<= acl_access_allowed: granted to database root\n",
-                   0, 0, 0 );
-               return( 1 );
-       }
+               op->o_ndn ?  op->o_ndn : "",
+               accessmask2str( *mask ) );
 
-       default_access = be->be_dfltaccess ? be->be_dfltaccess : global_default_access;
+       for ( i = 1, b = a->acl_access; b != NULL; b = b->a_next, i++ ) {
+               slap_access_mask_t oldmask, modmask;
 
-       if ( a == NULL ) {
-               Debug( LDAP_DEBUG_ACL,
-                   "<= acl_access_allowed: %s by default (no matching to)\n",
-                   default_access >= access ? "granted" : "denied", 0, 0 );
-               return( default_access >= access );
-       }
+               ACL_INVALIDATE( modmask );
 
-       for ( i = 1, b = a->acl_access; b != NULL; b = b->a_next, i++ ) {
                /* AND <who> clauses */
                if ( b->a_dn_pat != NULL ) {
-                       Debug( LDAP_DEBUG_TRACE, "<= check a_dn_pat: %s\n",
+                       Debug( LDAP_DEBUG_ACL, "<= check a_dn_pat: %s\n",
                                b->a_dn_pat, 0, 0);
                        /*
                         * if access applies to the entry itself, and the
@@ -275,60 +314,60 @@ acl_access_allowed(
                                        continue;
                                }
                                
-                               if ( e->e_dn == NULL || strcmp( edn, op->o_ndn ) != 0 ) {
+                               if ( e->e_dn == NULL || strcmp( e->e_ndn, op->o_ndn ) != 0 ) {
                                        continue;
                                }
 
                        } else if ( strcmp( b->a_dn_pat, ".*" ) != 0 &&
-                               !regex_matches( b->a_dn_pat, op->o_ndn, edn, matches ) )
+                               !regex_matches( b->a_dn_pat, op->o_ndn, e->e_ndn, matches ) )
                        {
                                continue;
                        }
                }
 
                if ( b->a_sockurl_pat != NULL ) {
-                       Debug( LDAP_DEBUG_ARGS, "<= check a_sockurl_pat: %s\n",
+                       Debug( LDAP_DEBUG_ACL, "<= check a_sockurl_pat: %s\n",
                                b->a_sockurl_pat, 0, 0 );
 
                        if ( strcmp( b->a_sockurl_pat, ".*" ) != 0 &&
                                !regex_matches( b->a_sockurl_pat, conn->c_listener_url,
-                               edn, matches ) ) 
+                               e->e_ndn, matches ) ) 
                        {
                                continue;
                        }
                }
 
                if ( b->a_domain_pat != NULL ) {
-                       Debug( LDAP_DEBUG_ARGS, "<= check a_domain_pat: %s\n",
+                       Debug( LDAP_DEBUG_ACL, "<= check a_domain_pat: %s\n",
                                b->a_domain_pat, 0, 0 );
 
                        if ( strcmp( b->a_domain_pat, ".*" ) != 0 &&
                                !regex_matches( b->a_domain_pat, conn->c_peer_domain,
-                               edn, matches ) ) 
+                               e->e_ndn, matches ) ) 
                        {
                                continue;
                        }
                }
 
                if ( b->a_peername_pat != NULL ) {
-                       Debug( LDAP_DEBUG_ARGS, "<= check a_peername_path: %s\n",
+                       Debug( LDAP_DEBUG_ACL, "<= check a_peername_path: %s\n",
                                b->a_peername_pat, 0, 0 );
 
                        if ( strcmp( b->a_peername_pat, ".*" ) != 0 &&
                                !regex_matches( b->a_peername_pat, conn->c_peer_name,
-                               edn, matches ) )
+                               e->e_ndn, matches ) )
                        {
                                continue;
                        }
                }
 
                if ( b->a_sockname_pat != NULL ) {
-                       Debug( LDAP_DEBUG_ARGS, "<= check a_sockname_path: %s\n",
+                       Debug( LDAP_DEBUG_ACL, "<= check a_sockname_path: %s\n",
                                b->a_sockname_pat, 0, 0 );
 
                        if ( strcmp( b->a_sockname_pat, ".*" ) != 0 &&
                                !regex_matches( b->a_sockname_pat, conn->c_sock_name,
-                               edn, matches ) )
+                               e->e_ndn, matches ) )
                        {
                                continue;
                        }
@@ -338,7 +377,7 @@ acl_access_allowed(
                        Attribute       *at;
                        struct berval   bv;
 
-                       Debug( LDAP_DEBUG_ARGS, "<= check a_dn_at: %s\n",
+                       Debug( LDAP_DEBUG_ACL, "<= check a_dn_at: %s\n",
                                b->a_dn_at, 0, 0);
 
                        bv.bv_val = op->o_ndn;
@@ -348,14 +387,14 @@ acl_access_allowed(
                        if ( (at = attr_find( e->e_attrs, b->a_dn_at )) != NULL &&
                                value_find( at->a_vals, &bv, at->a_syntax, 3 ) == 0 )
                        {
-                               if ( ACL_IS_SELF(b->a_access) && 
+                               if ( b->a_dn_self && 
                                        (val == NULL || value_cmp( &bv, val, at->a_syntax, 2 )) )
                                {
                                        continue;
                                }
 
                        /* asker not listed in dnattr - check for self access */
-                       } else if ( ! ACL_IS_SELF(b->a_access) || val == NULL ||
+                       } else if ( ! b->a_dn_self || val == NULL ||
                                value_cmp( &bv, val, at->a_syntax, 2 ) != 0 )
                        {
                                continue;
@@ -370,7 +409,7 @@ acl_access_allowed(
                         * the values in the attribute group
                         */
                        /* see if asker is listed in dnattr */
-                       string_expand(buf, sizeof(buf), b->a_group_pat, edn, matches);
+                       string_expand(buf, sizeof(buf), b->a_group_pat, e->e_ndn, matches);
                        if ( dn_normalize(buf) == NULL ) {
                                /* did not expand to a valid dn */
                                continue;
@@ -384,12 +423,12 @@ acl_access_allowed(
                }
 
 #ifdef SLAPD_ACI_ENABLED
-               if ( b->a_aci_at != NULL ) {                            
+               if ( b->a_aci_at != NULL ) {
                        Attribute       *at;
 
                        /* this case works different from the others above.
                         * since aci's themselves give permissions, we need
-                        * to first check b->a_access, the ACL's access level.
+                        * to first check b->a_mask, the ACL's access level.
                         */
 
                        if( op->o_ndn == NULL || op->o_ndn[0] == '\0' ) {
@@ -403,7 +442,7 @@ acl_access_allowed(
                        /* first check if the right being requested is
                         * higher than allowed by the ACL clause.
                         */
-                       if ( ! ACL_GRANT( b->a_access, access ) ) {
+                       if ( ! ACL_GRANT( b->a_mask, access ) ) {
                                continue;
                        }
 
@@ -418,39 +457,71 @@ acl_access_allowed(
                         * rights given by the acis.
                         */
                        for ( i = 0; at->a_vals[i] != NULL; i++ ) {
-                               if ( aci_access_allowed( at->a_vals[i], attr, be, e, op, access, edn, matches ) ) {
+                               if ( aci_access_allowed( be, op,
+                                       e, attr, at->a_vals[i],
+                                       matches ) )
+                               {
                                        Debug( LDAP_DEBUG_ACL,
-                                               "<= acl_access_allowed: matched by clause #%d access granted\n",
+                                               "<= acl_mask: matched by clause #%d access granted\n",
                                                i, 0, 0 );
-                                       return(1);
+                                       break;
                                }
                        }
-                       continue;
-               }
+
+                       if( ACL_IS_INVALID( modmask ) ) { 
+                               continue;
+                       }
+
+               } else
 #endif
+               {
+                       modmask = b->a_mask;
+               }
+
 
                Debug( LDAP_DEBUG_ACL,
-                       "<= acl_access_allowed: matched by clause #%d access %s\n",
-                       i,
-                       ACL_GRANT(b->a_access, access) ? "granted" : "denied",
-                       0 );
+                       "<= acl_mask: matched clause #%d\n",
+                       i, 0, 0 );
 
-               return ACL_GRANT(b->a_access, access );
-       }
+               oldmask = *mask;
 
-       Debug( LDAP_DEBUG_ACL,
-               "<= acl_access_allowed: %s by default (no matching by)\n",
-           default_access >= access ? "granted" : "denied", 0, 0 );
+               if( ACL_IS_ADDITIVE(modmask) ) {
+                       ACL_PRIV_CLR( *mask, ACL_PRIV_LEVEL );
+                       ACL_PRIV_SET( *mask, modmask );
+               
+               } else if( ACL_IS_SUBTRACTIVE(modmask) ) {
+                       ACL_PRIV_CLR( *mask, ACL_PRIV_LEVEL );
+                       ACL_PRIV_CLR( *mask, modmask );
+
+               } else {
+                       ACL_PRIV_ASSIGN( *mask, modmask );
+               }
+
+               Debug( LDAP_DEBUG_ACL,
+                       "<= acl_mask: old (%s) mod (%s) new (%s)\n",
+                       accessmask2str(oldmask),
+                       accessmask2str(modmask),
+                       accessmask2str(*mask) );
+
+               if( b->a_type == ACL_CONTINUE ) {
+                       continue;
+
+               } else if ( b->a_type == ACL_BREAK ) {
+                       return ACL_BREAK;
+
+               } else {
+                       break;
+               }
+       }
 
-       return( default_access >= access );
+       return ACL_STOP;
 }
 
 /*
  * acl_check_modlist - check access control on the given entry to see if
  * it allows the given modifications by the user associated with op.
- * returns     LDAP_SUCCESS    mods allowed ok
- *             anything else   mods not allowed - return is an error
- *                             code indicating the problem
+ * returns     1       if mods allowed ok
+ *                     0       mods not allowed
  */
 
 int
@@ -463,8 +534,38 @@ acl_check_modlist(
 )
 {
        int             i;
-       AccessControl   *a;
-       char    *edn = e->e_ndn;
+
+       assert( be != NULL );
+
+       /* short circuit root database access */
+       if ( be_isroot( be, op->o_ndn ) ) {
+               Debug( LDAP_DEBUG_ACL,
+                       "<= acl_access_allowed: granted to database root\n",
+                   0, 0, 0 );
+               return 1;
+       }
+
+       /* use backend default access if no backend acls */
+       if( be != NULL && be->be_acl == NULL ) {
+               Debug( LDAP_DEBUG_ACL,
+                       "=> access_allowed: backend default %s access %s to \"%s\"\n",
+                       access2str( ACL_WRITE ),
+                       be->be_dfltaccess >= ACL_WRITE ? "granted" : "denied", op->o_dn );
+
+               return be->be_dfltaccess >= ACL_WRITE;
+
+#ifdef notdef
+       /* be is always non-NULL */
+       /* use global default access if no global acls */
+       } else if ( be == NULL && global_acl == NULL ) {
+               Debug( LDAP_DEBUG_ACL,
+                       "=> access_allowed: global default %s access %s to \"%s\"\n",
+                       access2str( ACL_WRITE ),
+                       global_default_access >= ACL_WRITE ? "granted" : "denied", op->o_dn );
+
+               return global_default_access >= ACL_WRITE;
+#endif
+       }
 
        for ( ; mlist != NULL; mlist = mlist->ml_next ) {
                regmatch_t       matches[MAXREMATCHES];
@@ -476,9 +577,6 @@ acl_check_modlist(
                        continue;
                }
 
-               a = acl_get_applicable( be, op, e, mlist->ml_type,
-                       MAXREMATCHES, matches );
-
                switch ( mlist->ml_op & ~LDAP_MOD_BVALUES ) {
                case LDAP_MOD_REPLACE:
                case LDAP_MOD_ADD:
@@ -486,35 +584,38 @@ acl_check_modlist(
                                break;
                        }
                        for ( i = 0; mlist->ml_bvalues[i] != NULL; i++ ) {
-                               if ( ! acl_access_allowed( a, mlist->ml_type, be, conn, e, mlist->ml_bvalues[i], 
-                                       op, ACL_WRITE, edn, matches) ) 
+                               if ( ! access_allowed( be, conn, op, e,
+                                       mlist->ml_type, mlist->ml_bvalues[i],
+                                       ACL_WRITE ) )
                                {
-                                       return( LDAP_INSUFFICIENT_ACCESS );
+                                       return( 0 );
                                }
                        }
                        break;
 
                case LDAP_MOD_DELETE:
                        if ( mlist->ml_bvalues == NULL ) {
-                               if ( ! acl_access_allowed( a, mlist->ml_type, be, conn, e,
-                                       NULL, op, ACL_WRITE, edn, matches) ) 
+                               if ( ! access_allowed( be, conn, op, e,
+                                       mlist->ml_type, NULL, 
+                                       ACL_WRITE ) )
                                {
-                                       return( LDAP_INSUFFICIENT_ACCESS );
+                                       return( 0 );
                                }
                                break;
                        }
                        for ( i = 0; mlist->ml_bvalues[i] != NULL; i++ ) {
-                               if ( ! acl_access_allowed( a, mlist->ml_type, be, conn, e, mlist->ml_bvalues[i], 
-                                       op, ACL_WRITE, edn, matches) ) 
+                               if ( ! access_allowed( be, conn, op, e,
+                                       mlist->ml_type, mlist->ml_bvalues[i],
+                                       ACL_WRITE ) )
                                {
-                                       return( LDAP_INSUFFICIENT_ACCESS );
+                                       return( 0 );
                                }
                        }
                        break;
                }
        }
 
-       return( LDAP_SUCCESS );
+       return( 1 );
 }
 
 #ifdef SLAPD_ACI_ENABLED
@@ -583,10 +684,14 @@ aci_get_part (struct berval *list, int ix, char sep, struct berval *bv)
 }
 
 static int
-aci_list_has_right (struct berval *list, int access, int action)
+aci_list_has_right(
+       struct berval *list,
+       slap_access_t access,
+       int action)
 {
        struct berval bv;
-       int i, right;
+       int i;
+       slap_access_t right;
 
        for (i = 0; aci_get_part(list, i, ',', &bv) >= 0; i++) {
                if (bv.bv_len <= 0)
@@ -680,7 +785,10 @@ aci_list_has_attr_right (struct berval *list, char *attr, int access, int action
 }
 
 static int
-aci_list_has_permission (struct berval *list, char *attr, int access)
+aci_list_has_permission(
+       struct berval *list,
+       char *attr,
+       slap_access_t access)
 {
     struct berval perm, actn;
     int i, action, specific, general;
@@ -720,7 +828,6 @@ aci_group_member (
     Backend            *be,
     Entry              *e,
     Operation          *op,
-       char            *edn,
        regmatch_t      *matches
 )
 {
@@ -747,7 +854,7 @@ aci_group_member (
 
        grpdn = (char *)ch_malloc(1024);
        if (grpoc != NULL && grpat != NULL && grpdn != NULL) {
-               string_expand(grpdn, 1024, subjdn, edn, matches);
+               string_expand(grpdn, 1024, subjdn, e->e_ndn, matches);
                if ( dn_normalize(grpdn) != NULL ) {
                        rc = (backend_group(be, e, grpdn, op->o_ndn, grpoc, grpat) == 0);
                }
@@ -761,15 +868,14 @@ aci_group_member (
        return(rc);
 }
 
-int
+static int
 aci_access_allowed (
     struct berval      *aci,
     char                       *attr,
     Backend                    *be,
     Entry                      *e,
     Operation          *op,
-    int                                access,
-       char                    *edn,
+    slap_access_t      access,
        regmatch_t              *matches
 )
 {
@@ -778,11 +884,11 @@ aci_access_allowed (
        int rc;
 
        Debug( LDAP_DEBUG_ACL,
-               "\n=> aci_access_allowed: %s access to entry \"%s\"\n",
+               "=> aci_access_allowed: %s access to entry \"%s\"\n",
                access2str( access ), e->e_dn, 0 );
 
        Debug( LDAP_DEBUG_ACL,
-               "\n=> aci_access_allowed: %s access to attribute \"%s\" by \"%s\"\n",
+               "=> aci_access_allowed: %s access to attribute \"%s\" by \"%s\"\n",
            access2str( access ),
                attr,
                op->o_ndn ? op->o_ndn : "" );
@@ -833,15 +939,15 @@ aci_access_allowed (
        }
 
        if (aci_strbvcmp( "self", &bv ) == 0) {
-               return(strcasecmp(op->o_ndn, edn) == 0);
+               return(strcasecmp(op->o_ndn, e->e_ndn) == 0);
        }
 
        if (aci_strbvcmp( "group", &bv ) == 0) {
-               return(aci_group_member(&sdn, "groupOfNames", "member", be, e, op, edn, matches));
+               return(aci_group_member(&sdn, "groupOfNames", "member", be, e, op, matches));
        }
 
        if (aci_strbvcmp( "role", &bv ) == 0) {
-               return(aci_group_member(&sdn, "organizationalRole", "roleOccupant", be, e, op, edn, matches));
+               return(aci_group_member(&sdn, "organizationalRole", "roleOccupant", be, e, op, matches));
        }
 
        return(0);
index a1345069089da7475d18e452ab64983a2f2d8650..5b9363714c8e8258345444d1679c35832b0bc901 100644 (file)
 #include "slap.h"
 
 static void            split(char *line, int splitchar, char **left, char **right);
-static void            acl_append(AccessControl **l, AccessControl *a);
 static void            access_append(Access **l, Access *a);
 static void            acl_usage(void) LDAP_GCCATTR((noreturn));
+
 #ifdef LDAP_DEBUG
-static void            print_acl(AccessControl *a);
+static void            print_acl(Backend *be, AccessControl *a);
 static void            print_access(Access *b);
 #endif
 
@@ -179,12 +179,15 @@ parse_acl(
                                    fname, lineno );
                                acl_usage();
                        }
+
                        /*
                         * by clause consists of <who> and <access>
                         */
 
                        b = (Access *) ch_calloc( 1, sizeof(Access) );
 
+                       ACL_INVALIDATE( b->a_mask );
+
                        if ( ++i == argc ) {
                                fprintf( stderr,
                            "%s: line %d: premature eol: expecting <who>\n",
@@ -344,16 +347,92 @@ parse_acl(
                                }
 #endif
 
-                               /* get <access> */
-                               if ( ACL_IS_INVALID(ACL_SET(b->a_access, str2access( left ))) ) {
-                                       fprintf( stderr,
-                                       "%s: line %d: expecting <access> got \"%s\"\n",
-                                               fname, lineno, left );
-                                       acl_usage();
+                               if( right != NULL ) {
+                                       /* unsplit */
+                                       right[-1] = '=';
                                }
-                               access_append( &a->acl_access, b );
                                break;
                        }
+
+                       if( i == argc || ( strcasecmp( left, "stop" ) == 0 )) { 
+                               /* out of arguments or plain stop */
+
+                               ACL_PRIV_ASSIGN(b->a_mask, ACL_NONE);
+                               b->a_type = ACL_STOP;
+
+                               access_append( &a->acl_access, b );
+                               continue;
+                       }
+
+                       if( strcasecmp( left, "continue" ) == 0 ) {
+                               /* plain continue */
+
+                               ACL_PRIV_ASSIGN(b->a_mask, ACL_NONE);
+                               b->a_type = ACL_CONTINUE;
+
+                               access_append( &a->acl_access, b );
+                               continue;
+                       }
+
+                       if( strcasecmp( left, "break" ) == 0 ) {
+                               /* plain continue */
+
+                               ACL_PRIV_ASSIGN(b->a_mask, ACL_NONE);
+                               b->a_type = ACL_BREAK;
+
+                               access_append( &a->acl_access, b );
+                               continue;
+                       }
+
+                       if ( strcasecmp( left, "by" ) == 0 ) {
+                               /* we've gone too far */
+                               --i;
+                               ACL_PRIV_ASSIGN(b->a_mask, ACL_NONE);
+                               b->a_type = ACL_STOP;
+
+                               access_append( &a->acl_access, b );
+                               continue;
+                       }
+
+                       /* get <access> */
+                       if( strncasecmp( left, "self", 4 ) == 0 ) {
+                               b->a_dn_self = 1;
+                               ACL_PRIV_ASSIGN( b->a_mask, str2accessmask( &left[4] ) );
+
+                       } else {
+                               ACL_PRIV_ASSIGN( b->a_mask, str2accessmask( left ) );
+                       }
+
+                       if( ACL_IS_INVALID( b->a_mask ) ) {
+                               fprintf( stderr,
+                                       "%s: line %d: expecting <access> got \"%s\"\n",
+                                       fname, lineno, left );
+                               acl_usage();
+                       }
+
+                       b->a_type = ACL_STOP;
+
+                       if( ++i == argc ) {
+                               /* out of arguments or plain stop */
+                               access_append( &a->acl_access, b );
+                               continue;
+                       }
+
+                       if( strcasecmp( argv[i], "continue" ) == 0 ) {
+                               /* plain continue */
+                               b->a_type = ACL_CONTINUE;
+
+                       } else if( strcasecmp( argv[i], "break" ) == 0 ) {
+                               /* plain continue */
+                               b->a_type = ACL_BREAK;
+
+                       } else if ( strcasecmp( argv[i], "stop" ) != 0 ) {
+                               /* gone to far */
+                               i--;
+                       }
+
+                       access_append( &a->acl_access, b );
+
                } else {
                        fprintf( stderr,
                    "%s: line %d: expecting \"to\" or \"by\" got \"%s\"\n",
@@ -372,7 +451,7 @@ parse_acl(
 
 #ifdef LDAP_DEBUG
                 if (ldap_debug & LDAP_DEBUG_ACL)
-                    print_acl(a);
+                    print_acl(be, a);
 #endif
        
                if ( a->acl_access == NULL ) {
@@ -390,72 +469,165 @@ parse_acl(
 }
 
 char *
-access2str( int access )
+accessmask2str( slap_access_mask_t mask )
 {
-       static char     buf[12];
+       static char     buf[sizeof("unknown (+wrsca0)")]; 
+       int none=1;
 
-       if ( ACL_IS_SELF( access ) ) {
-               strcpy( buf, "self" );
-       } else {
-               buf[0] = '\0';
+       if ( ACL_IS_INVALID( mask ) ) {
+               return "invalid";
        }
 
-       if ( ACL_IS_NONE(access) ) {
-               strcat( buf, "none" );
-       } else if ( ACL_IS_AUTH(access) ) {
-               strcat( buf, "auth" );
-       } else if ( ACL_IS_COMPARE(access) ) {
-               strcat( buf, "compare" );
-       } else if ( ACL_IS_SEARCH(access) ) {
-               strcat( buf, "search" );
-       } else if ( ACL_IS_READ(access) ) {
-               strcat( buf, "read" );
-       } else if ( ACL_IS_WRITE(access) ) {
-               strcat( buf, "write" );
+       buf[0] = '\0';
+
+       if ( ACL_IS_LEVEL( mask ) ) {
+               if ( ACL_LVL_IS_NONE(mask) ) {
+                       strcat( buf, "none" );
+
+               } else if ( ACL_LVL_IS_AUTH(mask) ) {
+                       strcat( buf, "auth" );
+
+               } else if ( ACL_LVL_IS_COMPARE(mask) ) {
+                       strcat( buf, "compare" );
+
+               } else if ( ACL_LVL_IS_SEARCH(mask) ) {
+                       strcat( buf, "search" );
+
+               } else if ( ACL_LVL_IS_READ(mask) ) {
+                       strcat( buf, "read" );
+
+               } else if ( ACL_LVL_IS_WRITE(mask) ) {
+                       strcat( buf, "write" );
+               } else {
+                       strcat( buf, "unknown" );
+               }
+               
+               strcat(buf, " (");
+       }
+
+       if( ACL_IS_ADDITIVE( mask ) ) {
+               strcat( buf, "+" );
+
+       } else if( ACL_IS_SUBTRACTIVE( mask ) ) {
+               strcat( buf, "-" );
 
        } else {
-               strcat( buf, "unknown" );
+               strcat( buf, "=" );
        }
 
-       return( buf );
+       if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WRITE) ) {
+               none = 0;
+               strcat( buf, "w" );
+       } 
+
+       if ( ACL_PRIV_ISSET(mask, ACL_PRIV_READ) ) {
+               none = 0;
+               strcat( buf, "r" );
+       } 
+
+       if ( ACL_PRIV_ISSET(mask, ACL_PRIV_SEARCH) ) {
+               none = 0;
+               strcat( buf, "s" );
+       } 
+
+       if ( ACL_PRIV_ISSET(mask, ACL_PRIV_COMPARE) ) {
+               none = 0;
+               strcat( buf, "c" );
+       } 
+
+       if ( ACL_PRIV_ISSET(mask, ACL_PRIV_AUTH) ) {
+               none = 0;
+               strcat( buf, "x" );
+       } 
+
+       if ( none && ACL_PRIV_ISSET(mask, ACL_PRIV_NONE) ) {
+               strcat( buf, "0" );
+       } 
+
+       if ( ACL_IS_LEVEL( mask ) ) {
+               strcat(buf, ")");
+       } 
+       return buf;
 }
 
-int
-str2access( char *str )
+slap_access_mask_t
+str2accessmask( const char *str )
 {
-       int     access;
+       slap_access_mask_t      mask;
+
+       if( !isalpha(str[0]) ) {
+               int i;
+
+               if ( str[0] == '=' ) {
+                       ACL_INIT(mask);
+
+               } else if( str[0] == '+' ) {
+                       ACL_PRIV_ASSIGN(mask, ACL_PRIV_ADDITIVE);
+
+               } else if( str[0] == '-' ) {
+                       ACL_PRIV_ASSIGN(mask, ACL_PRIV_SUBSTRACTIVE);
 
-       ACL_CLR(access);
+               } else {
+                       ACL_INVALIDATE(mask);
+                       return mask;
+               }
+
+               for( i=1; str[i] != '\0'; i++ ) {
+                       if( TOLOWER(str[i]) == 'w' ) {
+                               ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
+
+                       } else if( TOLOWER(str[0]) == 'r' ) {
+                               ACL_PRIV_SET(mask, ACL_PRIV_READ);
+
+                       } else if( TOLOWER(str[0]) == 's' ) {
+                               ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
+
+                       } else if( TOLOWER(str[0]) == 'c' ) {
+                               ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
+
+                       } else if( TOLOWER(str[0]) == 'x' ) {
+                               ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
+
+                       } else {
+                               ACL_INVALIDATE(mask);
+                               return mask;
+                       }
+               }
 
-       if ( strncasecmp( str, "self", 4 ) == 0 ) {
-               ACL_SET_SELF(access);
-               str += 4;
+               return mask;
        }
 
        if ( strcasecmp( str, "none" ) == 0 ) {
-               ACL_SET_NONE(access);
+               ACL_LVL_ASSIGN_NONE(mask);
+
        } else if ( strcasecmp( str, "auth" ) == 0 ) {
-               ACL_SET_AUTH(access);
+               ACL_LVL_ASSIGN_AUTH(mask);
+
        } else if ( strcasecmp( str, "compare" ) == 0 ) {
-               ACL_SET_COMPARE(access);
+               ACL_LVL_ASSIGN_COMPARE(mask);
+
        } else if ( strcasecmp( str, "search" ) == 0 ) {
-               ACL_SET_SEARCH(access);
+               ACL_LVL_ASSIGN_SEARCH(mask);
+
        } else if ( strcasecmp( str, "read" ) == 0 ) {
-               ACL_SET_READ(access);
+               ACL_LVL_ASSIGN_READ(mask);
+
        } else if ( strcasecmp( str, "write" ) == 0 ) {
-               ACL_SET_WRITE(access);
+               ACL_LVL_ASSIGN_WRITE(mask);
+
        } else {
-               ACL_SET_INVALID(access);
+               ACL_INVALIDATE( mask );
        }
 
-       return( access );
+       return mask;
 }
 
 static void
 acl_usage( void )
 {
        fprintf( stderr, "\n"
-               "<access clause> ::= access to <what> [ by <who> <access> ]+ \n"
+               "<access clause> ::= access to <what> "
+                               "[ by <who> <access> <control> ]+ \n"
                "<what> ::= * | [dn=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n"
                "<attrlist> ::= <attr> | <attr> , <attrlist>\n"
                "<attr> ::= <attrname> | entry | children\n"
@@ -467,7 +639,10 @@ acl_usage( void )
 #ifdef SLAPD_ACI_ENABLED
                        "\t[aci=<attrname>]\n"
 #endif
-               "<access> ::= [self]{none|auth|compare|search|read|write}\n"
+               "<access> ::= [self]{<level>|<priv>}\n"
+               "<level> ::= none | auth | compare | search | read | write\n"
+               "<priv> ::= {=|+|-}{w|r|s|c|x}+\n"
+               "<control> ::= [ stop | continue | break ]\n"
                );
        exit( EXIT_FAILURE );
 }
@@ -495,7 +670,7 @@ access_append( Access **l, Access *a )
        *l = a;
 }
 
-static void
+void
 acl_append( AccessControl **l, AccessControl *a )
 {
        for ( ; *l != NULL; l = &(*l)->acl_next )
@@ -542,6 +717,7 @@ print_access( Access *b )
        if ( b->a_peername_pat != NULL ) {
                fprintf( stderr, " peername=%s", b->a_peername_pat );
        }
+
        if ( b->a_sockname_pat != NULL ) {
                fprintf( stderr, " sockname=%s", b->a_sockname_pat );
        }
@@ -560,31 +736,91 @@ print_access( Access *b )
        }
 #endif
 
+       fprintf( stderr, " %s%s",
+               b->a_dn_self ? "self" : "",
+               accessmask2str( b->a_mask ) );
+
        fprintf( stderr, "\n" );
 }
 
+char *
+access2str( slap_access_t access )
+{
+       if ( access == ACL_NONE ) {
+               return "none";
+
+       } else if ( access == ACL_AUTH ) {
+               return "auth";
+
+       } else if ( access == ACL_COMPARE ) {
+               return "compare";
+
+       } else if ( access == ACL_SEARCH ) {
+               return "search";
+
+       } else if ( access == ACL_READ ) {
+               return "read";
+
+       } else if ( access == ACL_WRITE ) {
+               return "write";
+       }
+
+       return "unknown";
+}
+
+slap_access_t
+str2access( const char *str )
+{
+       if ( strcasecmp( str, "none" ) == 0 ) {
+               return ACL_NONE;
+
+       } else if ( strcasecmp( str, "auth" ) == 0 ) {
+               return ACL_AUTH;
+
+       } else if ( strcasecmp( str, "compare" ) == 0 ) {
+               return ACL_COMPARE;
+
+       } else if ( strcasecmp( str, "search" ) == 0 ) {
+               return ACL_SEARCH;
+
+       } else if ( strcasecmp( str, "read" ) == 0 ) {
+               return ACL_READ;
+
+       } else if ( strcasecmp( str, "write" ) == 0 ) {
+               return ACL_WRITE;
+       }
+
+       return( ACL_INVALID_ACCESS );
+}
+
+
 static void
-print_acl( AccessControl *a )
+print_acl( Backend *be, AccessControl *a )
 {
-       int             i;
+       int             to = 0;
        Access  *b;
 
-       if ( a == NULL ) {
-               fprintf( stderr, "NULL\n" );
+       fprintf( stderr, "%s ACL: access to",
+               be == NULL ? "Global" : "Backend" );
+
+       if ( a->acl_dn_pat != NULL ) {
+               to++;
+               fprintf( stderr, " dn=%s\n",
+                       a->acl_dn_pat );
        }
-       fprintf( stderr, "ACL: access to" );
+
        if ( a->acl_filter != NULL ) {
-               fprintf(  stderr," filter=" );
+               to++;
+               fprintf( stderr, " filter=" );
                filter_print( a->acl_filter );
+               fprintf( stderr, "\n" );
        }
-       if ( a->acl_dn_pat != NULL ) {
-               fprintf( stderr, " dn=" );
-               fprintf( stderr, a->acl_dn_pat );
-       }
+
        if ( a->acl_attrs != NULL ) {
-               int     first = 1;
+               int     i, first = 1;
+               to++;
 
-               fprintf( stderr, "\n attrs=" );
+               fprintf( stderr, " attrs=" );
                for ( i = 0; a->acl_attrs[i] != NULL; i++ ) {
                        if ( ! first ) {
                                fprintf( stderr, "," );
@@ -592,11 +828,17 @@ print_acl( AccessControl *a )
                        fprintf( stderr, a->acl_attrs[i] );
                        first = 0;
                }
+               fprintf(  stderr, "\n" );
        }
-       fprintf( stderr, "\n" );
+
+       if( !to ) {
+               fprintf( stderr, " *\n" );
+       }
+
        for ( b = a->acl_access; b != NULL; b = b->a_next ) {
                print_access( b );
        }
+
        fprintf( stderr, "\n" );
 }
 
index de632c8df139cf4ef98d543b273a8d91aa2e38d7..badab589eb4cc993bd6c5944277ca8607cb8d2f4 100644 (file)
@@ -28,8 +28,8 @@ bdb2i_back_modify_internal(
 
        Debug(LDAP_DEBUG_ARGS, "bdb2i_back_modify:\n", 0, 0, 0);
 
-       if ( (err = acl_check_modlist( be, conn, op, e, modlist )) != LDAP_SUCCESS ) {
-               send_ldap_result( conn, op, err,
+       if ( !acl_check_modlist( be, conn, op, e, modlist )) {
+               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
                        NULL, NULL, NULL, NULL );
                goto error_return;
        }
index af69d50bc67bec6b92cc63b77571685b3de327ca..fa55df90bef373b261769fdb18fdaab54d00cc03 100644 (file)
@@ -38,10 +38,8 @@ int ldbm_modify_internal(
        Attribute       *a;
        Attribute       *save_attrs;
 
-       if ( (err = acl_check_modlist( be, conn, op, e, modlist ))
-            != LDAP_SUCCESS )
-       {
-               send_ldap_result( conn, op, err,
+       if ( !acl_check_modlist( be, conn, op, e, modlist )) {
+               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
                        NULL, NULL, NULL, NULL );
                return -1;
        }
index ad8b82736077cbdbb279c9566ac524ee014fd4cd..7e83933b21f2f0492b086fd3074ae9081951f8d4 100644 (file)
@@ -222,6 +222,9 @@ int backend_startup(Backend *be)
 
        /* open each backend database */
        for( i = 0; i < nBackendDB; i++ ) {
+               /* append global access controls */
+               acl_append( &backendDB[i].be_acl, global_acl );
+
                if ( backendDB[i].bd_info->bi_db_open ) {
                        rc = backendDB[i].bd_info->bi_db_open(
                                &backendDB[i] );
@@ -376,6 +379,7 @@ backend_db_init(
        be->bd_info = bi;
        be->be_sizelimit = defsize;
        be->be_timelimit = deftime;
+       be->be_dfltaccess = global_default_access;
 
        /* assign a default depth limit for alias deref */
        be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; 
index abb5dab945aa6cfa98524f887be74dd8a06005a2..cee2fe9e3d7a4f9796d1705a33ef272053a63c41 100644 (file)
@@ -27,7 +27,7 @@
 int            defsize = SLAPD_DEFAULT_SIZELIMIT;
 int            deftime = SLAPD_DEFAULT_TIMELIMIT;
 AccessControl  *global_acl = NULL;
-int            global_default_access = ACL_AUTH;
+slap_access_t          global_default_access = ACL_READ;
 int            global_readonly = 0;
 char           *replogfile;
 int            global_lastmod = ON;
@@ -478,31 +478,29 @@ read_config( const char *fname )
 
                /* specify default access control info */
                } else if ( strcasecmp( cargv[0], "defaultaccess" ) == 0 ) {
+                       slap_access_t access;
+
                        if ( cargc < 2 ) {
                                Debug( LDAP_DEBUG_ANY,
            "%s: line %d: missing limit in \"defaultaccess <access>\" line\n",
                                    fname, lineno, 0 );
                                return( 1 );
                        }
+
+                       access = str2access( cargv[1] );
+
+                       if ( access == ACL_INVALID_ACCESS ) {
+                               Debug( LDAP_DEBUG_ANY,
+                                       "%s: line %d: bad access level \"%s\", "
+                                       "expecting none|auth|compare|search|read|write\n",
+                                   fname, lineno, cargv[1] );
+                               return( 1 );
+                       }
+
                        if ( be == NULL ) {
-                               if ( ACL_IS_INVALID(ACL_SET(global_default_access,
-                                               str2access(cargv[1]))) )
-                               {
-                                       Debug( LDAP_DEBUG_ANY,
-"%s: line %d: bad access \"%s\" expecting [self]{none|auth|compare|search|read|write}\n",
-                                           fname, lineno, cargv[1] );
-                                       return( 1 );
-                               }
+                               global_default_access = access;
                        } else {
-                               if ( ACL_IS_INVALID(ACL_SET(be->be_dfltaccess,
-                                               str2access(cargv[1]))) )
-                               {
-                                       Debug( LDAP_DEBUG_ANY,
-                                               "%s: line %d: bad access \"%s\", "
-                                               "expecting [self]{none|auth|compare|search|read|write}\n",
-                                           fname, lineno, cargv[1] );
-                                       return( 1 );
-                               }
+                               be->be_dfltaccess = access;
                        }
 
                /* debug level to log things to syslog */
index 139a37eb403d1333996c691e8bfe5dd7e07f5db4..f676bc0e16f3466f62ab46ca9e9077c34ae3006d 100644 (file)
@@ -16,16 +16,7 @@ LDAP_BEGIN_DECL
 
 int access_allowed LDAP_P(( Backend *be, Connection *conn,
        Operation *op, Entry *e,
-       char *attr, struct berval *val, int access ));
-
-AccessControl * acl_get_applicable LDAP_P(( Backend *be,
-       Operation *op, Entry *e,
-       char *attr, int nmatches, regmatch_t *matches ));
-
-int acl_access_allowed LDAP_P((
-       AccessControl *a, char *attr, Backend *be, Connection *conn, Entry *e,
-       struct berval *val, Operation *op, int  access, char *edn,
-       regmatch_t *matches ));
+       char *attr, struct berval *val, slap_access_t access ));
 
 int acl_check_modlist LDAP_P(( Backend *be,
        Connection *conn,
@@ -33,6 +24,8 @@ int acl_check_modlist LDAP_P(( Backend *be,
        Entry *e,
        LDAPModList *ml ));
 
+void acl_append( AccessControl **l, AccessControl *a );
+
 /*
  * aclparse.c
  */
@@ -41,8 +34,12 @@ void parse_acl LDAP_P(( Backend *be,
        const char *fname,
        int lineno,
        int argc, char **argv ));
-char * access2str LDAP_P(( int access ));
-int str2access LDAP_P(( char *str ));
+
+char * access2str LDAP_P(( slap_access_t access ));
+slap_access_t str2access LDAP_P(( const char *str ));
+
+char * accessmask2str LDAP_P(( slap_access_mask_t mask ));
+slap_access_mask_t str2accessmask LDAP_P(( const char *str ));
 
 /*
  * attr.c
@@ -432,7 +429,7 @@ extern int          active_threads;
 extern int             defsize;
 extern int             deftime;
 extern int             g_argc;
-extern int             global_default_access;
+extern slap_access_t           global_default_access;
 extern int             global_readonly;
 extern int             global_lastmod;
 extern int             global_idletimeout;
index 9e316669bc0f565a13d59e2a9b9a38f30b3750af..3f28d4b6545f0b68f5aab87fdf645ef6e8d550a5 100644 (file)
@@ -572,12 +572,11 @@ send_search_entry(
                        }
                }
 
-               acl = acl_get_applicable( be, op, e, a->a_type,
-                       MAXREMATCHES, matches );
-
-               if ( ! acl_access_allowed( acl, a->a_type, be, conn, e,
-                       NULL, op, ACL_READ, edn, matches ) ) 
+               if ( ! access_allowed( be, conn, op, e,
+                       a->a_type, NULL, ACL_READ ) )
                {
+                       Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
+                           a->a_type, 0, 0 );
                        continue;
                }
 
@@ -591,10 +590,12 @@ send_search_entry(
 
                if ( ! attrsonly ) {
                        for ( i = 0; a->a_vals[i] != NULL; i++ ) {
-                               if ( a->a_syntax & SYNTAX_DN && 
-                                       ! acl_access_allowed( acl, a->a_type, be, conn, e, a->a_vals[i], op,
-                                               ACL_READ, edn, matches) )
+                               if ( ! access_allowed( be, conn, op, e,
+                                       a->a_type, a->a_vals[i], ACL_READ ) )
                                {
+                                       Debug( LDAP_DEBUG_ACL,
+                                               "acl: access to attribute %s, value %d not allowed\n",
+                                       a->a_type, i, 0 );
                                        continue;
                                }
 
@@ -647,12 +648,11 @@ send_search_entry(
                        }
                }
 
-               acl = acl_get_applicable( be, op, e, a->a_type,
-                       MAXREMATCHES, matches );
-
-               if ( ! acl_access_allowed( acl, a->a_type, be, conn, e,
-                       NULL, op, ACL_READ, edn, matches ) ) 
+               if ( ! access_allowed( be, conn, op, e,
+                       a->a_type, NULL, ACL_READ ) )
                {
+                       Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
+                           a->a_type, 0, 0 );
                        continue;
                }
 
@@ -666,13 +666,16 @@ send_search_entry(
 
                if ( ! attrsonly ) {
                        for ( i = 0; a->a_vals[i] != NULL; i++ ) {
-                               if ( a->a_syntax & SYNTAX_DN && 
-                                       ! acl_access_allowed( acl, a->a_type, be, conn, e, a->a_vals[i], op,
-                                               ACL_READ, edn, matches) )
+                               if ( ! access_allowed( be, conn, op, e,
+                                       a->a_type, a->a_vals[i], ACL_READ ) )
                                {
+                                       Debug( LDAP_DEBUG_ACL,
+                                               "acl: access to attribute %s, value %d not allowed\n",
+                                       a->a_type, i, 0 );
                                        continue;
                                }
 
+
                                if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
                                        Debug( LDAP_DEBUG_ANY,
                                            "ber_printf failed\n", 0, 0, 0 );
index 304a5090d78182c9b57f9faf9852e97cf288b1b2..1d0339a214df3c19d4c82b48a75f1dcd990a25d5 100644 (file)
@@ -226,49 +226,91 @@ typedef struct slap_entry {
  * represents an access control list
  */
 
+typedef enum slap_access_e {
+       ACL_INVALID_ACCESS = -1,
+       ACL_NONE = 0,
+       ACL_AUTH,
+       ACL_COMPARE,
+       ACL_SEARCH,
+       ACL_READ,
+       ACL_WRITE
+} slap_access_t;
+
+typedef enum slap_control_e {
+       ACL_INVALID_CONTROL     = 0,
+       ACL_STOP,
+       ACL_CONTINUE,
+       ACL_BREAK
+} slap_control_t;
+
+typedef unsigned long slap_access_mask_t;
+
 /* the "by" part */
 typedef struct slap_access {
+       slap_control_t a_type;
+
+#define ACL_ACCESS2PRIV(access)        (0x01U << (access))
+
+#define ACL_PRIV_NONE                  ACL_ACCESS2PRIV( ACL_NONE )
+#define ACL_PRIV_AUTH                  ACL_ACCESS2PRIV( ACL_AUTH )
+#define ACL_PRIV_COMPARE               ACL_ACCESS2PRIV( ACL_COMPARE )
+#define ACL_PRIV_SEARCH                        ACL_ACCESS2PRIV( ACL_SEARCH )
+#define ACL_PRIV_READ                  ACL_ACCESS2PRIV( ACL_READ )
+#define ACL_PRIV_WRITE                 ACL_ACCESS2PRIV( ACL_WRITE )
+
+#define ACL_PRIV_MASK                  0x00ffUL
+
+/* priv flags */
+#define ACL_PRIV_LEVEL                 0x1000UL
+#define ACL_PRIV_ADDITIVE              0x2000UL
+#define ACL_PRIV_SUBSTRACTIVE  0x4000UL
+
+/* invalid privs */
+#define ACL_PRIV_INVALID               0x0UL
+
+#define ACL_PRIV_ISSET(m,p)            (((m) & (p)) == (p))
+#define ACL_PRIV_ASSIGN(m,p)   do { (m)  =  (p); } while(0)
+#define ACL_PRIV_SET(m,p)              do { (m) |=  (p); } while(0)
+#define ACL_PRIV_CLR(m,p)              do { (m) &= ~(p); } while(0)
+
+#define ACL_INIT(m)                            ACL_PRIV_ASSIGN(m, ACL_PRIV_NONE)
+#define ACL_INVALIDATE(m)              ACL_PRIV_ASSIGN(m, ACL_PRIV_INVALID)
+
+#define ACL_GRANT(m,a)                 ACL_PRIV_ISSET((m),ACL_ACCESS2PRIV(a))
+
+#define ACL_IS_INVALID(m)              ((m) == ACL_PRIV_INVALID)
+
+#define ACL_IS_LEVEL(m)                        ACL_PRIV_ISSET((m),ACL_PRIV_LEVEL)
+#define ACL_IS_ADDITIVE(m)             ACL_PRIV_ISSET((m),ACL_PRIV_ADDITIVE)
+#define ACL_IS_SUBTRACTIVE(m)  ACL_PRIV_ISSET((m),ACL_PRIV_SUBSTRACTIVE)
+
+#define ACL_LVL_NONE                   (ACL_PRIV_NONE|ACL_PRIV_LEVEL)
+#define ACL_LVL_AUTH                   (ACL_PRIV_AUTH|ACL_LVL_NONE)
+#define ACL_LVL_COMPARE                        (ACL_PRIV_COMPARE|ACL_LVL_AUTH)
+#define ACL_LVL_SEARCH                 (ACL_PRIV_SEARCH|ACL_LVL_COMPARE)
+#define ACL_LVL_READ                   (ACL_PRIV_READ|ACL_LVL_SEARCH)
+#define ACL_LVL_WRITE                  (ACL_PRIV_WRITE|ACL_LVL_READ)
+
+#define ACL_LVL(m,l)                   (((m)&ACL_PRIV_MASK) == ((l)&ACL_PRIV_MASK))
+#define ACL_LVL_IS_NONE(m)             ACL_LVL((m),ACL_LVL_NONE)
+#define ACL_LVL_IS_AUTH(m)             ACL_LVL((m),ACL_LVL_AUTH)
+#define ACL_LVL_IS_COMPARE(m)  ACL_LVL((m),ACL_LVL_COMPARE)
+#define ACL_LVL_IS_SEARCH(m)   ACL_LVL((m),ACL_LVL_SEARCH)
+#define ACL_LVL_IS_READ(m)             ACL_LVL((m),ACL_LVL_READ)
+#define ACL_LVL_IS_WRITE(m)            ACL_LVL((m),ACL_LVL_WRITE)
+
+#define ACL_LVL_ASSIGN_NONE(m)         ACL_PRIV_ASSIGN((m),ACL_LVL_NONE)
+#define ACL_LVL_ASSIGN_AUTH(m)         ACL_PRIV_ASSIGN((m),ACL_LVL_AUTH)
+#define ACL_LVL_ASSIGN_COMPARE(m)      ACL_PRIV_ASSIGN((m),ACL_LVL_COMPARE)
+#define ACL_LVL_ASSIGN_SEARCH(m)       ACL_PRIV_ASSIGN((m),ACL_LVL_SEARCH)
+#define ACL_LVL_ASSIGN_READ(m)         ACL_PRIV_ASSIGN((m),ACL_LVL_READ)
+#define ACL_LVL_ASSIGN_WRITE(m)                ACL_PRIV_ASSIGN((m),ACL_LVL_WRITE)
 
-#define ACL_NONE               0x0001
-#define ACL_AUTH               0x0004
-#define ACL_COMPARE            0x0008
-#define ACL_SEARCH             0x0010
-#define ACL_READ               0x0020
-#define ACL_WRITE              0x0040
-#define ACL_PRIV_MASK  0x00ff
-
-#define ACL_SELF               0x4000
-#define ACL_INVALID            (-1)
-
-#define ACL_IS(a,lvl)  (((a) & (lvl)) == (lvl))
-
-#define ACL_IS_NONE(a)         ACL_IS((a),ACL_SELF)
-#define ACL_IS_AUTH(a)         ACL_IS((a),ACL_AUTH)
-#define ACL_IS_COMPARE(a)      ACL_IS((a),ACL_COMPARE)
-#define ACL_IS_SEARCH(a)       ACL_IS((a),ACL_SEARCH)
-#define ACL_IS_READ(a)         ACL_IS((a),ACL_READ)
-#define ACL_IS_WRITE(a)                ACL_IS((a),ACL_WRITE)
-#define ACL_IS_SELF(a)         ACL_IS((a),ACL_SELF)
-#define ACL_IS_INVALID(a)      ((a) == ACL_INVALID)
-
-#define ACL_CLR(a)                     ((a) = 0)
-#define ACL_SET(a,lvl)         ((a) |= (lvl))
-#define ACL_SET_NONE(a)                ACL_SET((a),ACL_SELF)
-#define ACL_SET_AUTH(a)                ACL_SET((a),ACL_AUTH)
-#define ACL_SET_COMPARE(a)     ACL_SET((a),ACL_COMPARE)
-#define ACL_SET_SEARCH(a)      ACL_SET((a),ACL_SEARCH)
-#define ACL_SET_READ(a)                ACL_SET((a),ACL_READ)
-#define ACL_SET_WRITE(a)       ACL_SET((a),ACL_WRITE)
-#define ACL_SET_SELF(a)                ACL_SET((a),ACL_SELF)
-#define ACL_SET_INVALID(a)     ((a) = ACL_INVALID)
-
-#define        ACL_PRIV(a)                     ((a) & ACL_PRIV_MASK)
-#define ACL_GRANT(a,lvl)       (ACL_PRIV(a) >= (lvl))
-
-       int                     a_access;
+       slap_access_mask_t      a_mask;
 
        char            *a_dn_pat;
        char            *a_dn_at;
+       int                     a_dn_self;
 
        char            *a_peername_pat;
        char            *a_sockname_pat;
@@ -469,7 +511,7 @@ struct slap_backend_db {
        int     be_sizelimit;   /* size limit for this backend             */
        int     be_timelimit;   /* time limit for this backend             */
        AccessControl *be_acl;  /* access control list for this backend    */
-       int     be_dfltaccess;  /* access given if no acl matches          */
+       slap_access_t   be_dfltaccess;  /* access given if no acl matches          */
        char    **be_replica;   /* replicas of this backend (in master)    */
        char    *be_replogfile; /* replication log file (in master)        */
        char    *be_update_ndn; /* allowed to make changes (in replicas)   */
index e20c277be2496761cbbde7f88303dbf1a4f6b406..7f13a04257e6afee2947f46f905cda76fafabe6d 100644 (file)
@@ -6,9 +6,7 @@
 include                %SYSCONFDIR%/slapd.at.conf
 include                %SYSCONFDIR%/slapd.oc.conf
 
-# Using ACLs to control access is wise.  When ACLs are used,
-# "defaultaccess none" is recommended (default is 'auth').
-defaultaccess read
+# Define global ACLs to disable default read access.
 
 # Do not enable referrals until AFTER you have a working directory
 # service AND an understanding of referrals.