]> git.sur5r.net Git - openldap/commitdiff
implement add/delete granularity in write access (ITS#3631)
authorPierangelo Masarati <ando@openldap.org>
Fri, 8 Apr 2005 00:18:24 +0000 (00:18 +0000)
committerPierangelo Masarati <ando@openldap.org>
Fri, 8 Apr 2005 00:18:24 +0000 (00:18 +0000)
20 files changed:
servers/slapd/acl.c
servers/slapd/aclparse.c
servers/slapd/back-bdb/add.c
servers/slapd/back-bdb/delete.c
servers/slapd/back-bdb/modrdn.c
servers/slapd/back-ldbm/add.c
servers/slapd/back-ldbm/delete.c
servers/slapd/back-ldbm/modrdn.c
servers/slapd/back-shell/add.c
servers/slapd/back-shell/delete.c
servers/slapd/back-shell/modrdn.c
servers/slapd/back-sql/add.c
servers/slapd/back-sql/delete.c
servers/slapd/back-sql/modrdn.c
servers/slapd/modrdn.c
servers/slapd/slap.h
servers/slapd/slapi/slapi_utils.c
tests/data/acl.out.master
tests/data/slapd-acl.conf
tests/scripts/test006-acls

index b26162e0521e915f4188f11164b898e812dc0313..7404cda5b08a04cb1245e868720339b7b5c9ccac 100644 (file)
@@ -164,22 +164,26 @@ access_allowed_mask(
        int                             ret = 1;
        int                             count;
        AccessControl                   *a = NULL;
-       Backend *be;
-       int     be_null = 0;
+       Backend                         *be;
+       int                             be_null = 0;
 
 #ifdef LDAP_DEBUG
-       char accessmaskbuf[ACCESSMASK_MAXLEN];
+       char                            accessmaskbuf[ACCESSMASK_MAXLEN];
 #endif
-       slap_mask_t mask;
-       slap_control_t control;
-       const char *attr;
-       regmatch_t matches[MAXREMATCHES];
-       int        st_same_attr = 0;
-       static AccessControlState state_init = ACL_STATE_INIT;
+       slap_mask_t                     mask;
+       slap_control_t                  control;
+       slap_access_t                   access_level;
+       const char                      *attr;
+       regmatch_t                      matches[MAXREMATCHES];
+       int                             st_same_attr = 0;
+       static AccessControlState       state_init = ACL_STATE_INIT;
 
        assert( e != NULL );
        assert( desc != NULL );
-       assert( access > ACL_NONE );
+
+       access_level = ACL_LEVEL( access );
+
+       assert( access_level > ACL_NONE );
        if ( maskp ) ACL_INVALIDATE( *maskp );
 
        attr = desc->ad_cname.bv_val;
@@ -187,7 +191,7 @@ access_allowed_mask(
        assert( attr != NULL );
 
        if( op && op->o_is_auth_check &&
-               ( access == ACL_SEARCH || access == ACL_READ ))
+               ( access_level == ACL_SEARCH || access_level == ACL_READ ))
        {
                access = ACL_AUTH;
        }
@@ -265,7 +269,7 @@ access_allowed_mask(
         * by ACL_WRITE checking as any found here are not provided
         * by the user
         */
-       if ( access >= ACL_WRITE && is_at_no_user_mod( desc->ad_type )
+       if ( access_level >= ACL_WRITE && is_at_no_user_mod( desc->ad_type )
                && desc != slap_schema.si_ad_entry
                && desc != slap_schema.si_ad_children )
        {
@@ -280,9 +284,9 @@ access_allowed_mask(
                Debug( LDAP_DEBUG_ACL,
                        "=> access_allowed: backend default %s access %s to \"%s\"\n",
                        access2str( access ),
-                       be->be_dfltaccess >= access ? "granted" : "denied",
+                       be->be_dfltaccess >= access_level ? "granted" : "denied",
                        op->o_dn.bv_val ? op->o_dn.bv_val : "(anonymous)" );
-               ret = be->be_dfltaccess >= access;
+               ret = be->be_dfltaccess >= access_level;
 
                if ( maskp ) {
                        int     i;
@@ -302,8 +306,8 @@ access_allowed_mask(
                Debug( LDAP_DEBUG_ACL,
                        "=> access_allowed: global default %s access %s to \"%s\"\n",
                        access2str( access ),
-                       frontendDB->be_dfltaccess >= access ? "granted" : "denied", op->o_dn.bv_val );
-               ret = frontendDB->be_dfltaccess >= access;
+                       frontendDB->be_dfltaccess >= access_level ? "granted" : "denied", op->o_dn.bv_val );
+               ret = frontendDB->be_dfltaccess >= access_level;
 
                if ( maskp ) {
                        int     i;
@@ -1929,7 +1933,7 @@ acl_check_modlist(
                         * This prevents abuse from selfwriters.
                         */
                        if ( ! access_allowed( op, e,
-                               mlist->sml_desc, NULL, ACL_WRITE, &state ) )
+                               mlist->sml_desc, NULL, ACL_WDEL, &state ) )
                        {
                                ret = 0;
                                goto done;
@@ -1947,7 +1951,7 @@ acl_check_modlist(
                                bv->bv_val != NULL; bv++ )
                        {
                                if ( ! access_allowed( op, e,
-                                       mlist->sml_desc, bv, ACL_WRITE, &state ) )
+                                       mlist->sml_desc, bv, ACL_WADD, &state ) )
                                {
                                        ret = 0;
                                        goto done;
@@ -1958,7 +1962,7 @@ acl_check_modlist(
                case LDAP_MOD_DELETE:
                        if ( mlist->sml_values == NULL ) {
                                if ( ! access_allowed( op, e,
-                                       mlist->sml_desc, NULL, ACL_WRITE, NULL ) )
+                                       mlist->sml_desc, NULL, ACL_WDEL, NULL ) )
                                {
                                        ret = 0;
                                        goto done;
@@ -1970,7 +1974,7 @@ acl_check_modlist(
                                bv->bv_val != NULL; bv++ )
                        {
                                if ( ! access_allowed( op, e,
-                                       mlist->sml_desc, bv, ACL_WRITE, &state ) )
+                                       mlist->sml_desc, bv, ACL_WDEL, &state ) )
                                {
                                        ret = 0;
                                        goto done;
index fddae6b13a5eec2f6a9fbe8fdb2e6db8a78150b0..43f93f827fe67c4ac5f5f5d7fca49c0755f14e9d 100644 (file)
@@ -1816,6 +1816,12 @@ accessmask2str( slap_mask_t mask, char *buf, int debug )
                } else if ( ACL_LVL_IS_WRITE(mask) ) {
                        ptr = lutil_strcopy( ptr, "write" );
 
+               } else if ( ACL_LVL_IS_WADD(mask) ) {
+                       ptr = lutil_strcopy( ptr, "add" );
+
+               } else if ( ACL_LVL_IS_WDEL(mask) ) {
+                       ptr = lutil_strcopy( ptr, "delete" );
+
                } else if ( ACL_LVL_IS_MANAGE(mask) ) {
                        ptr = lutil_strcopy( ptr, "manage" );
 
@@ -1850,6 +1856,16 @@ accessmask2str( slap_mask_t mask, char *buf, int debug )
                *ptr++ = 'w';
        } 
 
+       if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WADD) ) {
+               none = 0;
+               *ptr++ = 'a';
+       } 
+
+       if ( ACL_PRIV_ISSET(mask, ACL_PRIV_WDEL) ) {
+               none = 0;
+               *ptr++ = 'z';
+       } 
+
        if ( ACL_PRIV_ISSET(mask, ACL_PRIV_READ) ) {
                none = 0;
                *ptr++ = 'r';
@@ -1877,7 +1893,7 @@ accessmask2str( slap_mask_t mask, char *buf, int debug )
 
        if ( none && ACL_PRIV_ISSET(mask, ACL_PRIV_NONE) ) {
                none = 0;
-               *ptr++ = 'n';
+               *ptr++ = '0';
        } 
 
        if ( none ) {
@@ -1922,6 +1938,12 @@ str2accessmask( const char *str )
                        } else if( TOLOWER((unsigned char) str[i]) == 'w' ) {
                                ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
 
+                       } else if( TOLOWER((unsigned char) str[i]) == 'a' ) {
+                               ACL_PRIV_SET(mask, ACL_PRIV_WADD);
+
+                       } else if( TOLOWER((unsigned char) str[i]) == 'z' ) {
+                               ACL_PRIV_SET(mask, ACL_PRIV_WDEL);
+
                        } else if( TOLOWER((unsigned char) str[i]) == 'r' ) {
                                ACL_PRIV_SET(mask, ACL_PRIV_READ);
 
@@ -1964,6 +1986,12 @@ str2accessmask( const char *str )
        } else if ( strcasecmp( str, "read" ) == 0 ) {
                ACL_LVL_ASSIGN_READ(mask);
 
+       } else if ( strcasecmp( str, "add" ) == 0 ) {
+               ACL_LVL_ASSIGN_WADD(mask);
+
+       } else if ( strcasecmp( str, "delete" ) == 0 ) {
+               ACL_LVL_ASSIGN_WDEL(mask);
+
        } else if ( strcasecmp( str, "write" ) == 0 ) {
                ACL_LVL_ASSIGN_WRITE(mask);
 
@@ -2008,8 +2036,8 @@ acl_usage( void )
                "<peernamestyle> ::= exact | regex | ip | path\n"
                "<domainstyle> ::= exact | regex | base(Object) | sub(tree)\n"
                "<access> ::= [[real]self]{<level>|<priv>}\n"
-               "<level> ::= none|disclose|auth|compare|search|read|write|manage\n"
-               "<priv> ::= {=|+|-}{0|d|x|c|s|r|w|m}+\n"
+               "<level> ::= none|disclose|auth|compare|search|read|{write|add|delete}|manage\n"
+               "<priv> ::= {=|+|-}{0|d|x|c|s|r|{w|a|z}|m}+\n"
                "<control> ::= [ stop | continue | break ]\n"
        );
        exit( EXIT_FAILURE );
@@ -2192,6 +2220,12 @@ access2str( slap_access_t access )
        } else if ( access == ACL_WRITE ) {
                return "write";
 
+       } else if ( access == ACL_WADD ) {
+               return "add";
+
+       } else if ( access == ACL_WDEL ) {
+               return "delete";
+
        } else if ( access == ACL_MANAGE ) {
                return "manage";
 
@@ -2224,6 +2258,12 @@ str2access( const char *str )
        } else if ( strcasecmp( str, "write" ) == 0 ) {
                return ACL_WRITE;
 
+       } else if ( strcasecmp( str, "add" ) == 0 ) {
+               return ACL_WADD;
+
+       } else if ( strcasecmp( str, "delete" ) == 0 ) {
+               return ACL_WDEL;
+
        } else if ( strcasecmp( str, "manage" ) == 0 ) {
                return ACL_MANAGE;
        }
index f94448412c549af4b33443f1abd7ea23d3fc433a..b8554453d920ee40d8d42e49d28bf04202ee5cc4 100644 (file)
@@ -177,7 +177,7 @@ retry:      /* transaction retry */
                }
 
                rs->sr_err = access_allowed( op, p,
-                       children, NULL, ACL_WRITE, NULL );
+                       children, NULL, ACL_WADD, NULL );
 
                if ( ! rs->sr_err ) {
                        switch( opinfo.boi_err ) {
@@ -272,7 +272,7 @@ retry:      /* transaction retry */
        }
 
        rs->sr_err = access_allowed( op, op->oq_add.rs_e,
-               entry, NULL, ACL_WRITE, NULL );
+               entry, NULL, ACL_WADD, NULL );
 
        if ( ! rs->sr_err ) {
                switch( opinfo.boi_err ) {
index f5910ef9a35dc0e6f290cda023bebae3b8bc32c9..e2a8561572a2228cbb109664881101b3e9a3babc 100644 (file)
@@ -202,7 +202,7 @@ retry:      /* transaction retry */
 
                /* check parent for "children" acl */
                rs->sr_err = access_allowed( op, p,
-                       children, NULL, ACL_WRITE, NULL );
+                       children, NULL, ACL_WDEL, NULL );
 
                if ( !rs->sr_err  ) {
                        switch( opinfo.boi_err ) {
@@ -228,7 +228,7 @@ retry:      /* transaction retry */
 
                                /* check parent for "children" acl */
                                rs->sr_err = access_allowed( op, p,
-                                       children, NULL, ACL_WRITE, NULL );
+                                       children, NULL, ACL_WDEL, NULL );
 
                                p = NULL;
 
@@ -266,7 +266,7 @@ retry:      /* transaction retry */
        }
 
        rs->sr_err = access_allowed( op, e,
-               entry, NULL, ACL_WRITE, NULL );
+               entry, NULL, ACL_WDEL, NULL );
 
        if ( !rs->sr_err  ) {
                switch( opinfo.boi_err ) {
index 4385e8e92cdd05f43f98b505b9abb08438090ac5..3bbf08d54b5e5ea4516eaa95b5196ae01054c976 100644 (file)
@@ -289,7 +289,10 @@ retry:     /* transaction retry */
 
                /* check parent for "children" acl */
                rs->sr_err = access_allowed( op, p,
-                       children, NULL, ACL_WRITE, NULL );
+                       children, NULL,
+                       op->oq_modrdn.rs_newSup == NULL ?
+                               ACL_WRITE : ACL_WDEL,
+                       NULL );
 
                if ( ! rs->sr_err ) {
                        switch( opinfo.boi_err ) {
@@ -330,7 +333,10 @@ retry:     /* transaction retry */
 
                                /* check parent for "children" acl */
                                rs->sr_err = access_allowed( op, p,
-                                       children, NULL, ACL_WRITE, NULL );
+                                       children, NULL,
+                                       op->oq_modrdn.rs_newSup == NULL ?
+                                               ACL_WRITE : ACL_WDEL,
+                                       NULL );
 
                                p = NULL;
 
@@ -437,7 +443,7 @@ retry:      /* transaction retry */
 
                        /* check newSuperior for "children" acl */
                        rs->sr_err = access_allowed( op, np, children,
-                               NULL, ACL_WRITE, NULL );
+                               NULL, ACL_WADD, NULL );
 
                        if( ! rs->sr_err ) {
                                switch( opinfo.boi_err ) {
@@ -492,7 +498,7 @@ retry:      /* transaction retry */
 
                                        /* check parent for "children" acl */
                                        rs->sr_err = access_allowed( op, np,
-                                               children, NULL, ACL_WRITE, NULL );
+                                               children, NULL, ACL_WADD, NULL );
 
                                        np = NULL;
 
index 6bc32c1f221c0ed4e13169a88f094e2b547929ae..25cb07cc0b6e9ab8a02607b2db4da503e6e6defd 100644 (file)
@@ -62,7 +62,7 @@ ldbm_back_add(
 #endif
 
        if ( !access_allowed( op, op->oq_add.rs_e,
-                               entry, NULL, ACL_WRITE, NULL ) )
+                               entry, NULL, ACL_WADD, NULL ) )
        {
                Debug( LDAP_DEBUG_TRACE, "no write access to entry\n", 0,
                    0, 0 );
@@ -131,7 +131,7 @@ ldbm_back_add(
                        return rs->sr_err;
                }
 
-               if ( ! access_allowed( op, p, children, NULL, ACL_WRITE, NULL ) ) {
+               if ( ! access_allowed( op, p, children, NULL, ACL_WADD, NULL ) ) {
                        /* free parent and writer lock */
                        cache_return_entry_w( &li->li_cache, p ); 
                        ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
index dc6256ac2252df77cf0c0968c6f83c2f53f08cd4..6db0d31dbf47be50e88496c1be6621d0850f28ff 100644 (file)
@@ -77,8 +77,7 @@ ldbm_back_delete(
        }
 
        /* check entry for "entry" acl */
-       if ( ! access_allowed( op, e,
-               entry, NULL, ACL_WRITE, NULL ) )
+       if ( ! access_allowed( op, e, entry, NULL, ACL_WDEL, NULL ) )
        {
                Debug( LDAP_DEBUG_TRACE,
                        "<=- ldbm_back_delete: no write access to entry\n", 0,
@@ -134,7 +133,7 @@ ldbm_back_delete(
 
                /* check parent for "children" acl */
                if ( ! access_allowed( op, p,
-                       children, NULL, ACL_WRITE, NULL ) )
+                       children, NULL, ACL_WDEL, NULL ) )
                {
                        Debug( LDAP_DEBUG_TRACE,
                                "<=- ldbm_back_delete: no access to parent\n", 0,
@@ -153,7 +152,7 @@ ldbm_back_delete(
                                p = (Entry *)&slap_entry_root;
                                
                                rc = access_allowed( op, p,
-                                       children, NULL, ACL_WRITE, NULL );
+                                       children, NULL, ACL_WDEL, NULL );
                                p = NULL;
                                                                
                                /* check parent for "children" acl */
index 4df7478e0cd828f53b8aeb9393c65cf8a897f320..c999b27b646a07f1f418de94bb39a66b5966b739 100644 (file)
@@ -101,8 +101,7 @@ ldbm_back_modrdn(
        }
 
        /* check entry for "entry" acl */
-       if ( ! access_allowed( op, e,
-               entry, NULL, ACL_WRITE, NULL ) )
+       if ( ! access_allowed( op, e, entry, NULL, ACL_WRITE, NULL ) )
        {
                Debug( LDAP_DEBUG_TRACE,
                        "<=- ldbm_back_modrdn: no write access to entry\n", 0,
@@ -163,8 +162,10 @@ ldbm_back_modrdn(
                }
 
                /* check parent for "children" acl */
-               if ( ! access_allowed( op, p,
-                       children, NULL, ACL_WRITE, NULL ) )
+               if ( ! access_allowed( op, p, children, NULL,
+                               op->oq_modrdn.rs_newSup != NULL ?
+                                       ACL_WDEL : ACL_WRITE,
+                               NULL ) )
                {
                        Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
                                0, 0 );
@@ -197,7 +198,10 @@ ldbm_back_modrdn(
                                p = (Entry *)&slap_entry_root;
                                
                                can_access = access_allowed( op, p,
-                                               children, NULL, ACL_WRITE, NULL );
+                                               children, NULL,
+                                               op->oq_modrdn.rs_newSup ?
+                                                       ACL_WDEL : ACL_WRITE,
+                                               NULL );
                                p = NULL;
                                                                
                                /* check parent for "children" acl */
@@ -270,7 +274,7 @@ ldbm_back_modrdn(
 
                        /* check newSuperior for "children" acl */
                        if ( !access_allowed( op, np, children, NULL,
-                                             ACL_WRITE, NULL ) )
+                                             ACL_WADD, NULL ) )
                        {
                                Debug( LDAP_DEBUG_TRACE,
                                       "ldbm_back_modrdn: no wr to newSup children\n",
@@ -316,7 +320,7 @@ ldbm_back_modrdn(
                                        np = (Entry *)&slap_entry_root;
                                
                                        can_access = access_allowed( op, np,
-                                                       children, NULL, ACL_WRITE, NULL );
+                                                       children, NULL, ACL_WADD, NULL );
                                        np = NULL;
                                                                
                                        /* check parent for "children" acl */
index 120ed0e9ceb0354c635775837e8d3956ef18e221..3ae45cec7095f2275e6b2bb206ea6d6742858d46 100644 (file)
@@ -55,7 +55,7 @@ shell_back_add(
        }
 
        if ( ! access_allowed( op, op->oq_add.rs_e,
-               entry, NULL, ACL_WRITE, NULL ) )
+               entry, NULL, ACL_WADD, NULL ) )
        {
                send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS, NULL );
                return -1;
index 8721efb082b5882f7fa457f5c4be382769e94af1..df81625688bfe6fe17feeb5f0e48e26f9db93dbe 100644 (file)
@@ -64,7 +64,7 @@ shell_back_delete(
        e.e_private = NULL;
 
        if ( ! access_allowed( op, &e,
-               entry, NULL, ACL_WRITE, NULL ) )
+               entry, NULL, ACL_WDEL, NULL ) )
        {
                send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS, NULL );
                return -1;
index 6388f17f6d3a9a388978beacedf486a968bea7fb..60484def5b2b2b3a3a89fec54b475eb607b36fb6 100644 (file)
@@ -63,8 +63,9 @@ shell_back_modrdn(
        e.e_bv.bv_val = NULL;
        e.e_private = NULL;
 
-       if ( ! access_allowed( op, &e,
-               entry, NULL, ACL_WRITE, NULL ) )
+       if ( ! access_allowed( op, &e, entry, NULL,
+                       op->oq_modrdn.rs_newSup ? ACL_WDEL : ACL_WRITE,
+                       NULL ) )
        {
                send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS, NULL );
                return -1;
@@ -83,7 +84,7 @@ shell_back_modrdn(
        fprintf( wfp, "dn: %s\n", op->o_req_dn.bv_val );
        fprintf( wfp, "newrdn: %s\n", op->oq_modrdn.rs_newrdn.bv_val );
        fprintf( wfp, "deleteoldrdn: %d\n", op->oq_modrdn.rs_deleteoldrdn ? 1 : 0 );
-       if (op->oq_modrdn.rs_newSup != NULL) {
+       if ( op->oq_modrdn.rs_newSup != NULL ) {
                fprintf( wfp, "newSuperior: %s\n", op->oq_modrdn.rs_newSup->bv_val );
        }
        fclose( wfp );
index 1e46866dd826daaa56582f299cb6f33e0e7ba12d..40aac5a3e42c5eb7b38d5ab4f1297547b1e7a561 100644 (file)
@@ -1152,7 +1152,7 @@ backsql_add( Operation *op, SlapReply *rs )
 
        /* check "children" pseudo-attribute access to parent */
        if ( !access_allowed( op, &p, slap_schema.si_ad_children,
-                               NULL, ACL_WRITE, NULL ) )
+                               NULL, ACL_WADD, NULL ) )
        {
                rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
                e = &p;
@@ -1170,7 +1170,7 @@ backsql_add( Operation *op, SlapReply *rs )
 
        if ( !access_allowed_mask( op, op->ora_e,
                                slap_schema.si_ad_entry,
-                               NULL, ACL_WRITE, NULL, &mask ) )
+                               NULL, ACL_WADD, NULL, &mask ) )
        {
                rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
                e = op->ora_e;
index 9d85cce33a58de3d3c0c6337cf0943de430ce85d..5659541268adaae12a36f7d5779f72bf3deb0f09 100644 (file)
@@ -162,7 +162,7 @@ backsql_delete( Operation *op, SlapReply *rs )
        }
 
        if ( !access_allowed( op, &d, slap_schema.si_ad_entry, 
-                       NULL, ACL_WRITE, NULL ) )
+                       NULL, ACL_WDEL, NULL ) )
        {
                Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
                        "no write access to entry\n", 
@@ -238,7 +238,7 @@ backsql_delete( Operation *op, SlapReply *rs )
 
        /* check parent for "children" acl */
        if ( !access_allowed( op, &p, slap_schema.si_ad_children, 
-                       NULL, ACL_WRITE, NULL ) )
+                       NULL, ACL_WDEL, NULL ) )
        {
                Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
                        "no write access to parent\n", 
index a1578e565d8749d6c399feea9a62c11211a6f858..55acd62d2d7b92fe10f550fb51bf7571c4cd97d3 100644 (file)
@@ -194,8 +194,9 @@ backsql_modrdn( Operation *op, SlapReply *rs )
                goto done;
        }
 
-       if ( !access_allowed( op, &p, slap_schema.si_ad_children, 
-                               NULL, ACL_WRITE, NULL ) ) {
+       if ( !access_allowed( op, &p, slap_schema.si_ad_children, NULL,
+                       newSuperior ? ACL_WDEL : ACL_WRITE, NULL ) )
+       {
                Debug( LDAP_DEBUG_TRACE, "   no access to parent\n", 0, 0, 0 );
                rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
                goto done;
@@ -250,7 +251,7 @@ backsql_modrdn( Operation *op, SlapReply *rs )
 #endif /* ! BACKSQL_ARBITRARY_KEY */
 
                if ( !access_allowed( op, &n, slap_schema.si_ad_children, 
-                                       NULL, ACL_WRITE, NULL ) ) {
+                                       NULL, ACL_WADD, NULL ) ) {
                        Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
                                        "no access to new parent \"%s\"\n", 
                                        new_pdn->bv_val, 0, 0 );
index c9171d709bb52e6d5ebd5d5003a64264095b8e40..b0f8d3e0288d1df4da5271120e3851be50a40d66 100644 (file)
@@ -450,7 +450,7 @@ slap_modrdn2mods(
 
                /* ACL check of newly added attrs */
                if ( op->o_bd && !access_allowed( op, e, desc,
-                       &new_rdn[a_cnt]->la_value, ACL_WRITE, NULL ) ) {
+                       &new_rdn[a_cnt]->la_value, ACL_WADD, NULL ) ) {
                        Debug( LDAP_DEBUG_TRACE,
                                "slap_modrdn2modlist: access to attr \"%s\" "
                                "(new) not allowed\n", 
@@ -500,9 +500,9 @@ slap_modrdn2mods(
                                goto done;              
                        }
 
-                       /* ACL check of newly added attrs */
+                       /* ACL check of old rdn attrs removal */
                        if ( op->o_bd && !access_allowed( op, e, desc,
-                               &old_rdn[d_cnt]->la_value, ACL_WRITE
+                               &old_rdn[d_cnt]->la_value, ACL_WDEL
                                NULL ) ) {
                                Debug( LDAP_DEBUG_TRACE,
                                        "slap_modrdn2modlist: access "
index 2f855c9ef679710d18cb82d75c39c676e6ed5af5..fc020433c299bb48c3409b93943a834805544c0d 100644 (file)
@@ -1156,7 +1156,19 @@ typedef enum slap_access_e {
        ACL_SEARCH,
        ACL_READ,
        ACL_WRITE,
-       ACL_MANAGE
+       ACL_MANAGE,
+
+       /* ACL level mask and modifiers */
+       ACL_LEVEL_MASK = 0x000f,
+       ACL_QUALIFIER1 = 0x0100,
+       ACL_QUALIFIER2 = 0x0200,
+       ACL_QUALIFIER3 = 0x0400,
+       ACL_QUALIFIER4 = 0x0800,
+       ACL_QUALIFIER_MASK = 0x0f00,
+
+       /* write granularity */
+       ACL_WADD = ACL_WRITE|ACL_QUALIFIER1,
+       ACL_WDEL = ACL_WRITE|ACL_QUALIFIER2
 } slap_access_t;
 
 typedef enum slap_control_e {
@@ -1246,7 +1258,11 @@ typedef struct slap_dn_access {
 typedef struct slap_access {
        slap_control_t a_type;
 
-#define ACL_ACCESS2PRIV(access)        (0x01U << (access))
+/* strip qualifiers */
+#define ACL_LEVEL(p)                   ((p) & ACL_LEVEL_MASK)
+#define ACL_QUALIFIERS(p)              ((p) & ~ACL_LEVEL_MASK)
+
+#define ACL_ACCESS2PRIV(access)                ((0x01U << ACL_LEVEL((access))) | ACL_QUALIFIERS((access)))
 
 #define ACL_PRIV_NONE                  ACL_ACCESS2PRIV( ACL_NONE )
 #define ACL_PRIV_DISCLOSE              ACL_ACCESS2PRIV( ACL_DISCLOSE )
@@ -1254,25 +1270,28 @@ typedef struct slap_access {
 #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_WADD                  ACL_ACCESS2PRIV( ACL_WADD )
+#define ACL_PRIV_WDEL                  ACL_ACCESS2PRIV( ACL_WDEL )
+#define ACL_PRIV_WRITE                 ( ACL_PRIV_WADD | ACL_PRIV_WDEL )
 #define ACL_PRIV_MANAGE                        ACL_ACCESS2PRIV( ACL_MANAGE )
 
-#define ACL_PRIV_MASK                  0x00ffUL
+/* NOTE: always use the highest level; current: 0x00ffUL */
+#define ACL_PRIV_MASK                  ((ACL_PRIV_MANAGE - 1) | ACL_QUALIFIER_MASK)
 
 /* priv flags */
 #define ACL_PRIV_LEVEL                 0x1000UL
 #define ACL_PRIV_ADDITIVE              0x2000UL
-#define ACL_PRIV_SUBSTRACTIVE  0x4000UL
+#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_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_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))
@@ -1281,7 +1300,7 @@ typedef struct slap_access {
 
 #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_IS_SUBTRACTIVE(m)          ACL_PRIV_ISSET((m),ACL_PRIV_SUBSTRACTIVE)
 
 #define ACL_LVL_NONE                   (ACL_PRIV_NONE|ACL_PRIV_LEVEL)
 #define ACL_LVL_DISCLOSE               (ACL_PRIV_DISCLOSE|ACL_LVL_NONE)
@@ -1289,18 +1308,22 @@ typedef struct slap_access {
 #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_WADD                   (ACL_PRIV_WADD|ACL_LVL_READ)
+#define ACL_LVL_WDEL                   (ACL_PRIV_WDEL|ACL_LVL_READ)
 #define ACL_LVL_WRITE                  (ACL_PRIV_WRITE|ACL_LVL_READ)
 #define ACL_LVL_MANAGE                 (ACL_PRIV_MANAGE|ACL_LVL_WRITE)
 
 #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_DISCLOSE(m) ACL_LVL((m),ACL_LVL_DISCLOSE)
+#define ACL_LVL_IS_DISCLOSE(m)         ACL_LVL((m),ACL_LVL_DISCLOSE)
 #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_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_WADD(m)             ACL_LVL((m),ACL_LVL_WADD)
+#define ACL_LVL_IS_WDEL(m)             ACL_LVL((m),ACL_LVL_WDEL)
 #define ACL_LVL_IS_WRITE(m)            ACL_LVL((m),ACL_LVL_WRITE)
-#define ACL_LVL_IS_MANAGE(m)   ACL_LVL((m),ACL_LVL_MANAGE)
+#define ACL_LVL_IS_MANAGE(m)           ACL_LVL((m),ACL_LVL_MANAGE)
 
 #define ACL_LVL_ASSIGN_NONE(m)         ACL_PRIV_ASSIGN((m),ACL_LVL_NONE)
 #define ACL_LVL_ASSIGN_DISCLOSE(m)     ACL_PRIV_ASSIGN((m),ACL_LVL_DISCLOSE)
@@ -1308,6 +1331,8 @@ typedef struct slap_access {
 #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_WADD(m)         ACL_PRIV_ASSIGN((m),ACL_LVL_WADD)
+#define ACL_LVL_ASSIGN_WDEL(m)         ACL_PRIV_ASSIGN((m),ACL_LVL_WDEL)
 #define ACL_LVL_ASSIGN_WRITE(m)                ACL_PRIV_ASSIGN((m),ACL_LVL_WRITE)
 #define ACL_LVL_ASSIGN_MANAGE(m)       ACL_PRIV_ASSIGN((m),ACL_LVL_MANAGE)
 
index 244ec53701825bf5c76fc650534de223634c6989..7590a93912675a39341fcd935ed42dea638bd9a2 100644 (file)
@@ -3364,6 +3364,7 @@ int slapi_access_allowed( Slapi_PBlock *pb, Slapi_Entry *e, char *attr,
        case SLAPI_ACL_DELETE:
        case SLAPI_ACL_ADD:
        case SLAPI_ACL_SELF:
+               /* FIXME: handle ACL_WADD/ACL_WDEL */
                slap_access = ACL_WRITE;
                break;
        default:
@@ -4000,6 +4001,7 @@ int slapi_int_access_allowed( Operation *op,
 
        switch ( access ) {
        case ACL_WRITE:
+               /* FIXME: handle ACL_WADD/ACL_WDEL */
                slap_access |= SLAPI_ACL_ADD | SLAPI_ACL_DELETE | SLAPI_ACL_WRITE;
                break;
        case ACL_READ:
index ea2abb2317113e4ad36801ddde2759bbd72ae49b..8b0134895ee751095fa43bc914354553707ea795 100644 (file)
@@ -21,6 +21,22 @@ facsimileTelephoneNumber: +1 313 555 4332
 telephoneNumber: +1 313 555 0895
 
 # Using ldapsearch to retrieve all the entries...
+dn: ou=Add/Delete,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Add/Delete
+
+dn: cn=Added by Bjorn (must succeed),ou=Add/Delete,dc=example,dc=com
+objectClass: inetOrgPerson
+cn: Added by Bjorn (must succeed)
+sn: None
+description: this attribute value has been added __after__entry creation
+description: Bjorn will try to delete this attribute value (should fail)
+
+dn: cn=Added by Bjorn (renamed by Jaj),ou=Add/Delete,dc=example,dc=com
+objectClass: inetOrgPerson
+sn: None
+cn: Added by Bjorn (renamed by Jaj)
+
 dn: cn=All Staff,ou=Groups,dc=example,dc=com
 member: cn=Manager,dc=example,dc=com
 member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam
index f01b747f8f2422609cd2c45e1fea80034f3112bb..c56586bff17df4c9d78b411005f5ab9576e5e723 100644 (file)
@@ -95,6 +95,12 @@ access               to dn.exact="cn=Alumni Assoc Staff,ou=Groups,dc=example,dc=com"
 access         to filter="(name=X*Y*Z)"
                by * continue
 
+access         to dn.subtree="ou=Add/Delete,dc=example,dc=com"
+               by dn.exact="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" add
+               by dn.exact="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" delete
+               by dn.exact="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com" write
+               by * read
+
 # fall into global ACLs
 
 #monitor#database monitor
index 338b145fc9e5465c92cfe1890556bac7ca260839..20a367f6ac82f3e8fc52529dfd7def7990992794 100755 (executable)
@@ -172,6 +172,103 @@ description: added by bjensen (should fail)
 -
 EOMODS6
 
+$LDAPMODIFY -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD >> \
+       $TESTOUT 2>&1 << EOMODS7
+dn: ou=Add/Delete,dc=example,dc=com
+changetype: add
+objectClass: organizationalUnit
+ou: Add/Delete
+EOMODS7
+
+$LDAPMODIFY -D "$BABSDN" -h $LOCALHOST -p $PORT1 -w bjensen >> \
+       $TESTOUT 2>&1 << EOMODS8
+dn: cn=Added by Babs (must fail),ou=Add/Delete,dc=example,dc=com
+changetype: add
+objectClass: inetOrgPerson
+cn: Added by Babs (must fail)
+sn: None
+EOMODS8
+
+$LDAPMODIFY -D "$BJORNSDN" -h $LOCALHOST -p $PORT1 -w bjorn >> \
+       $TESTOUT 2>&1 << EOMODS9
+dn: cn=Added by Bjorn (must succeed),ou=Add/Delete,dc=example,dc=com
+changetype: add
+objectClass: inetOrgPerson
+cn: Added by Bjorn (must succeed)
+sn: None
+
+dn: cn=Added by Bjorn (will be deleted),ou=Add/Delete,dc=example,dc=com
+changetype: add
+objectClass: inetOrgPerson
+cn: Added by Bjorn (will be deleted)
+sn: None
+
+dn: cn=Added by Bjorn (will be renamed),ou=Add/Delete,dc=example,dc=com
+changetype: add
+objectClass: inetOrgPerson
+cn: Added by Bjorn (will be renamed)
+sn: None
+
+dn: cn=Added by Bjorn (must succeed),ou=Add/Delete,dc=example,dc=com
+changetype: modify
+add: description
+description: this attribute value has been added __after__entry creation
+description: this attribute value will be deleted by Babs (must succeed)
+description: Bjorn will try to delete this attribute value (should fail)
+-
+EOMODS9
+
+$LDAPMODIFY -D "$BJORNSDN" -h $LOCALHOST -p $PORT1 -w bjorn >> \
+       $TESTOUT 2>&1 << EOMODS10
+dn: cn=Added by Bjorn (will be deleted),ou=Add/Delete,dc=example,dc=com
+changetype: delete
+EOMODS10
+
+$LDAPMODIFY -D "$BJORNSDN" -h $LOCALHOST -p $PORT1 -w bjorn >> \
+       $TESTOUT 2>&1 << EOMODS11
+dn: cn=Added by Bjorn (will be renamed),ou=Add/Delete,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Added by Bjorn (renamed by Bjorn)
+deleteoldrdn: 1
+EOMODS11
+
+$LDAPMODIFY -D "$BABSDN" -h $LOCALHOST -p $PORT1 -w bjensen >> \
+       $TESTOUT 2>&1 << EOMODS12
+dn: cn=Added by Bjorn (will be renamed),ou=Add/Delete,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Added by Bjorn (renamed by Babs)
+deleteoldrdn: 1
+EOMODS12
+
+$LDAPMODIFY -D "$JAJDN" -h $LOCALHOST -p $PORT1 -w jaj >> \
+       $TESTOUT 2>&1 << EOMODS13
+dn: cn=Added by Bjorn (will be renamed),ou=Add/Delete,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Added by Bjorn (renamed by Jaj)
+deleteoldrdn: 1
+EOMODS13
+
+$LDAPMODIFY -D "$BJORNSDN" -h $LOCALHOST -p $PORT1 -w bjorn >> \
+       $TESTOUT 2>&1 << EOMODS14
+dn: cn=Added by Bjorn (must succeed),ou=Add/Delete,dc=example,dc=com
+changetype: modify
+delete: description
+description: Bjorn will try to delete this attribute value (should fail)
+-
+EOMODS14
+
+$LDAPMODIFY -D "$BABSDN" -h $LOCALHOST -p $PORT1 -w bjensen >> \
+       $TESTOUT 2>&1 << EOMODS15
+dn: cn=Added by Bjorn (will be deleted),ou=Add/Delete,dc=example,dc=com
+changetype: delete
+
+dn: cn=Added by Bjorn (must succeed),ou=Add/Delete,dc=example,dc=com
+changetype: modify
+delete: description
+description: this attribute value will be deleted by Babs (must succeed)
+-
+EOMODS15
+
 echo "Using ldapsearch to retrieve all the entries..."
 echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
 $LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \