- if ( aci_match_set( &bv, op, e, 0 ) == 0 ) {
- continue;
- }
- }
-
- if ( b->a_authz.sai_ssf ) {
- Debug( LDAP_DEBUG_ACL, "<= check a_authz.sai_ssf: ACL %u > OP %u\n",
- b->a_authz.sai_ssf, op->o_ssf, 0 );
- if ( b->a_authz.sai_ssf > op->o_ssf ) {
- continue;
- }
- }
-
- if ( b->a_authz.sai_transport_ssf ) {
- Debug( LDAP_DEBUG_ACL,
- "<= check a_authz.sai_transport_ssf: ACL %u > OP %u\n",
- b->a_authz.sai_transport_ssf, op->o_transport_ssf, 0 );
- if ( b->a_authz.sai_transport_ssf > op->o_transport_ssf ) {
- continue;
- }
- }
-
- if ( b->a_authz.sai_tls_ssf ) {
- Debug( LDAP_DEBUG_ACL,
- "<= check a_authz.sai_tls_ssf: ACL %u > OP %u\n",
- b->a_authz.sai_tls_ssf, op->o_tls_ssf, 0 );
- if ( b->a_authz.sai_tls_ssf > op->o_tls_ssf ) {
- continue;
- }
- }
-
- if ( b->a_authz.sai_sasl_ssf ) {
- Debug( LDAP_DEBUG_ACL,
- "<= check a_authz.sai_sasl_ssf: ACL %u > OP %u\n",
- b->a_authz.sai_sasl_ssf, op->o_sasl_ssf, 0 );
- if ( b->a_authz.sai_sasl_ssf > op->o_sasl_ssf ) {
- continue;
- }
- }
-
-#ifdef SLAP_DYNACL
- if ( b->a_dynacl ) {
- slap_dynacl_t *da;
- slap_access_t tgrant, tdeny;
-
- /* this case works different from the others above.
- * since aci's themselves give permissions, we need
- * to first check b->a_access_mask, the ACL's access level.
- */
- if ( BER_BVISEMPTY( &e->e_nname ) ) {
- /* no ACIs in the root DSE */
- continue;
- }
-
- /* first check if the right being requested
- * is allowed by the ACL clause.
- */
- if ( ! ACL_GRANT( b->a_access_mask, *mask ) ) {
- continue;
- }
-
- /* start out with nothing granted, nothing denied */
- ACL_INIT(tgrant);
- ACL_INIT(tdeny);
-
- for ( da = b->a_dynacl; da; da = da->da_next ) {
- slap_access_t grant, deny;
-
- (void)( *da->da_mask )( da->da_private, op, e, desc, val, nmatch, matches, &grant, &deny );
-
- tgrant |= grant;
- tdeny |= deny;
- }
-
- /* remove anything that the ACL clause does not allow */
- tgrant &= b->a_access_mask & ACL_PRIV_MASK;
- tdeny &= ACL_PRIV_MASK;
-
- /* see if we have anything to contribute */
- if( ACL_IS_INVALID(tgrant) && ACL_IS_INVALID(tdeny) ) {
- continue;
- }
-
- /* this could be improved by changing acl_mask so that it can deal with
- * by clauses that return grant/deny pairs. Right now, it does either
- * additive or subtractive rights, but not both at the same time. So,
- * we need to combine the grant/deny pair into a single rights mask in
- * a smart way: if either grant or deny is "empty", then we use the
- * opposite as is, otherwise we remove any denied rights from the grant
- * rights mask and construct an additive mask.
- */
- if (ACL_IS_INVALID(tdeny)) {
- modmask = tgrant | ACL_PRIV_ADDITIVE;
-
- } else if (ACL_IS_INVALID(tgrant)) {
- modmask = tdeny | ACL_PRIV_SUBSTRACTIVE;
-
- } else {
- modmask = (tgrant & ~tdeny) | ACL_PRIV_ADDITIVE;
- }
-
- } else
-#else /* !SLAP_DYNACL */
-
-#ifdef SLAPD_ACI_ENABLED
- if ( b->a_aci_at != NULL ) {
- Attribute *at;
- slap_access_t grant, deny, tgrant, tdeny;
- struct berval parent_ndn;
- BerVarray bvals = NULL;
- int ret, stop;
-
- /* this case works different from the others above.
- * since aci's themselves give permissions, we need
- * to first check b->a_access_mask, the ACL's access level.
- */
-
- if ( BER_BVISEMPTY( &e->e_nname ) ) {
- /* no ACIs in the root DSE */
- continue;
- }
-
- /* first check if the right being requested
- * is allowed by the ACL clause.
- */
- if ( ! ACL_GRANT( b->a_access_mask, *mask ) ) {
- continue;
- }
- /* start out with nothing granted, nothing denied */
- ACL_INIT(tgrant);
- ACL_INIT(tdeny);
-
- /* get the aci attribute */
- at = attr_find( e->e_attrs, b->a_aci_at );
- if ( at != NULL ) {
-#if 0
- /* FIXME: this breaks acl caching;
- * see also ACL_RECORD_VALUE_STATE below */
- ACL_RECORD_VALUE_STATE;
-#endif
- /* the aci is an multi-valued attribute. The
- * rights are determined by OR'ing the individual
- * rights given by the acis.
- */
- for ( i = 0; !BER_BVISNULL( &at->a_nvals[i] ); i++ ) {
- if (aci_mask( op,
- e, desc, val,
- &at->a_nvals[i],
- nmatch, matches,
- &grant, &deny, SLAP_ACI_SCOPE_ENTRY ) != 0)
- {
- tgrant |= grant;
- tdeny |= deny;
- }
- }
- Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
- accessmask2str(tgrant, accessmaskbuf, 1),
- accessmask2str(tdeny, accessmaskbuf1, 1), 0);
-
- }
- /* If the entry level aci didn't contain anything valid for the
- * current operation, climb up the tree and evaluate the
- * acis with scope set to subtree
- */
- if ( (tgrant == ACL_PRIV_NONE) && (tdeny == ACL_PRIV_NONE) ) {
- dnParent( &e->e_nname, &parent_ndn );
- while ( !BER_BVISEMPTY( &parent_ndn ) ) {
- Debug(LDAP_DEBUG_ACL, "checking ACI of %s\n", parent_ndn.bv_val, 0, 0);
- ret = backend_attribute(op, NULL, &parent_ndn, b->a_aci_at, &bvals, ACL_AUTH);
- switch(ret){
- case LDAP_SUCCESS :
- stop = 0;
- if (!bvals){
- break;
- }
-
- for( i = 0; bvals[i].bv_val != NULL; i++){
-#if 0
- /* FIXME: this breaks acl caching;
- * see also ACL_RECORD_VALUE_STATE above */
- ACL_RECORD_VALUE_STATE;
-#endif
- if (aci_mask(op, e, desc, val, &bvals[i],
- nmatch, matches,
- &grant, &deny, SLAP_ACI_SCOPE_CHILDREN ) != 0 )
- {
- tgrant |= grant;
- tdeny |= deny;
- /* evaluation stops as soon as either a "deny" or a
- * "grant" directive matches.
- */
- if( (tgrant != ACL_PRIV_NONE) || (tdeny != ACL_PRIV_NONE) ){
- stop = 1;
- }
- }
- Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
- accessmask2str(tgrant, accessmaskbuf, 1),
- accessmask2str(tdeny, accessmaskbuf1, 1), 0);
- }
- break;
-
- case LDAP_NO_SUCH_ATTRIBUTE:
- /* just go on if the aci-Attribute is not present in
- * the current entry
- */
- Debug(LDAP_DEBUG_ACL, "no such attribute\n", 0, 0, 0);
- stop = 0;
- break;
-
- case LDAP_NO_SUCH_OBJECT:
- /* We have reached the base object */
- Debug(LDAP_DEBUG_ACL, "no such object\n", 0, 0, 0);
- stop = 1;
- break;
-
- default:
- stop = 1;
- break;
- }
- if (stop){
- break;
- }
- dnParent( &parent_ndn, &parent_ndn );
- }
- }
-
-
- /* remove anything that the ACL clause does not allow */
- tgrant &= b->a_access_mask & ACL_PRIV_MASK;
- tdeny &= ACL_PRIV_MASK;
-
- /* see if we have anything to contribute */
- if( ACL_IS_INVALID(tgrant) && ACL_IS_INVALID(tdeny) ) {
- continue;
- }
-
- /* this could be improved by changing acl_mask so that it can deal with
- * by clauses that return grant/deny pairs. Right now, it does either
- * additive or subtractive rights, but not both at the same time. So,
- * we need to combine the grant/deny pair into a single rights mask in
- * a smart way: if either grant or deny is "empty", then we use the
- * opposite as is, otherwise we remove any denied rights from the grant
- * rights mask and construct an additive mask.
- */
- if (ACL_IS_INVALID(tdeny)) {
- modmask = tgrant | ACL_PRIV_ADDITIVE;
-
- } else if (ACL_IS_INVALID(tgrant)) {
- modmask = tdeny | ACL_PRIV_SUBSTRACTIVE;
-
- } else {
- modmask = (tgrant & ~tdeny) | ACL_PRIV_ADDITIVE;
- }
-
- } else
-#endif /* SLAPD_ACI_ENABLED */
-#endif /* !SLAP_DYNACL */
- {
- modmask = b->a_access_mask;
- }
-
- Debug( LDAP_DEBUG_ACL,
- "<= acl_mask: [%d] applying %s (%s)\n",
- i, accessmask2str( modmask, accessmaskbuf, 1 ),
- b->a_type == ACL_CONTINUE
- ? "continue"
- : b->a_type == ACL_BREAK
- ? "break"
- : "stop" );
- /* save old mask */
- oldmask = *mask;
-
- if( ACL_IS_ADDITIVE(modmask) ) {
- /* add privs */
- ACL_PRIV_SET( *mask, modmask );
-
- /* cleanup */
- ACL_PRIV_CLR( *mask, ~ACL_PRIV_MASK );
-
- } else if( ACL_IS_SUBTRACTIVE(modmask) ) {
- /* substract privs */
- ACL_PRIV_CLR( *mask, modmask );
-
- /* cleanup */
- ACL_PRIV_CLR( *mask, ~ACL_PRIV_MASK );
-
- } else {
- /* assign privs */
- *mask = modmask;
- }
-
- Debug( LDAP_DEBUG_ACL,
- "<= acl_mask: [%d] mask: %s\n",
- i, accessmask2str(*mask, accessmaskbuf, 1), 0 );
-
- if( b->a_type == ACL_CONTINUE ) {
- continue;
-
- } else if ( b->a_type == ACL_BREAK ) {
- return ACL_BREAK;
-
- } else {
- return ACL_STOP;
- }
- }
-
- /* implicit "by * none" clause */
- ACL_INIT(*mask);
-
- Debug( LDAP_DEBUG_ACL,
- "<= acl_mask: no more <who> clauses, returning %s (stop)\n",
- accessmask2str(*mask, accessmaskbuf, 1), 0, 0 );
- return ACL_STOP;
-}
-
-/*
- * acl_check_modlist - check access control on the given entry to see if
- * it allows the given modifications by the user associated with op.
- * returns 1 if mods allowed ok
- * 0 mods not allowed
- */
-
-int
-acl_check_modlist(
- Operation *op,
- Entry *e,
- Modifications *mlist
-)
-{
- struct berval *bv;
- AccessControlState state = ACL_STATE_INIT;
- Backend *be;
- int be_null = 0;
- int ret = 1; /* default is access allowed */
-
- be = op->o_bd;
- if ( be == NULL ) {
- be = LDAP_STAILQ_FIRST(&backendDB);
- be_null = 1;
- op->o_bd = be;
- }
- assert( be != NULL );
-
- /* short circuit root database access */
- if ( be_isroot( op ) ) {
- Debug( LDAP_DEBUG_ACL,
- "<= acl_access_allowed: granted to database root\n",
- 0, 0, 0 );
- goto done;
- }
-
- /* use backend default access if no backend acls */
- if( op->o_bd != NULL && op->o_bd->be_acl == NULL ) {
- Debug( LDAP_DEBUG_ACL,
- "=> access_allowed: backend default %s access %s to \"%s\"\n",
- access2str( ACL_WRITE ),
- op->o_bd->be_dfltaccess >= ACL_WRITE
- ? "granted" : "denied",
- op->o_dn.bv_val );
- ret = (op->o_bd->be_dfltaccess >= ACL_WRITE);
- goto done;
- }
-
- for ( ; mlist != NULL; mlist = mlist->sml_next ) {
- /*
- * no-user-modification operational attributes are ignored
- * by ACL_WRITE checking as any found here are not provided
- * by the user
- */
- if ( is_at_no_user_mod( mlist->sml_desc->ad_type ) ) {
- Debug( LDAP_DEBUG_ACL, "acl: no-user-mod %s:"
- " modify access granted\n",
- mlist->sml_desc->ad_cname.bv_val, 0, 0 );
- continue;
- }
-
- switch ( mlist->sml_op ) {
- case LDAP_MOD_REPLACE:
- /*
- * We must check both permission to delete the whole
- * attribute and permission to add the specific attributes.
- * This prevents abuse from selfwriters.
- */
- if ( ! access_allowed( op, e,
- mlist->sml_desc, NULL, ACL_WRITE, &state ) )
- {
- ret = 0;
- goto done;
- }
-
- if ( mlist->sml_values == NULL ) break;
-
- /* fall thru to check value to add */
-
- case LDAP_MOD_ADD:
- assert( mlist->sml_values != NULL );
-
- for ( bv = mlist->sml_nvalues
- ? mlist->sml_nvalues : mlist->sml_values;
- bv->bv_val != NULL; bv++ )
- {
- if ( ! access_allowed( op, e,
- mlist->sml_desc, bv, ACL_WRITE, &state ) )
- {
- ret = 0;
- goto done;
- }
- }
- break;
-
- case LDAP_MOD_DELETE:
- if ( mlist->sml_values == NULL ) {
- if ( ! access_allowed( op, e,
- mlist->sml_desc, NULL, ACL_WRITE, NULL ) )
- {
- ret = 0;
- goto done;
- }
- break;
- }
- for ( bv = mlist->sml_nvalues
- ? mlist->sml_nvalues : mlist->sml_values;
- bv->bv_val != NULL; bv++ )
- {
- if ( ! access_allowed( op, e,
- mlist->sml_desc, bv, ACL_WRITE, &state ) )
- {
- ret = 0;
- goto done;
- }
- }
- break;
-
- case SLAP_MOD_SOFTADD:
- /* allow adding attribute via modrdn thru */
- break;
-
- default:
- assert( 0 );
- /* not reached */
- ret = 0;
- break;
- }
- }
-
-done:
- if (be_null) op->o_bd = NULL;
- return( ret );
-}
-
-static int
-aci_get_part(
- struct berval *list,
- int ix,
- char sep,
- struct berval *bv )
-{
- int len;
- char *p;
-
- if ( bv ) {
- BER_BVZERO( bv );
- }
- len = list->bv_len;
- p = list->bv_val;
- while ( len >= 0 && --ix >= 0 ) {
- while ( --len >= 0 && *p++ != sep )
- ;
- }
- while ( len >= 0 && *p == ' ' ) {
- len--;
- p++;
- }
- if ( len < 0 ) {
- return -1;
- }
-
- if ( !bv ) {
- return 0;
- }
-
- bv->bv_val = p;
- while ( --len >= 0 && *p != sep ) {
- bv->bv_len++;
- p++;
- }
- while ( bv->bv_len > 0 && *--p == ' ' ) {
- bv->bv_len--;
- }
-
- return bv->bv_len;
-}
-
-typedef struct aci_set_gather_t {
- SetCookie *cookie;
- BerVarray bvals;
-} aci_set_gather_t;
-
-static int
-aci_set_cb_gather( Operation *op, SlapReply *rs )
-{
- aci_set_gather_t *p = (aci_set_gather_t *)op->o_callback->sc_private;
-
- if ( rs->sr_type == REP_SEARCH ) {
- BerValue bvals[ 2 ];
- BerVarray bvalsp = NULL;
- int j;
-
- for ( j = 0; !BER_BVISNULL( &rs->sr_attrs[ j ].an_name ); j++ ) {
- AttributeDescription *desc = rs->sr_attrs[ j ].an_desc;
-
- if ( desc == slap_schema.si_ad_entryDN ) {
- bvalsp = bvals;
- bvals[ 0 ] = rs->sr_entry->e_nname;
- BER_BVZERO( &bvals[ 1 ] );
-
- } else {
- Attribute *a;
-
- 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 ( bvals ) {
- p->bvals = slap_set_join( p->cookie, p->bvals,
- ( '|' | SLAP_SET_RREF ), bvalsp );
- }
-
- } else {
- assert( rs->sr_type == REP_RESULT );
- }
-
- return 0;
-}
-
-BerVarray
-aci_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *desc )
-{
- AciSetCookie *cp = (AciSetCookie *)cookie;
- int rc = 0;
- LDAPURLDesc *ludp = NULL;
- Operation op2 = { 0 };
- SlapReply rs = {REP_RESULT};
- AttributeName anlist[ 2 ], *anlistp = NULL;
- int nattrs = 0;
- slap_callback cb = { NULL, aci_set_cb_gather, NULL, NULL };
- aci_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
- * also return the syntax or some "comparison cookie".
- */
- if ( strncasecmp( name->bv_val, "ldap:///", STRLENOF( "ldap:///" ) ) != 0 ) {
- return aci_set_gather2( cookie, name, desc );
- }
-
- rc = ldap_url_parse( name->bv_val, &ludp );
- if ( rc != LDAP_URL_SUCCESS ) {
- rc = LDAP_PROTOCOL_ERROR;
- goto url_done;
- }
-
- if ( ( ludp->lud_host && ludp->lud_host[0] ) || ludp->lud_exts )
- {
- /* host part must be empty */
- /* extensions parts must be empty */
- rc = LDAP_PROTOCOL_ERROR;
- goto url_done;
- }
-
- /* Grab the searchbase and see if an appropriate database can be found */
- ber_str2bv( ludp->lud_dn, 0, 0, &op2.o_req_dn );
- rc = dnNormalize( 0, NULL, NULL, &op2.o_req_dn,
- &op2.o_req_ndn, cp->op->o_tmpmemctx );
- BER_BVZERO( &op2.o_req_dn );
- if ( rc != LDAP_SUCCESS ) {
- goto url_done;
- }
-
- op2.o_bd = select_backend( &op2.o_req_ndn, 0, 1 );
- if ( ( op2.o_bd == NULL ) || ( op2.o_bd->be_search == NULL ) ) {
- rc = LDAP_NO_SUCH_OBJECT;
- goto url_done;
- }
-
- /* Grab the filter */
- if ( ludp->lud_filter ) {
- ber_str2bv_x( ludp->lud_filter, 0, 0, &op2.ors_filterstr,
- cp->op->o_tmpmemctx );
-
- } else {
- op2.ors_filterstr = defaultFilter_bv;
- }
-
- op2.ors_filter = str2filter_x( cp->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 ) {
- for ( ; ludp->lud_attrs[ nattrs ]; nattrs++ )
- ;