Commit 4abbf9c6 authored by Pierangelo Masarati's avatar Pierangelo Masarati
Browse files

implement add/delete granularity in write access (ITS#3631)

parent 5807c2b3
......@@ -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;
......
......@@ -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;
}
......
......@@ -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 ) {
......
......@@ -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 ) {
......
......@@ -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;
......
......@@ -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);
......
......@@ -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 */
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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;
......
......@@ -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 );
......
......@@ -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;
......
......@@ -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",
......
......@@ -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 );
......
......@@ -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 "
......
......@@ -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 {