Newer
Older
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
#include <ac/regex.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "sets.h"
#include "lber_pvt.h"
#define ACL_BUF_SIZE 1024 /* use most appropriate size */
static const struct berval acl_bv_ip_eq = BER_BVC( "IP=" );
Pierangelo Masarati
committed
#ifdef LDAP_PF_INET6
static const struct berval acl_bv_ipv6_eq = BER_BVC( "IP=[" );
#endif /* LDAP_PF_INET6 */
static const struct berval acl_bv_path_eq = BER_BVC("PATH=");
Pierangelo Masarati
committed
AccessControl *ac, int *count,
Operation *op, Entry *e,
AccessControl *ac,
AccessControl *prev,
slap_mask_t *mask,
Operation *op, Entry *e,
struct berval *val,
static int regex_matches(
struct berval *pat, char *str,
struct berval *dn_matches, struct berval *val_matches,
AclRegexMatches *matches);
typedef struct AclSetCookie {
SetCookie asc_cookie;
#define asc_op asc_cookie.set_op
Entry *asc_e;
SLAP_SET_GATHER acl_set_gather;
SLAP_SET_GATHER acl_set_gather2;
* 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 loops through all access controls and calls
* slap_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
Pierangelo Masarati
committed
*
* Notes:
* - can be legally called with op == NULL
* - can be legally called with op->o_bd == NULL
Pierangelo Masarati
committed
int
slap_access_always_allowed(
Operation *op,
Entry *e,
AttributeDescription *desc,
struct berval *val,
slap_access_t access,
AccessControlState *state,
slap_mask_t *maskp )
{
Hallvard Furuseth
committed
assert( maskp != NULL );
Pierangelo Masarati
committed
/* assign all */
ACL_LVL_ASSIGN_MANAGE( *maskp );
Pierangelo Masarati
committed
return 1;
}
#define MATCHES_DNMAXCOUNT(m) \
( sizeof ( (m)->dn_data ) / sizeof( *(m)->dn_data ) )
#define MATCHES_VALMAXCOUNT(m) \
( sizeof ( (m)->val_data ) / sizeof( *(m)->val_data ) )
#define MATCHES_MEMSET(m) do { \
memset( (m)->dn_data, '\0', sizeof( (m)->dn_data ) ); \
memset( (m)->val_data, '\0', sizeof( (m)->val_data ) ); \
(m)->dn_count = MATCHES_DNMAXCOUNT( (m) ); \
(m)->val_count = MATCHES_VALMAXCOUNT( (m) ); \
} while ( 0 /* CONSTCOND */ )
slap_access_allowed(
Operation *op,
Entry *e,
AttributeDescription *desc,
struct berval *val,
slap_access_t access,
AccessControlState *state,
slap_mask_t *maskp )
{
int ret = 1;
int count;
#ifdef LDAP_DEBUG
char accessmaskbuf[ACCESSMASK_MAXLEN];
#endif
slap_mask_t mask;
slap_control_t control;
slap_access_t access_level;
const char *attr;
AclRegexMatches matches;
AccessControlState acl_state = ACL_STATE_INIT;
assert( op != NULL );
assert( e != NULL );
assert( desc != NULL );
assert( maskp != NULL );
access_level = ACL_LEVEL( access );
attr = desc->ad_cname.bv_val;
assert( attr != NULL );
ACL_INIT( mask );
/* grant database root access */
if ( be_isroot( op ) ) {
Debug( LDAP_DEBUG_ACL, "<= root access granted\n", 0, 0, 0 );
mask = ACL_LVL_MANAGE;
goto done;
}
/*
* no-user-modification operational attributes are ignored
* by ACL_WRITE checking as any found here are not provided
* by the user
*
* NOTE: but they are not ignored for ACL_MANAGE, because
* if we get here it means a non-root user is trying to
* manage data, so we need to check its privileges.
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 )
{
Debug( LDAP_DEBUG_ACL, "NoUserMod Operational attribute:"
" %s access granted\n",
attr, 0, 0 );
goto done;
}
/* use backend default access if no backend acls */
if ( op->o_bd->be_acl == NULL && frontendDB->be_acl == NULL ) {
int i;
Debug( LDAP_DEBUG_ACL,
"=> slap_access_allowed: backend default %s "
"access %s to \"%s\"\n",
access2str( access ),
op->o_bd->be_dfltaccess >= access_level ? "granted" : "denied",
op->o_dn.bv_val ? op->o_dn.bv_val : "(anonymous)" );
ret = op->o_bd->be_dfltaccess >= access_level;
mask = ACL_PRIV_LEVEL;
for ( i = ACL_NONE; i <= op->o_bd->be_dfltaccess; i++ ) {
ACL_PRIV_SET( mask, ACL_ACCESS2PRIV( i ) );
}
goto done;
}
ret = 0;
control = ACL_BREAK;
if ( state->as_desc == desc &&
state->as_access == access &&
a = state->as_vd_acl;
count = state->as_vd_acl_count;
while ( ( a = slap_acl_get( a, &count, op, e, desc, val,
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
int i;
int dnmaxcount = MATCHES_DNMAXCOUNT( &matches );
int valmaxcount = MATCHES_VALMAXCOUNT( &matches );
regmatch_t *dn_data = matches.dn_data;
regmatch_t *val_data = matches.val_data;
/* DN matches */
for ( i = 0; i < dnmaxcount && dn_data[i].rm_eo > 0; i++ ) {
char *data = e->e_ndn;
Debug( LDAP_DEBUG_ACL, "=> match[dn%d]: %d %d ", i,
(int)dn_data[i].rm_so,
(int)dn_data[i].rm_eo );
if ( dn_data[i].rm_so <= dn_data[0].rm_eo ) {
int n;
for ( n = dn_data[i].rm_so;
n < dn_data[i].rm_eo; n++ ) {
Debug( LDAP_DEBUG_ACL, "%c",
data[n], 0, 0 );
}
}
Debug( LDAP_DEBUG_ACL, "\n", 0, 0, 0 );
}
/* val matches */
for ( i = 0; i < valmaxcount && val_data[i].rm_eo > 0; i++ ) {
char *data = val->bv_val;
Debug( LDAP_DEBUG_ACL, "=> match[val%d]: %d %d ", i,
(int)val_data[i].rm_so,
(int)val_data[i].rm_eo );
if ( val_data[i].rm_so <= val_data[0].rm_eo ) {
for ( n = val_data[i].rm_so;
n < val_data[i].rm_eo; n++ ) {
Debug( LDAP_DEBUG_ACL, "%c",
data[n], 0, 0 );
if ( control != ACL_BREAK ) {
break;
}
}
if ( ACL_IS_INVALID( mask ) ) {
Debug( LDAP_DEBUG_ACL,
"=> slap_access_allowed: \"%s\" (%s) invalid!\n",
e->e_dn, attr, 0 );
} else if ( control == ACL_BREAK ) {
Debug( LDAP_DEBUG_ACL,
"=> slap_access_allowed: no more rules\n", 0, 0, 0 );
goto done;
}
Debug( LDAP_DEBUG_ACL,
"=> slap_access_allowed: %s access %s by %s\n",
access2str( access ), ret ? "granted" : "denied",
accessmask2str( mask, accessmaskbuf, 1 ) );
done:
int
fe_access_allowed(
Operation *op,
Entry *e,
AttributeDescription *desc,
struct berval *val,
slap_access_t access,
AccessControlState *state,
slap_mask_t *maskp )
{
BackendDB *be_orig;
int rc;
/*
* NOTE: control gets here if FIXME
* if an appropriate backend cannot be selected for the operation,
* we assume that the frontend should handle this
* FIXME: should select_backend() take care of this,
* and return frontendDB instead of NULL? maybe for some value
* of the flags?
*/
be_orig = op->o_bd;
if ( op->o_bd == NULL ) {
op->o_bd = select_backend( &op->o_req_ndn, 0 );
if ( op->o_bd == NULL )
op->o_bd = frontendDB;
rc = slap_access_allowed( op, e, desc, val, access, state, maskp );
op->o_bd = be_orig;
return rc;
}
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
int
access_allowed_mask(
Operation *op,
Entry *e,
AttributeDescription *desc,
struct berval *val,
slap_access_t access,
AccessControlState *state,
slap_mask_t *maskp )
{
int ret = 1;
int be_null = 0;
#ifdef LDAP_DEBUG
char accessmaskbuf[ACCESSMASK_MAXLEN];
#endif
slap_mask_t mask;
slap_access_t access_level;
const char *attr;
assert( e != NULL );
assert( desc != NULL );
access_level = ACL_LEVEL( access );
assert( access_level > ACL_NONE );
if ( maskp ) ACL_INVALIDATE( *maskp );
attr = desc->ad_cname.bv_val;
assert( attr != NULL );
Pierangelo Masarati
committed
if ( op->o_acl_priv != ACL_NONE ) {
access = op->o_acl_priv;
} else if ( op->o_is_auth_check &&
( access_level == ACL_SEARCH || access_level == ACL_READ ) )
{
access = ACL_AUTH;
} else if ( get_relax( op ) && access_level == ACL_WRITE &&
desc == slap_schema.si_ad_entry )
{
access = ACL_MANAGE;
}
if ( state != NULL ) {
if ( state->as_desc == desc &&
state->as_access == access &&
state->as_result != -1 &&
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: result was in cache (%s)\n",
attr, 0, 0 );
return state->as_result;
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: result not in cache (%s)\n",
attr, 0, 0 );
}
}
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: %s access to \"%s\" \"%s\" requested\n",
access2str( access ), e->e_dn, attr );
if ( op == NULL ) {
/* no-op call */
goto done;
}
if ( op->o_bd == NULL ) {
op->o_bd = LDAP_STAILQ_FIRST( &backendDB );
/* FIXME: experimental; use first backend rules
* iff there is no global_acl (ITS#3100)
*/
if ( frontendDB->be_acl != NULL ) {
op->o_bd = frontendDB;
}
}
assert( op->o_bd != NULL );
if ( op->o_bd->bd_info->bi_access_allowed ) {
/* delegate to backend */
Pierangelo Masarati
committed
ret = op->o_bd->bd_info->bi_access_allowed( op, e,
desc, val, access, state, &mask );
Pierangelo Masarati
committed
/* use default (but pass through frontend
* for global ACL overlays) */
ret = frontendDB->bd_info->bi_access_allowed( op, e,
desc, val, access, state, &mask );
if ( !ret ) {
if ( ACL_IS_INVALID( mask ) ) {
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: \"%s\" (%s) invalid!\n",
e->e_dn, attr, 0 );
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: no more rules\n", 0, 0, 0 );
goto done;
}
}
Debug( LDAP_DEBUG_ACL,
"=> access_allowed: %s access %s by %s\n",
access2str( access ), ret ? "granted" : "denied",
accessmask2str( mask, accessmaskbuf, 1 ) );
done:
if ( state != NULL ) {
}
if ( be_null ) op->o_bd = NULL;
if ( maskp ) ACL_PRIV_ASSIGN( *maskp, mask );
return ret;
}
* slap_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().
*/
static AccessControl *
AccessControl *a,
int *count,
Operation *op,
Entry *e,
assert( e != NULL );
assert( count != NULL );
assert( desc != NULL );
attr = desc->ad_cname.bv_val;
assert( attr != NULL );
if( a == NULL ) {
Pierangelo Masarati
committed
a = frontendDB->be_acl;
} else {
a = op->o_bd->be_acl;
assert( a != NULL );
if ( a == frontendDB->be_acl )
state->as_fe_done = 1;
} else {
a = a->acl_next;
for ( ; a != NULL; prev = a, a = a->acl_next ) {
(*count) ++;
if ( a != frontendDB->be_acl && state->as_fe_done )
state->as_fe_done++;
if ( a->acl_dn_pat.bv_len || ( a->acl_dn_style != ACL_STYLE_REGEX )) {
if ( a->acl_dn_style == ACL_STYLE_REGEX ) {
Debug( LDAP_DEBUG_ACL, "=> dnpat: [%d] %s nsub: %d\n",
*count, a->acl_dn_pat.bv_val, (int) a->acl_dn_re.re_nsub );
if ( regexec ( &a->acl_dn_re,
e->e_ndn,
matches->dn_count,
matches->dn_data, 0 ) )
continue;
} else {
Debug( LDAP_DEBUG_ACL, "=> dn: [%d] %s\n",
patlen = a->acl_dn_pat.bv_len;
if ( dnlen < patlen )
continue;
if ( a->acl_dn_style == ACL_STYLE_BASE ) {
/* base dn -- entire object DN must match */
if ( dnlen != patlen )
continue;
} else if ( a->acl_dn_style == ACL_STYLE_ONE ) {
if ( dnlen <= patlen )
continue;
if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
rdnlen = dn_rdnlen( NULL, &e->e_nname );
continue;
} else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) {
if ( dnlen > patlen && !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
continue;
} else if ( a->acl_dn_style == ACL_STYLE_CHILDREN ) {
if ( dnlen <= patlen )
continue;
if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
continue;
}
if ( strcmp( a->acl_dn_pat.bv_val, e->e_ndn + dnlen - patlen ) != 0 )
continue;
Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] matched\n",
*count, 0, 0 );
if ( a->acl_attrs && !ad_inlist( desc, a->acl_attrs ) ) {
matches->dn_data[0].rm_so = -1;
matches->dn_data[0].rm_eo = -1;
matches->val_data[0].rm_so = -1;
matches->val_data[0].rm_eo = -1;
continue;
}
/* Is this ACL only for a specific value? */
if ( a->acl_attrval.bv_val ) {
if ( !state->as_vd_acl_present ) {
state->as_vd_acl_present = 1;
state->as_vd_acl = prev;
state->as_vd_acl_count = *count - 1;
if ( a->acl_attrval_style == ACL_STYLE_REGEX ) {
Debug( LDAP_DEBUG_ACL,
"acl_get: valpat %s\n",
a->acl_attrval.bv_val, 0, 0 );
if ( regexec ( &a->acl_attrval_re,
val->bv_val,
matches->val_count,
matches->val_data, 0 ) )
} else {
int match = 0;
const char *text;
Debug( LDAP_DEBUG_ACL,
"acl_get: val %s\n",
a->acl_attrval.bv_val, 0, 0 );
if ( a->acl_attrs[0].an_desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
if (value_match( &match, desc,
a->acl_attrval_mr, 0,
val, &a->acl_attrval, &text ) != LDAP_SUCCESS ||
match )
continue;
} else {
patlen = a->acl_attrval.bv_len;
vdnlen = val->bv_len;
if ( vdnlen < patlen )
continue;
if ( a->acl_attrval_style == ACL_STYLE_BASE ) {
} else if ( a->acl_attrval_style == ACL_STYLE_ONE ) {
if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
continue;
rdnlen = dn_rdnlen( NULL, val );
} else if ( a->acl_attrval_style == ACL_STYLE_SUBTREE ) {
if ( vdnlen > patlen && !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
} else if ( a->acl_attrval_style == ACL_STYLE_CHILDREN ) {
if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
if ( strcmp( a->acl_attrval.bv_val, val->bv_val + vdnlen - patlen ) )
ber_int_t rc = test_filter( NULL, e, a->acl_filter );
if ( rc != LDAP_COMPARE_TRUE ) {
Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] attr %s\n",
if ( !state->as_fe_done ) {
state->as_fe_done = 1;
a = frontendDB->be_acl;
goto retry;
}
Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 );
/*
* Record value-dependent access control state
*/
#define ACL_RECORD_VALUE_STATE do { \
if( state && !state->as_vd_acl_present ) { \
state->as_vd_acl_present = 1; \
state->as_vd_acl = prev; \
state->as_vd_acl_count = count - 1; \
Pierangelo Masarati
committed
static int
acl_mask_dn(
Operation *op,
Entry *e,
Pierangelo Masarati
committed
AccessControl *a,
slap_dn_access *bdn,
Pierangelo Masarati
committed
struct berval *opndn )
{
/*
* if access applies to the entry itself, and the
* user is bound as somebody in the same namespace as
* the entry, OR the given dn matches the dn pattern
*/
/*
* NOTE: styles "anonymous", "users" and "self"
* have been moved to enum slap_style_t, whose
* value is set in a_dn_style; however, the string
* is maintained in a_dn_pat.
Pierangelo Masarati
committed
*/
if ( bdn->a_style == ACL_STYLE_ANONYMOUS ) {
Pierangelo Masarati
committed
if ( !BER_BVISEMPTY( opndn ) ) {
return 1;
}
} else if ( bdn->a_style == ACL_STYLE_USERS ) {
Pierangelo Masarati
committed
if ( BER_BVISEMPTY( opndn ) ) {
return 1;
}
} else if ( bdn->a_style == ACL_STYLE_SELF ) {
Pierangelo Masarati
committed
struct berval ndn, selfndn;
int level;
if ( BER_BVISEMPTY( opndn ) || BER_BVISNULL( &e->e_nname ) ) {
return 1;
}
level = bdn->a_self_level;
Pierangelo Masarati
committed
if ( level < 0 ) {
selfndn = *opndn;
ndn = e->e_nname;
level = -level;
} else {
ndn = *opndn;
selfndn = e->e_nname;
}
for ( ; level > 0; level-- ) {
if ( BER_BVISEMPTY( &ndn ) ) {
break;
}
dnParent( &ndn, &ndn );
}
if ( BER_BVISEMPTY( &ndn ) || !dn_match( &ndn, &selfndn ) )
{
return 1;
}
} else if ( bdn->a_style == ACL_STYLE_REGEX ) {
if ( !ber_bvccmp( &bdn->a_pat, '*' ) ) {
AclRegexMatches tmp_matches,
*tmp_matchesp = &tmp_matches;
Pierangelo Masarati
committed
int rc = 0;
regmatch_t *tmp_data;
MATCHES_MEMSET( &tmp_matches );
tmp_data = &tmp_matches.dn_data[0];
Pierangelo Masarati
committed
if ( a->acl_attrval_style == ACL_STYLE_REGEX )
tmp_matchesp = matches;
else switch ( a->acl_dn_style ) {
Pierangelo Masarati
committed
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
Pierangelo Masarati
committed
break;
}
/* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_data[0].rm_so = 0;
tmp_data[0].rm_eo = e->e_nname.bv_len;
tmp_matches.dn_count = 1;
Pierangelo Masarati
committed
break;
case ACL_STYLE_ONE:
case ACL_STYLE_SUBTREE:
case ACL_STYLE_CHILDREN:
tmp_data[0].rm_so = 0;
tmp_data[0].rm_eo = e->e_nname.bv_len;
tmp_data[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
tmp_data[1].rm_eo = e->e_nname.bv_len;
tmp_matches.dn_count = 2;
Pierangelo Masarati
committed
break;
default:
/* error */
rc = 1;
break;
}
if ( rc ) {
return 1;
}
if ( !regex_matches( &bdn->a_pat, opndn->bv_val,
Pierangelo Masarati
committed
{
return 1;
}
}
} else {
struct berval pat;
ber_len_t patlen, odnlen;
int got_match = 0;
if ( e->e_dn == NULL )
return 1;
if ( bdn->a_expand ) {
Pierangelo Masarati
committed
struct berval bv;
char buf[ACL_BUF_SIZE];
AclRegexMatches tmp_matches,
*tmp_matchesp = &tmp_matches;
Pierangelo Masarati
committed
int rc = 0;
regmatch_t *tmp_data;
MATCHES_MEMSET( &tmp_matches );
tmp_data = &tmp_matches.dn_data[0];
Pierangelo Masarati
committed
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = buf;
/* Expand value regex */
if ( a->acl_attrval_style == ACL_STYLE_REGEX )
tmp_matchesp = matches;
else switch ( a->acl_dn_style ) {
Pierangelo Masarati
committed
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
break;
}
/* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_data[0].rm_so = 0;
tmp_data[0].rm_eo = e->e_nname.bv_len;
tmp_matches.dn_count = 1;
Pierangelo Masarati
committed
break;
case ACL_STYLE_ONE:
case ACL_STYLE_SUBTREE:
case ACL_STYLE_CHILDREN:
tmp_data[0].rm_so = 0;
tmp_data[0].rm_eo = e->e_nname.bv_len;
tmp_data[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
tmp_data[1].rm_eo = e->e_nname.bv_len;
tmp_matches.dn_count = 2;
Pierangelo Masarati
committed
break;
default:
/* error */
rc = 1;
break;
}
if ( rc ) {
return 1;
}
if ( acl_string_expand( &bv, &bdn->a_pat,
Pierangelo Masarati
committed
{
return 1;
}
if ( dnNormalize(0, NULL, NULL, &bv,
&pat, op->o_tmpmemctx )
!= LDAP_SUCCESS )
{
/* did not expand to a valid dn */
return 1;
}
} else {
pat = bdn->a_pat;
Pierangelo Masarati
committed
}
patlen = pat.bv_len;
odnlen = opndn->bv_len;
if ( odnlen < patlen ) {
goto dn_match_cleanup;
}
if ( bdn->a_style == ACL_STYLE_BASE ) {
Pierangelo Masarati
committed
/* base dn -- entire object DN must match */
if ( odnlen != patlen ) {
goto dn_match_cleanup;
}
} else if ( bdn->a_style == ACL_STYLE_ONE ) {
Pierangelo Masarati
committed
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
rdnlen = dn_rdnlen( NULL, opndn );
if ( rdnlen - ( odnlen - patlen - 1 ) != 0 ) {
Pierangelo Masarati
committed
goto dn_match_cleanup;
}
} else if ( bdn->a_style == ACL_STYLE_SUBTREE ) {
Pierangelo Masarati
committed
if ( odnlen > patlen && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
} else if ( bdn->a_style == ACL_STYLE_CHILDREN ) {
Pierangelo Masarati
committed
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
} else if ( bdn->a_style == ACL_STYLE_LEVEL ) {
int level = bdn->a_level;
struct berval ndn;
Pierangelo Masarati
committed
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( level > 0 && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) )
{
goto dn_match_cleanup;
}
ndn = *opndn;
for ( ; level > 0; level-- ) {
if ( BER_BVISEMPTY( &ndn ) ) {
goto dn_match_cleanup;
}
dnParent( &ndn, &ndn );
if ( ndn.bv_len < patlen ) {
goto dn_match_cleanup;
}
}
if ( ndn.bv_len != patlen ) {
goto dn_match_cleanup;
}
}
got_match = !strcmp( pat.bv_val, &opndn->bv_val[ odnlen - patlen ] );
dn_match_cleanup:;
if ( pat.bv_val != bdn->a_pat.bv_val ) {