X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Facl.c;h=bbd89fbd3812edaddc6b3c644ae21bb4d33d7f73;hb=7ca6247395c4fb838516e4b3ec917b8f7c1769e4;hp=b58992fe048b4f0c8742a7834500d8cfaad7effc;hpb=71c93265e20c817bfc39d4b2eea69d79f1c70736;p=openldap diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index b58992fe04..bbd89fbd38 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2007 The OpenLDAP Foundation. + * Copyright 1998-2009 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,7 +52,8 @@ static AccessControl * slap_acl_get( Operation *op, Entry *e, AttributeDescription *desc, struct berval *val, - int nmatch, regmatch_t *matches, + AclRegexMatches *matches, + slap_mask_t *mask, AccessControlState *state ); static slap_control_t slap_acl_mask( @@ -60,14 +61,15 @@ static slap_control_t slap_acl_mask( Operation *op, Entry *e, AttributeDescription *desc, struct berval *val, - int nmatch, - regmatch_t *matches, + AclRegexMatches *matches, int count, - AccessControlState *state ); + AccessControlState *state, + slap_access_t access ); static int regex_matches( - struct berval *pat, char *str, char *buf, - int nmatch, regmatch_t *matches); + struct berval *pat, char *str, + struct berval *dn_matches, struct berval *val_matches, + AclRegexMatches *matches); typedef struct AclSetCookie { SetCookie asc_cookie; @@ -75,6 +77,7 @@ typedef struct AclSetCookie { Entry *asc_e; } AclSetCookie; + SLAP_SET_GATHER acl_set_gather; SLAP_SET_GATHER acl_set_gather2; @@ -115,6 +118,17 @@ slap_access_always_allowed( 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 */ ) + int slap_access_allowed( Operation *op, @@ -136,7 +150,9 @@ slap_access_allowed( slap_control_t control; slap_access_t access_level; const char *attr; - regmatch_t matches[MAXREMATCHES]; + AclRegexMatches matches; + AccessControlState acl_state = ACL_STATE_INIT; + static AccessControlState state_init = ACL_STATE_INIT; assert( op != NULL ); assert( e != NULL ); @@ -178,7 +194,7 @@ slap_access_allowed( } /* use backend default access if no backend acls */ - if ( op->o_bd->be_acl == NULL ) { + if ( op->o_bd->be_acl == NULL && frontendDB->be_acl == NULL ) { int i; Debug( LDAP_DEBUG_ACL, @@ -200,59 +216,80 @@ slap_access_allowed( ret = 0; control = ACL_BREAK; - if ( state && state->as_vd_ad == desc ) { + if ( state == NULL ) + state = &acl_state; + if ( state->as_desc == desc && + state->as_access == access && + state->as_vd_acl != NULL ) + { a = state->as_vd_acl; count = state->as_vd_acl_count; - + if ( state->as_fe_done ) + state->as_fe_done--; + ACL_PRIV_ASSIGN( mask, state->as_vd_mask ); } else { - if ( state ) state->as_vi_acl = NULL; + *state = state_init; + a = NULL; count = 0; + ACL_PRIV_ASSIGN( mask, *maskp ); } - ACL_PRIV_ASSIGN( mask, *maskp ); - memset( matches, '\0', sizeof( matches ) ); + + MATCHES_MEMSET( &matches ); while ( ( a = slap_acl_get( a, &count, op, e, desc, val, - MAXREMATCHES, matches, state ) ) != NULL ) + &matches, &mask, state ) ) != NULL ) { - int i; - - for ( i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++ ) { - Debug( LDAP_DEBUG_ACL, "=> match[%d]: %d %d ", i, - (int)matches[i].rm_so, (int)matches[i].rm_eo ); - if ( matches[i].rm_so <= matches[0].rm_eo ) { + 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 = matches[i].rm_so; n < matches[i].rm_eo; n++ ) { - Debug( LDAP_DEBUG_ACL, "%c", e->e_ndn[n], 0, 0 ); + 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_ARGS, "\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ACL, "\n", 0, 0, 0 ); } - if ( state ) { - if ( state->as_vi_acl == a && - ( state->as_recorded & ACL_STATE_RECORDED_NV ) ) - { - Debug( LDAP_DEBUG_ACL, - "=> slap_access_allowed: result from state (%s)\n", - attr, 0, 0 ); - ret = state->as_result; - goto done; - } else { - Debug( LDAP_DEBUG_ACL, - "=> slap_access_allowed: no res from state (%s)\n", - attr, 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 ) { + int n; + for ( n = val_data[i].rm_so; + n < val_data[i].rm_eo; n++ ) { + Debug( LDAP_DEBUG_ACL, "%c", + data[n], 0, 0 ); + } } + Debug( LDAP_DEBUG_ACL, "\n", 0, 0, 0 ); } control = slap_acl_mask( a, &mask, op, - e, desc, val, MAXREMATCHES, matches, count, state ); + e, desc, val, &matches, count, state, access ); if ( control != ACL_BREAK ) { break; } - memset( matches, '\0', sizeof( matches ) ); + MATCHES_MEMSET( &matches ); } if ( ACL_IS_INVALID( mask ) ) { @@ -304,7 +341,7 @@ fe_access_allowed( be_orig = op->o_bd; if ( op->o_bd == NULL ) { - op->o_bd = select_backend( &op->o_req_ndn, 0, 0 ); + op->o_bd = select_backend( &op->o_req_ndn, 0 ); if ( op->o_bd == NULL ) op->o_bd = frontendDB; } @@ -325,7 +362,6 @@ access_allowed_mask( slap_mask_t *maskp ) { int ret = 1; - AccessControl *a = NULL; int be_null = 0; #ifdef LDAP_DEBUG @@ -334,7 +370,6 @@ access_allowed_mask( slap_mask_t mask; slap_access_t access_level; const char *attr; - static AccessControlState state_init = ACL_STATE_INIT; assert( e != NULL ); assert( desc != NULL ); @@ -366,16 +401,20 @@ access_allowed_mask( } } - if ( state ) { - if ( state->as_vd_ad == desc ) { - if ( ( state->as_recorded & ACL_STATE_RECORDED_NV ) && - val == NULL ) + if ( state != NULL ) { + if ( state->as_desc == desc && + state->as_access == access && + state->as_result != -1 && + state->as_vd_acl == NULL ) { + Debug( LDAP_DEBUG_ACL, + "=> access_allowed: result was in cache (%s)\n", + attr, 0, 0 ); return state->as_result; - - } } else { - *state = state_init; + Debug( LDAP_DEBUG_ACL, + "=> access_allowed: result not in cache (%s)\n", + attr, 0, 0 ); } } @@ -436,13 +475,9 @@ access_allowed_mask( done: if ( state != NULL ) { - /* If not value-dependent, save ACL in case of more attrs */ - if ( !( state->as_recorded & ACL_STATE_RECORDED_VD ) ) { - state->as_vi_acl = a; + state->as_access = access; state->as_result = ret; - } - state->as_recorded |= ACL_STATE_RECORDED; - state->as_vd_ad = desc; + state->as_desc = desc; } if ( be_null ) op->o_bd = NULL; if ( maskp ) ACL_PRIV_ASSIGN( *maskp, mask ); @@ -464,24 +499,25 @@ slap_acl_get( Entry *e, AttributeDescription *desc, struct berval *val, - int nmatch, - regmatch_t *matches, + AclRegexMatches *matches, + slap_mask_t *mask, AccessControlState *state ) { const char *attr; - int dnlen, patlen; + ber_len_t dnlen; AccessControl *prev; assert( e != NULL ); assert( count != NULL ); assert( desc != NULL ); + assert( state != NULL ); attr = desc->ad_cname.bv_val; assert( attr != NULL ); if( a == NULL ) { - if( op->o_bd == NULL ) { + if( op->o_bd == NULL || op->o_bd->be_acl == NULL ) { a = frontendDB->be_acl; } else { a = op->o_bd->be_acl; @@ -489,7 +525,8 @@ slap_acl_get( prev = NULL; assert( a != NULL ); - + if ( a == frontendDB->be_acl ) + state->as_fe_done = 1; } else { prev = a; a = a->acl_next; @@ -497,17 +534,26 @@ slap_acl_get( dnlen = e->e_nname.bv_len; + retry: 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, nmatch, matches, 0)) + if ( regexec ( &a->acl_dn_re, + e->e_ndn, + matches->dn_count, + matches->dn_data, 0 ) ) continue; } else { + ber_len_t patlen; + Debug( LDAP_DEBUG_ACL, "=> dn: [%d] %s\n", *count, a->acl_dn_pat.bv_val, 0 ); patlen = a->acl_dn_pat.bv_len; @@ -521,7 +567,7 @@ slap_acl_get( } else if ( a->acl_dn_style == ACL_STYLE_ONE ) { ber_len_t rdnlen = 0; - int sep = 0; + ber_len_t sep = 0; if ( dnlen <= patlen ) continue; @@ -533,7 +579,7 @@ slap_acl_get( } rdnlen = dn_rdnlen( NULL, &e->e_nname ); - if ( rdnlen != dnlen - patlen - sep ) + if ( rdnlen + patlen + sep != dnlen ) continue; } else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) { @@ -556,7 +602,10 @@ slap_acl_get( } if ( a->acl_attrs && !ad_inlist( desc, a->acl_attrs ) ) { - matches[0].rm_so = matches[0].rm_eo = -1; + 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; } @@ -566,17 +615,20 @@ slap_acl_get( continue; } - if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) { - state->as_recorded |= ACL_STATE_RECORDED_VD; + if ( state->as_vd_acl == NULL ) { state->as_vd_acl = prev; state->as_vd_acl_count = *count - 1; + ACL_PRIV_ASSIGN ( state->as_vd_mask, *mask ); } 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, 0, NULL, 0 ) ) + if ( regexec ( &a->acl_attrval_re, + val->bv_val, + matches->val_count, + matches->val_data, 0 ) ) { continue; } @@ -596,7 +648,7 @@ slap_acl_get( continue; } else { - int patlen, vdnlen; + ber_len_t patlen, vdnlen; patlen = a->acl_attrval.bv_len; vdnlen = val->bv_len; @@ -615,7 +667,7 @@ slap_acl_get( continue; rdnlen = dn_rdnlen( NULL, val ); - if ( rdnlen != vdnlen - patlen - 1 ) + if ( rdnlen + patlen + 1 != vdnlen ) continue; } else if ( a->acl_attrval_style == ACL_STYLE_SUBTREE ) { @@ -648,6 +700,12 @@ slap_acl_get( return a; } + 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 ); return( NULL ); } @@ -656,10 +714,10 @@ slap_acl_get( * Record value-dependent access control state */ #define ACL_RECORD_VALUE_STATE do { \ - if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) { \ - state->as_recorded |= ACL_STATE_RECORDED_VD; \ + if( state && state->as_vd_acl == NULL ) { \ state->as_vd_acl = a; \ state->as_vd_acl_count = count; \ + ACL_PRIV_ASSIGN( state->as_vd_mask, *mask ); \ } \ } while( 0 ) @@ -667,11 +725,9 @@ static int acl_mask_dn( Operation *op, Entry *e, - AttributeDescription *desc, struct berval *val, AccessControl *a, - int nmatch, - regmatch_t *matches, + AclRegexMatches *matches, slap_dn_access *bdn, struct berval *opndn ) { @@ -730,35 +786,38 @@ acl_mask_dn( } else if ( bdn->a_style == ACL_STYLE_REGEX ) { if ( !ber_bvccmp( &bdn->a_pat, '*' ) ) { - int tmp_nmatch; - regmatch_t tmp_matches[2], - *tmp_matchesp = tmp_matches; - + AclRegexMatches tmp_matches, + *tmp_matchesp = &tmp_matches; int rc = 0; + regmatch_t *tmp_data; + + MATCHES_MEMSET( &tmp_matches ); + tmp_data = &tmp_matches.dn_data[0]; - switch ( a->acl_dn_style ) { + if ( a->acl_attrval_style == ACL_STYLE_REGEX ) + tmp_matchesp = matches; + else switch ( a->acl_dn_style ) { case ACL_STYLE_REGEX: if ( !BER_BVISNULL( &a->acl_dn_pat ) ) { - tmp_matchesp = matches; - tmp_nmatch = nmatch; + tmp_matchesp = matches; 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; + tmp_data[0].rm_so = 0; + tmp_data[0].rm_eo = e->e_nname.bv_len; + tmp_matches.dn_count = 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; + 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; break; default: @@ -772,7 +831,7 @@ acl_mask_dn( } if ( !regex_matches( &bdn->a_pat, opndn->bv_val, - e->e_ndn, tmp_nmatch, tmp_matchesp ) ) + &e->e_nname, NULL, tmp_matchesp ) ) { return 1; } @@ -790,38 +849,42 @@ acl_mask_dn( struct berval bv; char buf[ACL_BUF_SIZE]; - int tmp_nmatch; - regmatch_t tmp_matches[2], - *tmp_matchesp = tmp_matches; - + AclRegexMatches tmp_matches, + *tmp_matchesp = &tmp_matches; int rc = 0; + regmatch_t *tmp_data; + + MATCHES_MEMSET( &tmp_matches ); + tmp_data = &tmp_matches.dn_data[0]; bv.bv_len = sizeof( buf ) - 1; bv.bv_val = buf; - switch ( a->acl_dn_style ) { + /* Expand value regex */ + if ( a->acl_attrval_style == ACL_STYLE_REGEX ) + tmp_matchesp = matches; + else 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; + tmp_data[0].rm_so = 0; + tmp_data[0].rm_eo = e->e_nname.bv_len; + tmp_matches.dn_count = 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; + 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; break; default: @@ -835,8 +898,8 @@ acl_mask_dn( } if ( acl_string_expand( &bv, &bdn->a_pat, - e->e_nname.bv_val, - tmp_nmatch, tmp_matchesp ) ) + &e->e_nname, + val, tmp_matchesp ) ) { return 1; } @@ -946,11 +1009,9 @@ acl_mask_dnattr( Entry *e, struct berval *val, AccessControl *a, - Access *b, - int i, - regmatch_t *matches, int count, AccessControlState *state, + slap_mask_t *mask, slap_dn_access *bdn, struct berval *opndn ) { @@ -974,11 +1035,10 @@ acl_mask_dnattr( at != NULL; at = attrs_find( at->a_next, bdn->a_at ) ) { - if ( value_find_ex( bdn->a_at, + if ( attr_valfind( at, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - at->a_nvals, - &bv, op->o_tmpmemctx ) == 0 ) + &bv, NULL, op->o_tmpmemctx ) == 0 ) { /* found it */ match = 1; @@ -1051,10 +1111,10 @@ slap_acl_mask( Entry *e, AttributeDescription *desc, struct berval *val, - int nmatch, - regmatch_t *matches, + AclRegexMatches *matches, int count, - AccessControlState *state ) + AccessControlState *state, + slap_access_t access ) { int i; Access *b; @@ -1062,7 +1122,9 @@ slap_acl_mask( char accessmaskbuf[ACCESSMASK_MAXLEN]; #endif /* DEBUG */ const char *attr; - slap_mask_t a2pmask = ACL_ACCESS2PRIV( *mask ); +#ifdef SLAP_DYNACL + slap_mask_t a2pmask = ACL_ACCESS2PRIV( access ); +#endif /* SLAP_DYNACL */ assert( a != NULL ); assert( mask != NULL ); @@ -1107,7 +1169,7 @@ slap_acl_mask( * is maintained in a_dn_pat. */ - if ( acl_mask_dn( op, e, desc, val, a, nmatch, matches, + if ( acl_mask_dn( op, e, val, a, matches, &b->a_dn, &op->o_ndn ) ) { continue; @@ -1138,7 +1200,7 @@ slap_acl_mask( ndn = op->o_ndn; } - if ( acl_mask_dn( op, e, desc, val, a, nmatch, matches, + if ( acl_mask_dn( op, e, val, a, matches, &b->a_realdn, &ndn ) ) { continue; @@ -1154,8 +1216,8 @@ slap_acl_mask( if ( !ber_bvccmp( &b->a_sockurl_pat, '*' ) ) { if ( b->a_sockurl_style == ACL_STYLE_REGEX) { - if (!regex_matches( &b->a_sockurl_pat, op->o_conn->c_listener_url.bv_val, - e->e_ndn, nmatch, matches ) ) + if ( !regex_matches( &b->a_sockurl_pat, op->o_conn->c_listener_url.bv_val, + &e->e_nname, val, matches ) ) { continue; } @@ -1166,8 +1228,7 @@ slap_acl_mask( bv.bv_len = sizeof( buf ) - 1; bv.bv_val = buf; - if ( acl_string_expand( &bv, &b->a_sockurl_pat, - e->e_ndn, nmatch, matches ) ) + if ( acl_string_expand( &bv, &b->a_sockurl_pat, &e->e_nname, val, matches ) ) { continue; } @@ -1194,8 +1255,8 @@ slap_acl_mask( b->a_domain_pat.bv_val, 0, 0 ); if ( !ber_bvccmp( &b->a_domain_pat, '*' ) ) { if ( b->a_domain_style == ACL_STYLE_REGEX) { - if (!regex_matches( &b->a_domain_pat, op->o_conn->c_peer_domain.bv_val, - e->e_ndn, nmatch, matches ) ) + if ( !regex_matches( &b->a_domain_pat, op->o_conn->c_peer_domain.bv_val, + &e->e_nname, val, matches ) ) { continue; } @@ -1211,8 +1272,7 @@ slap_acl_mask( bv.bv_len = sizeof(buf) - 1; bv.bv_val = buf; - if ( acl_string_expand(&bv, &b->a_domain_pat, - e->e_ndn, nmatch, matches) ) + if ( acl_string_expand(&bv, &b->a_domain_pat, &e->e_nname, val, matches) ) { continue; } @@ -1249,8 +1309,8 @@ slap_acl_mask( b->a_peername_pat.bv_val, 0, 0 ); if ( !ber_bvccmp( &b->a_peername_pat, '*' ) ) { if ( b->a_peername_style == ACL_STYLE_REGEX ) { - if (!regex_matches( &b->a_peername_pat, op->o_conn->c_peer_name.bv_val, - e->e_ndn, nmatch, matches ) ) + if ( !regex_matches( &b->a_peername_pat, op->o_conn->c_peer_name.bv_val, + &e->e_nname, val, matches ) ) { continue; } @@ -1268,8 +1328,7 @@ slap_acl_mask( bv.bv_len = sizeof( buf ) - 1; bv.bv_val = buf; - if ( acl_string_expand( &bv, &b->a_peername_pat, - e->e_ndn, nmatch, matches ) ) + if ( acl_string_expand( &bv, &b->a_peername_pat, &e->e_nname, val, matches ) ) { continue; } @@ -1281,7 +1340,7 @@ slap_acl_mask( /* extract IP and try exact match */ } else if ( b->a_peername_style == ACL_STYLE_IP ) { char *port; - char buf[] = "255.255.255.255"; + char buf[STRLENOF("255.255.255.255") + 1]; struct berval ip; unsigned long addr; int port_number = -1; @@ -1326,7 +1385,7 @@ slap_acl_mask( /* extract IPv6 and try exact match */ } else if ( b->a_peername_style == ACL_STYLE_IPV6 ) { char *port; - char buf[] = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"; + char buf[STRLENOF("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF") + 1]; struct berval ip; struct in6_addr addr; int port_number = -1; @@ -1402,8 +1461,8 @@ slap_acl_mask( b->a_sockname_pat.bv_val, 0, 0 ); if ( !ber_bvccmp( &b->a_sockname_pat, '*' ) ) { if ( b->a_sockname_style == ACL_STYLE_REGEX) { - if (!regex_matches( &b->a_sockname_pat, op->o_conn->c_sock_name.bv_val, - e->e_ndn, nmatch, matches ) ) + if ( !regex_matches( &b->a_sockname_pat, op->o_conn->c_sock_name.bv_val, + &e->e_nname, val, matches ) ) { continue; } @@ -1414,8 +1473,7 @@ slap_acl_mask( bv.bv_len = sizeof( buf ) - 1; bv.bv_val = buf; - if ( acl_string_expand( &bv, &b->a_sockname_pat, - e->e_ndn, nmatch, matches ) ) + if ( acl_string_expand( &bv, &b->a_sockname_pat, &e->e_nname, val, matches ) ) { continue; } @@ -1433,8 +1491,8 @@ slap_acl_mask( } if ( b->a_dn_at != NULL ) { - if ( acl_mask_dnattr( op, e, val, a, b, i, - matches, count, state, + if ( acl_mask_dnattr( op, e, val, a, + count, state, mask, &b->a_dn, &op->o_ndn ) ) { continue; @@ -1451,8 +1509,8 @@ slap_acl_mask( ndn = op->o_ndn; } - if ( acl_mask_dnattr( op, e, val, a, b, i, - matches, count, state, + if ( acl_mask_dnattr( op, e, val, a, + count, state, mask, &b->a_realdn, &ndn ) ) { continue; @@ -1478,38 +1536,43 @@ slap_acl_mask( /* see if asker is listed in dnattr */ if ( b->a_group_style == ACL_STYLE_EXPAND ) { char buf[ACL_BUF_SIZE]; - int tmp_nmatch; - regmatch_t tmp_matches[2], - *tmp_matchesp = tmp_matches; + AclRegexMatches tmp_matches, + *tmp_matchesp = &tmp_matches; + regmatch_t *tmp_data; + + MATCHES_MEMSET( &tmp_matches ); + tmp_data = &tmp_matches.dn_data[0]; bv.bv_len = sizeof(buf) - 1; bv.bv_val = buf; rc = 0; - switch ( a->acl_dn_style ) { + if ( a->acl_attrval_style == ACL_STYLE_REGEX ) + tmp_matchesp = matches; + else 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; + tmp_data[0].rm_so = 0; + tmp_data[0].rm_eo = e->e_nname.bv_len; + tmp_matches.dn_count = 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; + 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; break; default: @@ -1523,8 +1586,8 @@ slap_acl_mask( } if ( acl_string_expand( &bv, &b->a_group_pat, - e->e_nname.bv_val, - tmp_nmatch, tmp_matchesp ) ) + &e->e_nname, val, + tmp_matchesp ) ) { continue; } @@ -1562,39 +1625,42 @@ slap_acl_mask( b->a_set_pat.bv_val, 0, 0 ); if ( b->a_set_style == ACL_STYLE_EXPAND ) { - int tmp_nmatch; - regmatch_t tmp_matches[2], - *tmp_matchesp = tmp_matches; + AclRegexMatches tmp_matches, + *tmp_matchesp = &tmp_matches; int rc = 0; + regmatch_t *tmp_data; + + MATCHES_MEMSET( &tmp_matches ); + tmp_data = &tmp_matches.dn_data[0]; bv.bv_len = sizeof( buf ) - 1; bv.bv_val = buf; rc = 0; - switch ( a->acl_dn_style ) { + if ( a->acl_attrval_style == ACL_STYLE_REGEX ) + tmp_matchesp = matches; + else 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; + tmp_data[0].rm_so = 0; + tmp_data[0].rm_eo = e->e_nname.bv_len; + tmp_matches.dn_count = 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; + 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; break; default: @@ -1608,8 +1674,8 @@ slap_acl_mask( } if ( acl_string_expand( &bv, &b->a_set_pat, - e->e_nname.bv_val, - tmp_nmatch, tmp_matchesp ) ) + &e->e_nname, val, + tmp_matchesp ) ) { continue; } @@ -1721,8 +1787,14 @@ slap_acl_mask( Debug( LDAP_DEBUG_ACL, " <= check a_dynacl: %s\n", da->da_name, 0, 0 ); + /* + * XXXmanu Only DN matches are supplied + * sending attribute values matches require + * an API update + */ (void)da->da_mask( da->da_private, op, e, desc, - val, nmatch, matches, &grant, &deny ); + val, matches->dn_count, matches->dn_data, + &grant, &deny ); tgrant |= grant; tdeny |= deny; @@ -1791,8 +1863,6 @@ slap_acl_mask( *mask = modmask; } - a2pmask = *mask; - Debug( LDAP_DEBUG_ACL, "<= acl_mask: [%d] mask: %s\n", i, accessmask2str(*mask, accessmaskbuf, 1), 0 ); @@ -1844,6 +1914,10 @@ acl_check_modlist( } assert( be != NULL ); + /* If ADD attribute checking is not enabled, just allow it */ + if ( op->o_tag == LDAP_REQ_ADD && !SLAP_DBACL_ADD( be )) + return 1; + /* short circuit root database access */ if ( be_isroot( op ) ) { Debug( LDAP_DEBUG_ACL, @@ -1853,7 +1927,7 @@ acl_check_modlist( } /* use backend default access if no backend acls */ - if( op->o_bd != NULL && op->o_bd->be_acl == NULL ) { + if( op->o_bd != NULL && op->o_bd->be_acl == NULL && frontendDB->be_acl == NULL ) { Debug( LDAP_DEBUG_ACL, "=> access_allowed: backend default %s access %s to \"%s\"\n", access2str( ACL_WRITE ), @@ -1933,7 +2007,7 @@ acl_check_modlist( if ( ! access_allowed( op, e, mlist->sml_desc, NULL, ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL, - NULL ) ) + &state ) ) { ret = 0; goto done; @@ -2032,6 +2106,10 @@ acl_set_cb_gather( Operation *op, SlapReply *rs ) for ( j = 0; !BER_BVISNULL( &rs->sr_attrs[ j ].an_name ); j++ ) { AttributeDescription *desc = rs->sr_attrs[ j ].an_desc; + + if ( desc == NULL ) { + continue; + } if ( desc == slap_schema.si_ad_entryDN ) { bvalsp = bvals; @@ -2043,19 +2121,14 @@ acl_set_cb_gather( Operation *op, SlapReply *rs ) a = attr_find( rs->sr_entry->e_attrs, desc ); if ( a != NULL ) { - int i; - - for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) - ; - bvalsp = a->a_nvals; } } - } - if ( bvalsp ) { - p->bvals = slap_set_join( p->cookie, p->bvals, - ( '|' | SLAP_SET_RREF ), bvalsp ); + if ( bvalsp ) { + p->bvals = slap_set_join( p->cookie, p->bvals, + ( '|' | SLAP_SET_RREF ), bvalsp ); + } } } else { @@ -2077,8 +2150,6 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de int nattrs = 0; slap_callback cb = { NULL, acl_set_cb_gather, NULL, NULL }; acl_set_gather_t p = { 0 }; - const char *text = NULL; - static struct berval defaultFilter_bv = BER_BVC( "(objectClass=*)" ); /* this routine needs to return the bervals instead of * plain strings, since syntax is not known. It should @@ -2090,6 +2161,10 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de rc = ldap_url_parse( name->bv_val, &ludp ); if ( rc != LDAP_URL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, + "%s acl_set_gather: unable to parse URL=\"%s\"\n", + cp->asc_op->o_log_prefix, name->bv_val, 0 ); + rc = LDAP_PROTOCOL_ERROR; goto url_done; } @@ -2098,6 +2173,10 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de { /* host part must be empty */ /* extensions parts must be empty */ + Debug( LDAP_DEBUG_TRACE, + "%s acl_set_gather: host/exts must be absent in URL=\"%s\"\n", + cp->asc_op->o_log_prefix, name->bv_val, 0 ); + rc = LDAP_PROTOCOL_ERROR; goto url_done; } @@ -2108,11 +2187,19 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de &op2.o_req_ndn, cp->asc_op->o_tmpmemctx ); BER_BVZERO( &op2.o_req_dn ); if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, + "%s acl_set_gather: DN=\"%s\" normalize failed\n", + cp->asc_op->o_log_prefix, ludp->lud_dn, 0 ); + goto url_done; } - op2.o_bd = select_backend( &op2.o_req_ndn, 0, 1 ); + op2.o_bd = select_backend( &op2.o_req_ndn, 1 ); if ( ( op2.o_bd == NULL ) || ( op2.o_bd->be_search == NULL ) ) { + Debug( LDAP_DEBUG_TRACE, + "%s acl_set_gather: no database could be selected for DN=\"%s\"\n", + cp->asc_op->o_log_prefix, op2.o_req_ndn.bv_val, 0 ); + rc = LDAP_NO_SUCH_OBJECT; goto url_done; } @@ -2121,35 +2208,46 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de if ( ludp->lud_filter ) { ber_str2bv_x( ludp->lud_filter, 0, 0, &op2.ors_filterstr, cp->asc_op->o_tmpmemctx ); + op2.ors_filter = str2filter_x( cp->asc_op, op2.ors_filterstr.bv_val ); + if ( op2.ors_filter == NULL ) { + Debug( LDAP_DEBUG_TRACE, + "%s acl_set_gather: unable to parse filter=\"%s\"\n", + cp->asc_op->o_log_prefix, op2.ors_filterstr.bv_val, 0 ); + + rc = LDAP_PROTOCOL_ERROR; + goto url_done; + } } else { - op2.ors_filterstr = defaultFilter_bv; + op2.ors_filterstr = *slap_filterstr_objectClass_pres; + op2.ors_filter = (Filter *)slap_filter_objectClass_pres; } - op2.ors_filter = str2filter_x( cp->asc_op, op2.ors_filterstr.bv_val ); - if ( op2.ors_filter == NULL ) { - rc = LDAP_PROTOCOL_ERROR; - goto url_done; - } /* Grab the scope */ op2.ors_scope = ludp->lud_scope; /* Grap the attributes */ if ( ludp->lud_attrs ) { + int i; + for ( ; ludp->lud_attrs[ nattrs ]; nattrs++ ) ; - anlistp = slap_sl_malloc( sizeof( AttributeName ) * ( nattrs + 2 ), + anlistp = slap_sl_calloc( sizeof( AttributeName ), nattrs + 2, cp->asc_op->o_tmpmemctx ); - for ( ; ludp->lud_attrs[ nattrs ]; nattrs++ ) { - ber_str2bv( ludp->lud_attrs[ nattrs ], 0, 0, &anlistp[ nattrs ].an_name ); - anlistp[ nattrs ].an_desc = NULL; - rc = slap_bv2ad( &anlistp[ nattrs ].an_name, - &anlistp[ nattrs ].an_desc, &text ); - if ( rc != LDAP_SUCCESS ) { - goto url_done; + for ( i = 0, nattrs = 0; ludp->lud_attrs[ i ]; i++ ) { + struct berval name; + AttributeDescription *desc = NULL; + const char *text = NULL; + + ber_str2bv( ludp->lud_attrs[ i ], 0, 0, &name ); + rc = slap_bv2ad( &name, &desc, &text ); + if ( rc == LDAP_SUCCESS ) { + anlistp[ nattrs ].an_name = name; + anlistp[ nattrs ].an_desc = desc; + nattrs++; } } @@ -2177,6 +2275,7 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de op2.ors_attrs = anlistp; op2.ors_attrsonly = 0; op2.o_private = cp->asc_op->o_private; + op2.o_extra = cp->asc_op->o_extra; cb.sc_private = &p; @@ -2186,8 +2285,8 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de } url_done:; - if ( op2.ors_filter ) { - filter_free_x( cp->asc_op, op2.ors_filter ); + if ( op2.ors_filter && op2.ors_filter != slap_filter_objectClass_pres ) { + filter_free_x( cp->asc_op, op2.ors_filter, 1 ); } if ( !BER_BVISNULL( &op2.o_req_ndn ) ) { slap_sl_free( op2.o_req_ndn.bv_val, cp->asc_op->o_tmpmemctx ); @@ -2251,7 +2350,7 @@ acl_match_set ( AclSetCookie cookie; if ( default_set_attribute == NULL ) { - ber_dupbv_x( &set, subj, op->o_tmpmemctx ); + set = *subj; } else { struct berval subjdn, ndn = BER_BVNULL; @@ -2300,7 +2399,9 @@ acl_match_set ( acl_set_gather, (SetCookie *)&cookie, &set, &op->o_ndn, &e->e_nname, NULL ) > 0 ); - slap_sl_free( set.bv_val, op->o_tmpmemctx ); + if ( set.bv_val != subj->bv_val ) { + slap_sl_free( set.bv_val, op->o_tmpmemctx ); + } } return(rc); @@ -2396,20 +2497,22 @@ int acl_string_expand( struct berval *bv, struct berval *pat, - char *match, - int nmatch, - regmatch_t *matches) + struct berval *dn_matches, + struct berval *val_matches, + AclRegexMatches *matches) { ber_len_t size; char *sp; char *dp; int flag; + enum { DN_FLAG, VAL_FLAG } tflag; size = 0; bv->bv_val[0] = '\0'; bv->bv_len--; /* leave space for lone $ */ flag = 0; + tflag = DN_FLAG; for ( dp = bv->bv_val, sp = pat->bv_val; size < bv->bv_len && sp < pat->bv_val + pat->bv_len ; sp++ ) { @@ -2419,11 +2522,21 @@ acl_string_expand( *dp++ = '$'; size++; flag = 0; + tflag = DN_FLAG; + + } else if ( flag == 2 && *sp == 'v' /*'}'*/) { + tflag = VAL_FLAG; + + } else if ( flag == 2 && *sp == 'd' /*'}'*/) { + tflag = DN_FLAG; } else if ( flag == 1 && *sp == '{' /*'}'*/) { flag = 2; } else if ( *sp >= '0' && *sp <= '9' ) { + int nm; + regmatch_t *m; + char *data; int n; int i; int l; @@ -2443,20 +2556,40 @@ acl_string_expand( } } - if ( n >= nmatch ) { + switch (tflag) { + case DN_FLAG: + nm = matches->dn_count; + m = matches->dn_data; + data = dn_matches ? dn_matches->bv_val : NULL; + break; + case VAL_FLAG: + nm = matches->val_count; + m = matches->val_data; + data = val_matches ? val_matches->bv_val : NULL; + break; + default: + assert( 0 ); + } + if ( n >= nm ) { + /* FIXME: error */ + return 1; + } + if ( data == NULL ) { /* FIXME: error */ return 1; } *dp = '\0'; - i = matches[n].rm_so; - l = matches[n].rm_eo; + i = m[n].rm_so; + l = m[n].rm_eo; + for ( ; size < bv->bv_len && i < l; size++, i++ ) { - *dp++ = match[i]; + *dp++ = data[i]; } *dp = '\0'; flag = 0; + tflag = DN_FLAG; } } else { if (*sp == '$') { @@ -2477,8 +2610,8 @@ acl_string_expand( *dp = '\0'; bv->bv_len = size; - Debug( LDAP_DEBUG_TRACE, "=> acl_string_expand: pattern: %.*s\n", (int)pat->bv_len, pat->bv_val, 0 ); - Debug( LDAP_DEBUG_TRACE, "=> acl_string_expand: expanded: %s\n", bv->bv_val, 0, 0 ); + Debug( LDAP_DEBUG_ACL, "=> acl_string_expand: pattern: %.*s\n", (int)pat->bv_len, pat->bv_val, 0 ); + Debug( LDAP_DEBUG_ACL, "=> acl_string_expand: expanded: %s\n", bv->bv_val, 0, 0 ); return 0; } @@ -2487,9 +2620,9 @@ static int regex_matches( struct berval *pat, /* pattern to expand and match against */ char *str, /* string to match against pattern */ - char *buf, /* buffer with $N expansion variables */ - int nmatch, /* size of the matches array */ - regmatch_t *matches /* offsets in buffer for $N expansion variables */ + struct berval *dn_matches, /* buffer with $N expansion variables from DN */ + struct berval *val_matches, /* buffer with $N expansion variables from val */ + AclRegexMatches *matches /* offsets in buffer for $N expansion variables */ ) { regex_t re; @@ -2504,7 +2637,7 @@ regex_matches( str = ""; }; - acl_string_expand( &bv, pat, buf, nmatch, matches ); + acl_string_expand( &bv, pat, dn_matches, val_matches, matches ); rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE ); if ( rc ) { char error[ACL_BUF_SIZE];