implement "realdn" by clause in ACLs (ITS#3627; accounting for Howard's remarks)

This commit is contained in:
Pierangelo Masarati 2005-04-03 01:59:03 +00:00
parent fe1b73c712
commit 3eb87b2faa
5 changed files with 593 additions and 337 deletions

View file

@ -618,6 +618,281 @@ acl_get(
return( NULL );
}
static int
acl_mask_dn(
Operation *op,
Entry *e,
AccessControl *a,
int nmatch,
regmatch_t *matches,
slap_dn_access *b,
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 maintaned in a_dn_pat.
*/
if ( b->a_style == ACL_STYLE_ANONYMOUS ) {
if ( !BER_BVISEMPTY( opndn ) ) {
return 1;
}
} else if ( b->a_style == ACL_STYLE_USERS ) {
if ( BER_BVISEMPTY( opndn ) ) {
return 1;
}
} else if ( b->a_style == ACL_STYLE_SELF ) {
struct berval ndn, selfndn;
int level;
if ( BER_BVISEMPTY( opndn ) || BER_BVISNULL( &e->e_nname ) ) {
return 1;
}
level = b->a_self_level;
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 ( b->a_style == ACL_STYLE_REGEX ) {
if ( !ber_bvccmp( &b->a_pat, '*' ) ) {
int tmp_nmatch;
regmatch_t tmp_matches[2],
*tmp_matchesp = tmp_matches;
int rc = 0;
switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
tmp_nmatch = nmatch;
break;
}
/* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 1;
break;
case ACL_STYLE_ONE:
case ACL_STYLE_SUBTREE:
case ACL_STYLE_CHILDREN:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
tmp_matches[1].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 2;
break;
default:
/* error */
rc = 1;
break;
}
if ( rc ) {
return 1;
}
if ( !regex_matches( &b->a_pat, opndn->bv_val,
e->e_ndn, tmp_nmatch, tmp_matchesp ) )
{
return 1;
}
}
} else {
struct berval pat;
ber_len_t patlen, odnlen;
int got_match = 0;
if ( e->e_dn == NULL )
return 1;
if ( b->a_expand ) {
struct berval bv;
char buf[ACL_BUF_SIZE];
int tmp_nmatch;
regmatch_t tmp_matches[2],
*tmp_matchesp = tmp_matches;
int rc = 0;
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = buf;
switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
tmp_nmatch = nmatch;
break;
}
/* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 1;
break;
case ACL_STYLE_ONE:
case ACL_STYLE_SUBTREE:
case ACL_STYLE_CHILDREN:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
tmp_matches[1].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 2;
break;
default:
/* error */
rc = 1;
break;
}
if ( rc ) {
return 1;
}
if ( string_expand( &bv, &b->a_pat,
e->e_nname.bv_val,
tmp_nmatch, tmp_matchesp ) )
{
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 = b->a_pat;
}
patlen = pat.bv_len;
odnlen = opndn->bv_len;
if ( odnlen < patlen ) {
goto dn_match_cleanup;
}
if ( b->a_style == ACL_STYLE_BASE ) {
/* base dn -- entire object DN must match */
if ( odnlen != patlen ) {
goto dn_match_cleanup;
}
} else if ( b->a_style == ACL_STYLE_ONE ) {
int rdnlen = -1;
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 ) {
goto dn_match_cleanup;
}
} else if ( b->a_style == ACL_STYLE_SUBTREE ) {
if ( odnlen > patlen && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
} else if ( b->a_style == ACL_STYLE_CHILDREN ) {
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
} else if ( b->a_style == ACL_STYLE_LEVEL ) {
int level;
struct berval ndn;
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( level > 0 && !DN_SEPARATOR( opndn->bv_val[odnlen - patlen - 1] ) )
{
goto dn_match_cleanup;
}
level = b->a_level;
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 != b->a_pat.bv_val ) {
slap_sl_free( pat.bv_val, op->o_tmpmemctx );
}
if ( !got_match ) {
return 1;
}
}
return 0;
}
/*
* Record value-dependent access control state
*/
@ -633,6 +908,100 @@ acl_get(
} \
} while( 0 )
static int
acl_mask_dnattr(
Operation *op,
Entry *e,
struct berval *val,
AccessControl *a,
Access *b,
int i,
regmatch_t *matches,
int count,
AccessControlState *state,
slap_dn_access *bdn,
struct berval *opndn )
{
Attribute *at;
struct berval bv;
int rc, match = 0;
const char *text;
const char *attr = bdn->a_at->ad_cname.bv_val;
assert( attr != NULL );
if ( BER_BVISEMPTY( opndn ) ) {
return 1;
}
Debug( LDAP_DEBUG_ACL, "<= check a_dn_at: %s\n", attr, 0, 0 );
bv = *opndn;
/* see if asker is listed in dnattr */
for ( at = attrs_find( e->e_attrs, bdn->a_at );
at != NULL;
at = attrs_find( at->a_next, bdn->a_at ) )
{
if ( value_find_ex( bdn->a_at,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
at->a_nvals,
&bv, op->o_tmpmemctx ) == 0 )
{
/* found it */
match = 1;
break;
}
}
if ( match ) {
/* have a dnattr match. if this is a self clause then
* the target must also match the op dn.
*/
if ( bdn->a_self ) {
/* check if the target is an attribute. */
if ( val == NULL ) return 1;
/* target is attribute, check if the attribute value
* is the op dn.
*/
rc = value_match( &match, bdn->a_at,
bdn->a_at->ad_type->sat_equality, 0,
val, &bv, &text );
/* on match error or no match, fail the ACL clause */
if ( rc != LDAP_SUCCESS || match != 0 )
return 1;
}
} else {
/* no dnattr match, check if this is a self clause */
if ( ! bdn->a_self )
return 1;
ACL_RECORD_VALUE_STATE;
/* this is a self clause, check if the target is an
* attribute.
*/
if ( val == NULL )
return 1;
/* target is attribute, check if the attribute value
* is the op dn.
*/
rc = value_match( &match, bdn->a_at,
bdn->a_at->ad_type->sat_equality, 0,
val, &bv, &text );
/* on match error or no match, fail the ACL clause */
if ( rc != LDAP_SUCCESS || match != 0 )
return 1;
}
return 0;
}
/*
* acl_mask - modifies mask based upon the given acl and the
* requested access to entry e, attribute attr, value val. if val
@ -655,7 +1024,7 @@ acl_mask(
int count,
AccessControlState *state )
{
int i, odnlen, patlen;
int i;
Access *b;
#ifdef LDAP_DEBUG
char accessmaskbuf[ACCESSMASK_MAXLEN];
@ -715,255 +1084,41 @@ acl_mask(
* value is set in a_dn_style; however, the string
* is maintaned in a_dn_pat.
*/
if ( b->a_dn_style == ACL_STYLE_ANONYMOUS ) {
if ( !BER_BVISEMPTY( &op->o_ndn ) ) {
continue;
}
} else if ( b->a_dn_style == ACL_STYLE_USERS ) {
if ( BER_BVISEMPTY( &op->o_ndn ) ) {
continue;
}
if ( acl_mask_dn( op, e, a, nmatch, matches,
&b->a_dn, &op->o_ndn ) )
{
continue;
}
}
} else if ( b->a_dn_style == ACL_STYLE_SELF ) {
struct berval ndn, selfndn;
int level;
if ( !BER_BVISEMPTY( &b->a_realdn_pat ) ) {
struct berval ndn;
if ( BER_BVISEMPTY( &op->o_ndn ) || BER_BVISNULL( &e->e_nname ) ) {
continue;
}
level = b->a_dn_self_level;
if ( level < 0 ) {
selfndn = op->o_ndn;
ndn = e->e_nname;
level = -level;
} else {
ndn = op->o_ndn;
selfndn = e->e_nname;
}
for ( ; level > 0; level-- ) {
if ( BER_BVISEMPTY( &ndn ) ) {
break;
}
dnParent( &ndn, &ndn );
}
if ( BER_BVISEMPTY( &ndn ) || !dn_match( &ndn, &selfndn ) )
{
continue;
}
} else if ( b->a_dn_style == ACL_STYLE_REGEX ) {
if ( !ber_bvccmp( &b->a_dn_pat, '*' ) ) {
int tmp_nmatch;
regmatch_t tmp_matches[2],
*tmp_matchesp = tmp_matches;
int rc = 0;
switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
tmp_nmatch = nmatch;
break;
}
/* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 1;
break;
case ACL_STYLE_ONE:
case ACL_STYLE_SUBTREE:
case ACL_STYLE_CHILDREN:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
tmp_matches[1].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 2;
break;
default:
/* error */
rc = 1;
break;
}
if ( rc ) {
continue;
}
if ( !regex_matches( &b->a_dn_pat,
op->o_ndn.bv_val, e->e_ndn,
tmp_nmatch, tmp_matchesp ) )
{
continue;
}
}
Debug( LDAP_DEBUG_ACL, "<= check a_realdn_pat: %s\n",
b->a_realdn_pat.bv_val, 0, 0);
/*
* 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 maintaned in a_dn_pat.
*/
if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
ndn = op->o_conn->c_ndn;
} else {
struct berval pat;
int got_match = 0;
ndn = op->o_ndn;
}
if ( e->e_dn == NULL )
continue;
if ( b->a_dn_expand ) {
struct berval bv;
char buf[ACL_BUF_SIZE];
int tmp_nmatch;
regmatch_t tmp_matches[2],
*tmp_matchesp = tmp_matches;
int rc = 0;
bv.bv_len = sizeof( buf ) - 1;
bv.bv_val = buf;
switch ( a->acl_dn_style ) {
case ACL_STYLE_REGEX:
if ( !BER_BVISNULL( &a->acl_dn_pat ) ) {
tmp_matchesp = matches;
tmp_nmatch = nmatch;
break;
}
/* FALLTHRU: applies also to ACL_STYLE_REGEX when pattern is "*" */
case ACL_STYLE_BASE:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 1;
break;
case ACL_STYLE_ONE:
case ACL_STYLE_SUBTREE:
case ACL_STYLE_CHILDREN:
tmp_matches[0].rm_so = 0;
tmp_matches[0].rm_eo = e->e_nname.bv_len;
tmp_matches[1].rm_so = e->e_nname.bv_len - a->acl_dn_pat.bv_len;
tmp_matches[1].rm_eo = e->e_nname.bv_len;
tmp_nmatch = 2;
break;
default:
/* error */
rc = 1;
break;
}
if ( rc ) {
continue;
}
if ( string_expand( &bv, &b->a_dn_pat,
e->e_nname.bv_val,
tmp_nmatch, tmp_matchesp ) )
{
continue;
}
if ( dnNormalize(0, NULL, NULL, &bv,
&pat, op->o_tmpmemctx )
!= LDAP_SUCCESS )
{
/* did not expand to a valid dn */
continue;
}
} else {
pat = b->a_dn_pat;
}
patlen = pat.bv_len;
odnlen = op->o_ndn.bv_len;
if ( odnlen < patlen ) {
goto dn_match_cleanup;
}
if ( b->a_dn_style == ACL_STYLE_BASE ) {
/* base dn -- entire object DN must match */
if ( odnlen != patlen ) {
goto dn_match_cleanup;
}
} else if ( b->a_dn_style == ACL_STYLE_ONE ) {
int rdnlen = -1;
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
rdnlen = dn_rdnlen( NULL, &op->o_ndn );
if ( rdnlen != odnlen - patlen - 1 ) {
goto dn_match_cleanup;
}
} else if ( b->a_dn_style == ACL_STYLE_SUBTREE ) {
if ( odnlen > patlen && !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
} else if ( b->a_dn_style == ACL_STYLE_CHILDREN ) {
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
goto dn_match_cleanup;
}
} else if ( b->a_dn_style == ACL_STYLE_LEVEL ) {
int level;
struct berval ndn;
if ( odnlen <= patlen ) {
goto dn_match_cleanup;
}
if ( level > 0 && !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) )
{
goto dn_match_cleanup;
}
level = b->a_dn_level;
ndn = op->o_ndn;
for ( ; level > 0; level-- ) {
if ( BER_BVISEMPTY( &ndn ) ) {
goto dn_match_cleanup;
}
dnParent( &ndn, &ndn );
if ( ndn.bv_len < patlen ) {
goto dn_match_cleanup;
}
}
if ( ndn.bv_len != patlen ) {
goto dn_match_cleanup;
}
}
got_match = !strcmp( pat.bv_val, &op->o_ndn.bv_val[ odnlen - patlen ] );
dn_match_cleanup:;
if ( pat.bv_val != b->a_dn_pat.bv_val ) {
slap_sl_free( pat.bv_val, op->o_tmpmemctx );
}
if ( !got_match ) {
continue;
}
if ( acl_mask_dn( op, e, a, nmatch, matches,
&b->a_realdn, &ndn ) )
{
continue;
}
}
@ -1209,6 +1364,33 @@ dn_match_cleanup:;
}
}
if ( b->a_dn_at != NULL ) {
if ( acl_mask_dnattr( op, e, val, a, b, i,
matches, count, state,
&b->a_dn, &op->o_ndn ) )
{
continue;
}
}
if ( b->a_realdn_at != NULL ) {
struct berval ndn;
if ( op->o_conn && !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
ndn = op->o_conn->c_ndn;
} else {
ndn = op->o_ndn;
}
if ( acl_mask_dnattr( op, e, val, a, b, i,
matches, count, state,
&b->a_realdn, &ndn ) )
{
continue;
}
}
#if 0
if ( b->a_dn_at != NULL ) {
Attribute *at;
struct berval bv;
@ -1243,7 +1425,7 @@ dn_match_cleanup:;
}
}
if( match ) {
if ( match ) {
/* have a dnattr match. if this is a self clause then
* the target must also match the op dn.
*/
@ -1261,6 +1443,7 @@ dn_match_cleanup:;
if (rc != LDAP_SUCCESS || match != 0 )
continue;
}
} else {
/* no dnattr match, check if this is a self clause */
if ( ! b->a_dn_self )
@ -1286,6 +1469,7 @@ dn_match_cleanup:;
continue;
}
}
#endif
if ( !BER_BVISEMPTY( &b->a_group_pat ) ) {
struct berval bv;

View file

@ -589,11 +589,13 @@ parse_acl(
/* get <who> */
for ( ; i < argc; i++ ) {
slap_style_t sty = ACL_STYLE_REGEX;
char *style_modifier = NULL;
char *style_level = NULL;
int level = 0;
int expand = 0;
slap_style_t sty = ACL_STYLE_REGEX;
char *style_modifier = NULL;
char *style_level = NULL;
int level = 0;
int expand = 0;
slap_dn_access *bdn = &b->a_dn;
int is_realdn = 0;
split( argv[i], '=', &left, &right );
split( left, '.', &left, &style );
@ -721,38 +723,48 @@ parse_acl(
fname, lineno );
}
if ( strcasecmp( argv[i], "*" ) == 0 ) {
if ( strncasecmp( left, "real", STRLENOF( "real" ) ) == 0 ) {
is_realdn = 1;
bdn = &b->a_realdn;
left += STRLENOF( "real" );
}
if ( strcasecmp( left, "*" ) == 0 ) {
if ( is_realdn ) {
acl_usage();
}
ber_str2bv( "*", STRLENOF( "*" ), 1, &bv );
sty = ACL_STYLE_REGEX;
} else if ( strcasecmp( argv[i], "anonymous" ) == 0 ) {
} else if ( strcasecmp( left, "anonymous" ) == 0 ) {
ber_str2bv("anonymous", STRLENOF( "anonymous" ), 1, &bv);
sty = ACL_STYLE_ANONYMOUS;
} else if ( strcasecmp( argv[i], "users" ) == 0 ) {
} else if ( strcasecmp( left, "users" ) == 0 ) {
ber_str2bv("users", STRLENOF( "users" ), 1, &bv);
sty = ACL_STYLE_USERS;
} else if ( strcasecmp( argv[i], "self" ) == 0 ) {
} else if ( strcasecmp( left, "self" ) == 0 ) {
ber_str2bv("self", STRLENOF( "self" ), 1, &bv);
sty = ACL_STYLE_SELF;
} else if ( strcasecmp( left, "dn" ) == 0 ) {
if ( sty == ACL_STYLE_REGEX ) {
b->a_dn_style = ACL_STYLE_REGEX;
bdn->a_style = ACL_STYLE_REGEX;
if ( right == NULL ) {
/* no '=' */
ber_str2bv("users",
STRLENOF( "users" ),
1, &bv);
b->a_dn_style = ACL_STYLE_USERS;
bdn->a_style = ACL_STYLE_USERS;
} else if (*right == '\0' ) {
/* dn="" */
ber_str2bv("anonymous",
STRLENOF( "anonymous" ),
1, &bv);
b->a_dn_style = ACL_STYLE_ANONYMOUS;
bdn->a_style = ACL_STYLE_ANONYMOUS;
} else if ( strcmp( right, "*" ) == 0 ) {
/* dn=* */
@ -760,7 +772,7 @@ parse_acl(
ber_str2bv("users",
STRLENOF( "users" ),
1, &bv);
b->a_dn_style = ACL_STYLE_USERS;
bdn->a_style = ACL_STYLE_USERS;
} else if ( strcmp( right, ".+" ) == 0
|| strcmp( right, "^.+" ) == 0
@ -772,7 +784,7 @@ parse_acl(
ber_str2bv("users",
STRLENOF( "users" ),
1, &bv);
b->a_dn_style = ACL_STYLE_USERS;
bdn->a_style = ACL_STYLE_USERS;
} else if ( strcmp( right, ".*" ) == 0
|| strcmp( right, "^.*" ) == 0
@ -808,7 +820,7 @@ parse_acl(
}
if ( !BER_BVISNULL( &bv ) ) {
if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
if ( !BER_BVISEMPTY( &bdn->a_pat ) ) {
fprintf( stderr,
"%s: line %d: dn pattern already specified.\n",
fname, lineno );
@ -822,7 +834,7 @@ parse_acl(
expand == 0 )
{
rc = dnNormalize(0, NULL, NULL,
&bv, &b->a_dn_pat, NULL);
&bv, &bdn->a_pat, NULL);
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr,
"%s: line %d: bad DN \"%s\" in by DN clause\n",
@ -832,12 +844,12 @@ parse_acl(
free( bv.bv_val );
} else {
b->a_dn_pat = bv;
bdn->a_pat = bv;
}
b->a_dn_style = sty;
b->a_dn_expand = expand;
bdn->a_style = sty;
bdn->a_expand = expand;
if ( sty == ACL_STYLE_SELF ) {
b->a_dn_self_level = level;
bdn->a_self_level = level;
} else {
if ( level < 0 ) {
@ -858,7 +870,7 @@ parse_acl(
fname, lineno, 0 );
}
b->a_dn_level = level;
bdn->a_level = level;
}
continue;
}
@ -872,14 +884,14 @@ parse_acl(
acl_usage();
}
if( b->a_dn_at != NULL ) {
if( bdn->a_at != NULL ) {
fprintf( stderr,
"%s: line %d: dnattr already specified.\n",
fname, lineno );
acl_usage();
}
rc = slap_str2ad( right, &b->a_dn_at, &text );
rc = slap_str2ad( right, &bdn->a_at, &text );
if( rc != LDAP_SUCCESS ) {
fprintf( stderr,
@ -889,20 +901,20 @@ parse_acl(
}
if( !is_at_syntax( b->a_dn_at->ad_type,
if( !is_at_syntax( bdn->a_at->ad_type,
SLAPD_DN_SYNTAX ) &&
!is_at_syntax( b->a_dn_at->ad_type,
!is_at_syntax( bdn->a_at->ad_type,
SLAPD_NAMEUID_SYNTAX ))
{
fprintf( stderr,
"%s: line %d: dnattr \"%s\": "
"inappropriate syntax: %s\n",
fname, lineno, right,
b->a_dn_at->ad_type->sat_syntax_oid );
bdn->a_at->ad_type->sat_syntax_oid );
acl_usage();
}
if( b->a_dn_at->ad_type->sat_equality == NULL ) {
if( bdn->a_at->ad_type->sat_equality == NULL ) {
fprintf( stderr,
"%s: line %d: dnattr \"%s\": "
"inappropriate matching (no EQUALITY)\n",
@ -1650,9 +1662,13 @@ parse_acl(
}
/* get <access> */
if ( strncasecmp( left, "self", 4 ) == 0 ) {
if ( strncasecmp( left, "self", STRLENOF( "self" ) ) == 0 ) {
b->a_dn_self = 1;
ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( &left[4] ) );
ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( &left[ STRLENOF( "self" ) ] ) );
} else if ( strncasecmp( left, "realself", STRLENOF( "realself" ) ) == 0 ) {
b->a_realdn_self = 1;
ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( &left[ STRLENOF( "realself" ) ] ) );
} else {
ACL_PRIV_ASSIGN( b->a_access_mask, str2accessmask( left ) );
@ -2080,6 +2096,9 @@ access_free( Access *a )
if ( !BER_BVISNULL( &a->a_dn_pat ) ) {
free( a->a_dn_pat.bv_val );
}
if ( !BER_BVISNULL( &a->a_realdn_pat ) ) {
free( a->a_realdn_pat.bv_val );
}
if ( !BER_BVISNULL( &a->a_peername_pat ) ) {
free( a->a_peername_pat.bv_val );
}
@ -2211,6 +2230,62 @@ str2access( const char *str )
static char aclbuf[ACLBUF_MAXLEN];
static char *
dnaccess2text( slap_dn_access *bdn, char *ptr, int is_realdn )
{
*ptr++ = ' ';
if ( is_realdn ) {
ptr = lutil_strcopy( ptr, "real" );
}
if ( ber_bvccmp( &bdn->a_pat, '*' ) ||
bdn->a_style == ACL_STYLE_ANONYMOUS ||
bdn->a_style == ACL_STYLE_USERS ||
bdn->a_style == ACL_STYLE_SELF )
{
if ( is_realdn ) {
assert( ! ber_bvccmp( &bdn->a_pat, '*' ) );
}
ptr = lutil_strcopy( ptr, bdn->a_pat.bv_val );
if ( bdn->a_style == ACL_STYLE_SELF && bdn->a_self_level != 0 ) {
int n = sprintf( ptr, ".level{%d}", bdn->a_self_level );
if ( n > 0 ) {
ptr += n;
} /* else ? */
}
} else {
ptr = lutil_strcopy( ptr, "dn." );
ptr = lutil_strcopy( ptr, style_strings[bdn->a_style] );
if ( bdn->a_style == ACL_STYLE_LEVEL ) {
int n = sprintf( ptr, "{%d}", bdn->a_level );
if ( n > 0 ) {
ptr += n;
} /* else ? */
}
if ( bdn->a_expand ) {
ptr = lutil_strcopy( ptr, ",expand" );
}
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, bdn->a_pat.bv_val );
*ptr++ = '"';
}
if ( bdn->a_at != NULL ) {
*ptr++ = ' ';
if ( is_realdn ) {
ptr = lutil_strcopy( ptr, "real" );
}
ptr = lutil_strcopy( ptr, "dnattr=" );
ptr = lutil_strcopy( ptr, bdn->a_at->ad_cname.bv_val );
}
return ptr;
}
static char *
access2text( Access *b, char *ptr )
{
@ -2219,42 +2294,11 @@ access2text( Access *b, char *ptr )
ptr = lutil_strcopy( ptr, "\tby" );
if ( !BER_BVISEMPTY( &b->a_dn_pat ) ) {
*ptr++ = ' ';
if ( ber_bvccmp( &b->a_dn_pat, '*' ) ||
b->a_dn_style == ACL_STYLE_ANONYMOUS ||
b->a_dn_style == ACL_STYLE_USERS ||
b->a_dn_style == ACL_STYLE_SELF )
{
ptr = lutil_strcopy( ptr, b->a_dn_pat.bv_val );
if ( b->a_dn_style == ACL_STYLE_SELF && b->a_dn_self_level != 0 ) {
int n = sprintf( ptr, ".level{%d}", b->a_dn_self_level );
if ( n > 0 ) {
ptr += n;
} /* else ? */
}
} else {
ptr = lutil_strcopy( ptr, "dn." );
ptr = lutil_strcopy( ptr, style_strings[b->a_dn_style] );
if ( b->a_dn_style == ACL_STYLE_LEVEL ) {
int n = sprintf( ptr, "{%d}", b->a_dn_level );
if ( n > 0 ) {
ptr += n;
} /* else ? */
}
if ( b->a_dn_expand ) {
ptr = lutil_strcopy( ptr, ",expand" );
}
*ptr++ = '=';
*ptr++ = '"';
ptr = lutil_strcopy( ptr, b->a_dn_pat.bv_val );
*ptr++ = '"';
}
ptr = dnaccess2text( &b->a_dn, ptr, 0 );
}
if ( b->a_dn_at != NULL ) {
ptr = lutil_strcopy( ptr, " dnattr=" );
ptr = lutil_strcopy( ptr, b->a_dn_at->ad_cname.bv_val );
if ( !BER_BVISEMPTY( &b->a_realdn_pat ) ) {
ptr = dnaccess2text( &b->a_realdn, ptr, 1 );
}
if ( !BER_BVISEMPTY( &b->a_group_pat ) ) {
@ -2342,7 +2386,11 @@ access2text( Access *b, char *ptr )
}
*ptr++ = ' ';
if ( b->a_dn_self ) ptr = lutil_strcopy( ptr, "self" );
if ( b->a_dn_self ) {
ptr = lutil_strcopy( ptr, "self" );
} else if ( b->a_realdn_self ) {
ptr = lutil_strcopy( ptr, "realself" );
}
ptr = lutil_strcopy( ptr, accessmask2str( b->a_access_mask, maskbuf, 0 ));
if ( !maskbuf[0] ) ptr--;

View file

@ -755,19 +755,17 @@ static int parseProxyAuthz (
ctrl->ldctl_value.bv_len ? ctrl->ldctl_value.bv_val : "anonymous",
0 );
if( ctrl->ldctl_value.bv_len == 0 ) {
if ( ctrl->ldctl_value.bv_len == 0 ) {
Debug( LDAP_DEBUG_TRACE,
"parseProxyAuthz: conn=%lu anonymous\n",
op->o_connid, 0, 0 );
/* anonymous */
free( op->o_dn.bv_val );
op->o_dn.bv_len = 0;
op->o_dn.bv_val = ch_strdup( "" );
free( op->o_ndn.bv_val );
op->o_ndn.bv_val[ 0 ] = '\0';
op->o_ndn.bv_len = 0;
op->o_ndn.bv_val = ch_strdup( "" );
op->o_dn.bv_val[ 0 ] = '\0';
op->o_dn.bv_len = 0;
return LDAP_SUCCESS;
}
@ -791,27 +789,26 @@ static int parseProxyAuthz (
rc = slap_sasl_authorized( op, &op->o_ndn, &dn );
if( rc ) {
if ( rc ) {
ch_free( dn.bv_val );
rs->sr_text = "not authorized to assume identity";
return LDAP_PROXY_AUTHZ_FAILURE;
}
ch_free( op->o_dn.bv_val );
ch_free( op->o_ndn.bv_val );
op->o_dn.bv_val = NULL;
op->o_ndn = dn;
Statslog( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n",
op->o_log_prefix, dn.bv_val, 0, 0, 0 );
ch_free( op->o_dn.bv_val );
/*
* NOTE: since slap_sasl_getdn() returns a normalized dn,
* from now on op->o_dn is normalized
*/
op->o_ndn = dn;
ber_dupbv( &op->o_dn, &dn );
Statslog( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n",
op->o_log_prefix, dn.bv_val, 0, 0, 0 );
return LDAP_SUCCESS;
}

View file

@ -68,13 +68,13 @@ slap_op_free( Operation *op )
if ( op->o_ber != NULL ) {
ber_free( op->o_ber, 1 );
}
if ( op->o_dn.bv_val != NULL ) {
if ( !BER_BVISNULL( &op->o_dn ) ) {
free( op->o_dn.bv_val );
}
if ( op->o_ndn.bv_val != NULL ) {
if ( !BER_BVISNULL( &op->o_ndn ) ) {
free( op->o_ndn.bv_val );
}
if ( op->o_authmech.bv_val != NULL ) {
if ( !BER_BVISNULL( &op->o_authmech ) ) {
free( op->o_authmech.bv_val );
}
if ( op->o_ctrls != NULL ) {
@ -89,9 +89,9 @@ slap_op_free( Operation *op )
{
GroupAssertion *g, *n;
for (g = op->o_groups; g; g=n) {
for ( g = op->o_groups; g; g = n ) {
n = g->ga_next;
slap_sl_free(g, op->o_tmpmemctx);
slap_sl_free( g, op->o_tmpmemctx );
}
op->o_groups = NULL;
}

View file

@ -1228,6 +1228,19 @@ typedef struct slap_dynacl_t {
} slap_dynacl_t;
#endif /* SLAP_DYNACL */
/* the DN portion of the "by" part */
typedef struct slap_dn_access {
/* DN pattern */
AuthorizationInformation a_dnauthz;
slap_style_t a_style;
int a_level;
int a_self_level;
AttributeDescription *a_at;
int a_self;
int a_expand;
} slap_dn_access;
/* the "by" part */
typedef struct slap_access {
slap_control_t a_type;
@ -1299,16 +1312,30 @@ typedef struct slap_access {
slap_mask_t a_access_mask;
AuthorizationInformation a_authz;
#define a_dn_pat a_authz.sai_dn
/* DN pattern */
slap_dn_access a_dn;
#define a_dn_pat a_dn.a_dnauthz.sai_dn
#define a_dn_style a_dn.a_style
#define a_dn_level a_dn.a_level
#define a_dn_self_level a_dn.a_self_level
#define a_dn_at a_dn.a_at
#define a_dn_self a_dn.a_self
#define a_dn_expand a_dn.a_expand
slap_style_t a_dn_style;
int a_dn_level;
int a_dn_self_level;
AttributeDescription *a_dn_at;
int a_dn_self;
int a_dn_expand;
/* real DN pattern */
slap_dn_access a_realdn;
#define a_realdn_pat a_realdn.a_dnauthz.sai_dn
#define a_realdn_style a_realdn.a_style
#define a_realdn_level a_realdn.a_level
#define a_realdn_self_level a_realdn.a_self_level
#define a_realdn_at a_realdn.a_at
#define a_realdn_self a_realdn.a_self
#define a_realdn_expand a_realdn.a_expand
#define a_authz a_dn.a_dnauthz
#define a_pat a_dnauthz.sai_dn
/* connection related stuff */
slap_style_t a_peername_style;
struct berval a_peername_pat;
unsigned long a_peername_addr,