From 3eb87b2faae4b9f59f1270936f70a1781c2abd7a Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Sun, 3 Apr 2005 01:59:03 +0000 Subject: [PATCH] implement "realdn" by clause in ACLs (ITS#3627; accounting for Howard's remarks) --- servers/slapd/acl.c | 674 ++++++++++++++++++++++++-------------- servers/slapd/aclparse.c | 176 ++++++---- servers/slapd/controls.c | 27 +- servers/slapd/operation.c | 10 +- servers/slapd/slap.h | 47 ++- 5 files changed, 595 insertions(+), 339 deletions(-) diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index 29e348494f..dfae7d5c5a 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -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; - } - - } else if ( b->a_dn_style == ACL_STYLE_SELF ) { - struct berval ndn, selfndn; - int level; - - 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 ( acl_mask_dn( op, e, a, nmatch, matches, + &b->a_dn, &op->o_ndn ) ) + { + continue; + } + } - if ( rc ) { - continue; - } + if ( !BER_BVISEMPTY( &b->a_realdn_pat ) ) { + struct berval ndn; - 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; - - 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 ); - } + ndn = op->o_ndn; + } - 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; diff --git a/servers/slapd/aclparse.c b/servers/slapd/aclparse.c index b72ad12d4a..f82a577c3d 100644 --- a/servers/slapd/aclparse.c +++ b/servers/slapd/aclparse.c @@ -589,11 +589,13 @@ parse_acl( /* get */ 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 */ - 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--; diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 78199b1d2e..27fe43f1c6 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -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; } diff --git a/servers/slapd/operation.c b/servers/slapd/operation.c index e65fd4d7ad..4946c772fd 100644 --- a/servers/slapd/operation.c +++ b/servers/slapd/operation.c @@ -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; } diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index c6bc400739..fb4403a500 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -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 - - 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; - + /* 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 + + /* 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, -- 2.39.5