X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fbackend.c;h=7e0dbce7d99f9a6648ecc5c486afdb40fd6ea947;hb=e841247c9086053d774d66e4fbb058d0ead706b2;hp=02e41b82ad1c286bd960b76a67be9e6648b5b033;hpb=ff89b2c14c38216f58fed97efb5b720131c85c39;p=openldap diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 02e41b82ad..7e0dbce7d9 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2005 The OpenLDAP Foundation. + * Copyright 1998-2009 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,20 +34,10 @@ #include #include "slap.h" +#include "config.h" #include "lutil.h" #include "lber_pvt.h" -#include "ldap_rq.h" - -#ifdef LDAP_SLAPI -#include "slapi/slapi.h" - -static void init_group_pblock( Operation *op, Entry *target, - Entry *e, struct berval *op_ndn, AttributeDescription *group_at ); -static int call_group_preop_plugins( Operation *op ); -static void call_group_postop_plugins( Operation *op ); -#endif /* LDAP_SLAPI */ - /* * If a module is configured as dynamic, its header should not * get included into slapd. While this is a general rule and does @@ -57,13 +47,10 @@ static void call_group_postop_plugins( Operation *op ); */ int nBackendInfo = 0; -BackendInfo *backendInfo = NULL; +slap_bi_head backendInfo = LDAP_STAILQ_HEAD_INITIALIZER(backendInfo); int nBackendDB = 0; -BackendDB *backendDB = NULL; - -ldap_pvt_thread_pool_t syncrepl_pool; -int syncrepl_pool_max = SLAP_MAX_SYNCREPL_THREADS; +slap_be_head backendDB = LDAP_STAILQ_HEAD_INITIALIZER(backendDB); static int backend_init_controls( BackendInfo *bi ) @@ -94,28 +81,24 @@ backend_init_controls( BackendInfo *bi ) int backend_init(void) { int rc = -1; + BackendInfo *bi; - ldap_pvt_thread_pool_init( &syncrepl_pool, syncrepl_pool_max, 0 ); - - if((nBackendInfo != 0) || (backendInfo != NULL)) { + if((nBackendInfo != 0) || !LDAP_STAILQ_EMPTY(&backendInfo)) { /* already initialized */ Debug( LDAP_DEBUG_ANY, "backend_init: already initialized\n", 0, 0, 0 ); return -1; } - for( ; - slap_binfo[nBackendInfo].bi_type != NULL; - nBackendInfo++ ) - { - assert( slap_binfo[nBackendInfo].bi_init ); + for( bi=slap_binfo; bi->bi_type != NULL; bi++,nBackendInfo++ ) { + assert( bi->bi_init != 0 ); - rc = slap_binfo[nBackendInfo].bi_init( &slap_binfo[nBackendInfo] ); + rc = bi->bi_init( bi ); if(rc != 0) { Debug( LDAP_DEBUG_ANY, "backend_init: initialized for type \"%s\"\n", - slap_binfo[nBackendInfo].bi_type, 0, 0 ); + bi->bi_type, 0, 0 ); /* destroy those we've already inited */ for( nBackendInfo--; nBackendInfo >= 0 ; @@ -128,10 +111,11 @@ int backend_init(void) } return rc; } + + LDAP_STAILQ_INSERT_TAIL(&backendInfo, bi, bi_next); } if ( nBackendInfo > 0) { - backendInfo = slap_binfo; return 0; } @@ -169,85 +153,82 @@ int backend_add(BackendInfo *aBackendInfo) (void)backend_init_controls( aBackendInfo ); /* now add the backend type to the Backend Info List */ - { - BackendInfo *newBackendInfo = 0; + LDAP_STAILQ_INSERT_TAIL( &backendInfo, aBackendInfo, bi_next ); + nBackendInfo++; + return 0; +} - /* if backendInfo == slap_binfo no deallocation of old backendInfo */ - if (backendInfo == slap_binfo) { - newBackendInfo = ch_calloc(nBackendInfo + 1, sizeof(BackendInfo)); - AC_MEMCPY(newBackendInfo, backendInfo, - sizeof(BackendInfo) * nBackendInfo); +static int +backend_set_controls( BackendDB *be ) +{ + BackendInfo *bi = be->bd_info; + + /* back-relay takes care of itself; so may do other */ + if ( overlay_is_over( be ) ) { + bi = ((slap_overinfo *)be->bd_info->bi_private)->oi_orig; + } + + if ( bi->bi_controls ) { + if ( be->be_ctrls[ SLAP_MAX_CIDS ] == 0 ) { + AC_MEMCPY( be->be_ctrls, bi->bi_ctrls, + sizeof( be->be_ctrls ) ); + be->be_ctrls[ SLAP_MAX_CIDS ] = 1; + } else { - newBackendInfo = ch_realloc(backendInfo, - sizeof(BackendInfo) * (nBackendInfo + 1)); + int i; + + for ( i = 0; i < SLAP_MAX_CIDS; i++ ) { + if ( bi->bi_ctrls[ i ] ) { + be->be_ctrls[ i ] = bi->bi_ctrls[ i ]; + } + } } - AC_MEMCPY(&newBackendInfo[nBackendInfo], aBackendInfo, - sizeof(BackendInfo)); - backendInfo = newBackendInfo; - nBackendInfo++; - return 0; } + + return 0; } /* startup a specific backend database */ -int backend_startup_one(Backend *be) +int backend_startup_one(Backend *be, ConfigReply *cr) { int rc = 0; - BackendInfo *bi = be->bd_info; - assert(be); + assert( be != NULL ); be->be_pending_csn_list = (struct be_pcl *) - ch_calloc( 1, sizeof( struct be_pcl )); + ch_calloc( 1, sizeof( struct be_pcl ) ); LDAP_TAILQ_INIT( be->be_pending_csn_list ); - /* back-relay takes care of itself; so may do other */ - if ( be->be_ctrls[ SLAP_MAX_CIDS ] == 0 ) { - if ( overlay_is_over( be ) ) { - bi = ((slap_overinfo *)be->bd_info->bi_private)->oi_orig; - } - - if ( bi->bi_controls ) { - AC_MEMCPY( be->be_ctrls, bi->bi_ctrls, sizeof( be->be_ctrls ) ); - } - - be->be_ctrls[ SLAP_MAX_CIDS ] = 1; - } - Debug( LDAP_DEBUG_TRACE, "backend_startup_one: starting \"%s\"\n", be->be_suffix ? be->be_suffix[0].bv_val : "(unknown)", 0, 0 ); - if ( be->bd_info->bi_db_open ) { - rc = be->bd_info->bi_db_open( be ); - if ( rc != 0 ) { - Debug( LDAP_DEBUG_ANY, - "backend_startup_one: bi_db_open failed! (%d)\n", - rc, 0, 0 ); - } - } - /* back-relay takes care of itself; so may do other */ - bi = be->bd_info; - if ( overlay_is_over( be ) ) { - bi = ((slap_overinfo *)be->bd_info->bi_private)->oi_orig; + /* set database controls */ + (void)backend_set_controls( be ); + +#if 0 + if ( !BER_BVISEMPTY( &be->be_rootndn ) + && select_backend( &be->be_rootndn, 0 ) == be + && BER_BVISNULL( &be->be_rootpw ) ) + { + /* warning: if rootdn entry is created, + * it can take rootdn privileges; + * set empty rootpw to prevent */ } +#endif - if ( bi->bi_controls ) { - if ( be->be_ctrls[ SLAP_MAX_CIDS ] == 0 ) { - AC_MEMCPY( be->be_ctrls, bi->bi_ctrls, sizeof( be->be_ctrls ) ); - be->be_ctrls[ SLAP_MAX_CIDS ] = 1; + if ( be->bd_info->bi_db_open ) { + rc = be->bd_info->bi_db_open( be, cr ); + if ( rc == 0 ) { + (void)backend_set_controls( be ); } else { - int i; - - for ( i = 0; i < SLAP_MAX_CIDS; i++ ) { - if ( bi->bi_ctrls[ i ] ) { - be->be_ctrls[ i ] = 1; - } - } + Debug( LDAP_DEBUG_ANY, + "backend_startup_one: bi_db_open failed! (%d)\n", + rc, 0, 0 ); } } @@ -258,6 +239,8 @@ int backend_startup(Backend *be) { int i; int rc = 0; + BackendInfo *bi; + ConfigReply cr={0, ""}; if( ! ( nBackendDB > 0 ) ) { /* no databases */ @@ -279,12 +262,12 @@ int backend_startup(Backend *be) } } - return backend_startup_one( be ); + return backend_startup_one( be, &cr ); } /* open frontend, if required */ if ( frontendDB->bd_info->bi_db_open ) { - rc = frontendDB->bd_info->bi_db_open( frontendDB ); + rc = frontendDB->bd_info->bi_db_open( frontendDB, &cr ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "backend_startup: bi_db_open(frontend) failed! (%d)\n", @@ -294,66 +277,41 @@ int backend_startup(Backend *be) } /* open each backend type */ - for( i = 0; i < nBackendInfo; i++ ) { - if( backendInfo[i].bi_nDB == 0) { + i = -1; + LDAP_STAILQ_FOREACH(bi, &backendInfo, bi_next) { + i++; + if( bi->bi_nDB == 0) { /* no database of this type, don't open */ continue; } - if( backendInfo[i].bi_open ) { - rc = backendInfo[i].bi_open( &backendInfo[i] ); + if( bi->bi_open ) { + rc = bi->bi_open( bi ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, - "backend_startup: bi_open %d failed!\n", - i, 0, 0 ); + "backend_startup: bi_open %d (%s) failed!\n", + i, bi->bi_type, 0 ); return rc; } } - (void)backend_init_controls( &backendInfo[i] ); + (void)backend_init_controls( bi ); } - ldap_pvt_thread_mutex_init( &slapd_rq.rq_mutex ); - LDAP_STAILQ_INIT( &slapd_rq.task_list ); - LDAP_STAILQ_INIT( &slapd_rq.run_list ); - /* open each backend database */ - for( i = 0; i < nBackendDB; i++ ) { - if ( backendDB[i].be_suffix == NULL ) { + i = -1; + LDAP_STAILQ_FOREACH(be, &backendDB, be_next) { + i++; + if ( be->be_suffix == NULL ) { Debug( LDAP_DEBUG_ANY, "backend_startup: warning, database %d (%s) " "has no suffix\n", - i, backendDB[i].bd_info->bi_type, 0 ); + i, be->bd_info->bi_type, 0 ); } - /* append global access controls */ - acl_append( &backendDB[i].be_acl, frontendDB->be_acl ); - rc = backend_startup_one( &backendDB[i] ); + rc = backend_startup_one( be, &cr ); if ( rc ) return rc; - - - if ( backendDB[i].be_syncinfo ) { - syncinfo_t *si; - - if ( !( backendDB[i].be_search && backendDB[i].be_add && - backendDB[i].be_modify && backendDB[i].be_delete )) { - Debug( LDAP_DEBUG_ANY, - "backend_startup: database(%d) does not support " - "operations required for syncrepl", i, 0, 0 ); - continue; - } - - { - si = backendDB[i].be_syncinfo; - si->si_be = &backendDB[i]; - init_syncrepl( si ); - ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); - ldap_pvt_runqueue_insert( &slapd_rq, - si->si_interval, do_syncrepl, (void *) si ); - ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); - } - } } return rc; @@ -361,20 +319,22 @@ int backend_startup(Backend *be) int backend_num( Backend *be ) { - int i; + int i = 0; + BackendDB *b2; if( be == NULL ) return -1; - for( i = 0; i < nBackendDB; i++ ) { - if( be == &backendDB[i] ) return i; + LDAP_STAILQ_FOREACH( b2, &backendDB, be_next ) { + if( be == b2 ) return i; + i++; } return -1; } int backend_shutdown( Backend *be ) { - int i; int rc = 0; + BackendInfo *bi; if( be != NULL ) { /* shutdown a specific backend database */ @@ -385,46 +345,46 @@ int backend_shutdown( Backend *be ) } if ( be->bd_info->bi_db_close ) { - be->bd_info->bi_db_close( be ); + rc = be->bd_info->bi_db_close( be, NULL ); + if ( rc ) return rc; } if( be->bd_info->bi_close ) { - be->bd_info->bi_close( be->bd_info ); + rc = be->bd_info->bi_close( be->bd_info ); + if ( rc ) return rc; } return 0; } /* close each backend database */ - for( i = 0; i < nBackendDB; i++ ) { - if ( backendDB[i].bd_info->bi_db_close ) { - backendDB[i].bd_info->bi_db_close( - &backendDB[i] ); + LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { + if ( be->bd_info->bi_db_close ) { + be->bd_info->bi_db_close( be, NULL ); } if(rc != 0) { Debug( LDAP_DEBUG_ANY, "backend_close: bi_db_close %s failed!\n", - backendDB[i].be_type, 0, 0 ); + be->be_type, 0, 0 ); } } /* close each backend type */ - for( i = 0; i < nBackendInfo; i++ ) { - if( backendInfo[i].bi_nDB == 0 ) { + LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next ) { + if( bi->bi_nDB == 0 ) { /* no database of this type */ continue; } - if( backendInfo[i].bi_close ) { - backendInfo[i].bi_close( - &backendInfo[i] ); + if( bi->bi_close ) { + bi->bi_close( bi ); } } /* close frontend, if required */ if ( frontendDB->bd_info->bi_db_close ) { - rc = frontendDB->bd_info->bi_db_close ( frontendDB ); + rc = frontendDB->bd_info->bi_db_close ( frontendDB, NULL ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "backend_startup: bi_db_close(frontend) failed! (%d)\n", @@ -435,73 +395,99 @@ int backend_shutdown( Backend *be ) return 0; } -int backend_destroy(void) +/* + * This function is supposed to be the exact counterpart + * of backend_startup_one(), although this one calls bi_db_destroy() + * while backend_startup_one() calls bi_db_open(). + * + * Make sure backend_stopdown_one() destroys resources allocated + * by backend_startup_one(); only call backend_destroy_one() when + * all stuff in a BackendDB needs to be destroyed + */ +void +backend_stopdown_one( BackendDB *bd ) { - int i; - BackendDB *bd; - struct slap_csn_entry *csne; + if ( bd->be_pending_csn_list ) { + struct slap_csn_entry *csne; + csne = LDAP_TAILQ_FIRST( bd->be_pending_csn_list ); + while ( csne ) { + struct slap_csn_entry *tmp_csne = csne; - ldap_pvt_thread_pool_destroy( &syncrepl_pool, 1 ); + LDAP_TAILQ_REMOVE( bd->be_pending_csn_list, csne, ce_csn_link ); + ch_free( csne->ce_csn.bv_val ); + csne = LDAP_TAILQ_NEXT( csne, ce_csn_link ); + ch_free( tmp_csne ); + } + ch_free( bd->be_pending_csn_list ); + } - /* destroy each backend database */ - for( i = 0, bd = backendDB; i < nBackendDB; i++, bd++ ) { + if ( bd->bd_info->bi_db_destroy ) { + bd->bd_info->bi_db_destroy( bd, NULL ); + } +} - if ( bd->be_syncinfo ) { - syncinfo_free( bd->be_syncinfo ); - } +void backend_destroy_one( BackendDB *bd, int dynamic ) +{ + if ( dynamic ) { + LDAP_STAILQ_REMOVE(&backendDB, bd, BackendDB, be_next ); + } - if ( bd->be_pending_csn_list ) { - csne = LDAP_TAILQ_FIRST( bd->be_pending_csn_list ); - while ( csne ) { - struct slap_csn_entry *tmp_csne = csne; + if ( bd->be_syncinfo ) { + syncinfo_free( bd->be_syncinfo, 1 ); + } - LDAP_TAILQ_REMOVE( bd->be_pending_csn_list, csne, ce_csn_link ); - ch_free( csne->ce_csn.bv_val ); - csne = LDAP_TAILQ_NEXT( csne, ce_csn_link ); - ch_free( tmp_csne ); - } - } - - if ( bd->bd_info->bi_db_destroy ) { - bd->bd_info->bi_db_destroy( bd ); - } - ber_bvarray_free( bd->be_suffix ); - ber_bvarray_free( bd->be_nsuffix ); - if ( !BER_BVISNULL( &bd->be_rootdn ) ) { - free( bd->be_rootdn.bv_val ); - } - if ( !BER_BVISNULL( &bd->be_rootndn ) ) { - free( bd->be_rootndn.bv_val ); - } - if ( !BER_BVISNULL( &bd->be_rootpw ) ) { - free( bd->be_rootpw.bv_val ); - } - acl_destroy( bd->be_acl, frontendDB->be_acl ); + backend_stopdown_one( bd ); + + ber_bvarray_free( bd->be_suffix ); + ber_bvarray_free( bd->be_nsuffix ); + if ( !BER_BVISNULL( &bd->be_rootdn ) ) { + free( bd->be_rootdn.bv_val ); + } + if ( !BER_BVISNULL( &bd->be_rootndn ) ) { + free( bd->be_rootndn.bv_val ); + } + if ( !BER_BVISNULL( &bd->be_rootpw ) ) { + free( bd->be_rootpw.bv_val ); + } + acl_destroy( bd->be_acl ); + limits_destroy( bd->be_limits ); + if ( !BER_BVISNULL( &bd->be_update_ndn ) ) { + ch_free( bd->be_update_ndn.bv_val ); + } + if ( bd->be_update_refs ) { + ber_bvarray_free( bd->be_update_refs ); } - free( backendDB ); - /* destroy each backend type */ - for( i = 0; i < nBackendInfo; i++ ) { - if( backendInfo[i].bi_destroy ) { - backendInfo[i].bi_destroy( - &backendInfo[i] ); - } + if ( dynamic ) { + free( bd ); } +} -#ifdef SLAPD_MODULES - if (backendInfo != slap_binfo) { - free(backendInfo); +int backend_destroy(void) +{ + BackendDB *bd; + BackendInfo *bi; + + /* destroy each backend database */ + while (( bd = LDAP_STAILQ_FIRST(&backendDB))) { + backend_destroy_one( bd, 1 ); + } + + /* destroy each backend type */ + LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next ) { + if( bi->bi_destroy ) { + bi->bi_destroy( bi ); + } } -#endif /* SLAPD_MODULES */ nBackendInfo = 0; - backendInfo = NULL; + LDAP_STAILQ_INIT(&backendInfo); /* destroy frontend database */ bd = frontendDB; if ( bd ) { if ( bd->bd_info->bi_db_destroy ) { - bd->bd_info->bi_db_destroy( bd ); + bd->bd_info->bi_db_destroy( bd, NULL ); } ber_bvarray_free( bd->be_suffix ); ber_bvarray_free( bd->be_nsuffix ); @@ -514,7 +500,8 @@ int backend_destroy(void) if ( !BER_BVISNULL( &bd->be_rootpw ) ) { free( bd->be_rootpw.bv_val ); } - acl_destroy( bd->be_acl, frontendDB->be_acl ); + acl_destroy( bd->be_acl ); + frontendDB = NULL; } return 0; @@ -522,25 +509,61 @@ int backend_destroy(void) BackendInfo* backend_info(const char *type) { - int i; + BackendInfo *bi; /* search for the backend type */ - for( i = 0; i < nBackendInfo; i++ ) { - if( strcasecmp(backendInfo[i].bi_type, type) == 0 ) { - return &backendInfo[i]; + LDAP_STAILQ_FOREACH(bi,&backendInfo,bi_next) { + if( strcasecmp(bi->bi_type, type) == 0 ) { + return bi; } } return NULL; } +void +backend_db_insert( + BackendDB *be, + int idx +) +{ + /* If idx < 0, just add to end of list */ + if ( idx < 0 ) { + LDAP_STAILQ_INSERT_TAIL(&backendDB, be, be_next); + } else if ( idx == 0 ) { + LDAP_STAILQ_INSERT_HEAD(&backendDB, be, be_next); + } else { + int i; + BackendDB *b2; + + b2 = LDAP_STAILQ_FIRST(&backendDB); + idx--; + for (i=0; ibe_pcl_mutexp = &be->be_pcl_mutex; - } + /* If be is provided, treat it as private. Otherwise allocate + * one and add it to the global list. + */ + if ( !be ) { + be = ch_calloc( 1, sizeof(Backend) ); + /* Just append */ + if ( idx >= nbackends ) + idx = -1; + nbackends++; + backend_db_insert( be, idx ); } - be = &backends[nbackends++]; - be->bd_info = bi; + be->bd_self = be; be->be_def_limit = frontendDB->be_def_limit; be->be_dfltaccess = frontendDB->be_dfltaccess; @@ -575,39 +593,46 @@ backend_db_init( be->be_requires = frontendDB->be_requires; be->be_ssf_set = frontendDB->be_ssf_set; - be->be_pcl_mutexp = &be->be_pcl_mutex; - ldap_pvt_thread_mutex_init( be->be_pcl_mutexp ); + ldap_pvt_thread_mutex_init( &be->be_pcl_mutex ); /* assign a default depth limit for alias deref */ be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; if ( bi->bi_db_init ) { - rc = bi->bi_db_init( be ); + rc = bi->bi_db_init( be, cr ); } if ( rc != 0 ) { fprintf( stderr, "database init failed (%s)\n", type ); - nbackends--; - return NULL; + /* If we created and linked this be, remove it and free it */ + if ( !b0 ) { + LDAP_STAILQ_REMOVE(&backendDB, be, BackendDB, be_next); + ch_free( be ); + be = NULL; + nbackends--; + } + } else { + if ( !bi->bi_nDB ) { + backend_init_controls( bi ); + } + bi->bi_nDB++; } - - bi->bi_nDB++; return( be ); } void be_db_close( void ) { - int i; + BackendDB *be; - for ( i = 0; i < nbackends; i++ ) { - if ( backends[i].bd_info->bi_db_close ) { - (*backends[i].bd_info->bi_db_close)( &backends[i] ); + LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { + if ( be->bd_info->bi_db_close ) { + be->bd_info->bi_db_close( be, NULL ); } } if ( frontendDB->bd_info->bi_db_close ) { - (*frontendDB->bd_info->bi_db_close)( frontendDB ); + frontendDB->bd_info->bi_db_close( frontendDB, NULL ); } } @@ -615,27 +640,25 @@ be_db_close( void ) Backend * select_backend( struct berval * dn, - int manageDSAit, int noSubs ) { - int i, j; + int j; ber_len_t len, dnlen = dn->bv_len; - Backend *be = NULL; + Backend *be; - for ( i = 0; i < nbackends; i++ ) { - if ( backends[i].be_nsuffix == NULL ) { + LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { + if ( be->be_nsuffix == NULL || SLAP_DBHIDDEN( be )) { continue; } - for ( j = 0; !BER_BVISNULL( &backends[i].be_nsuffix[j] ); j++ ) + for ( j = 0; !BER_BVISNULL( &be->be_nsuffix[j] ); j++ ) { - if ( ( SLAP_GLUE_SUBORDINATE( &backends[i] ) ) - && noSubs ) + if ( ( SLAP_GLUE_SUBORDINATE( be ) ) && noSubs ) { continue; } - len = backends[i].be_nsuffix[j].bv_len; + len = be->be_nsuffix[j].bv_len; if ( len > dnlen ) { /* suffix is longer than DN */ @@ -652,19 +675,9 @@ select_backend( continue; } - if ( strcmp( backends[i].be_nsuffix[j].bv_val, + if ( strcmp( be->be_nsuffix[j].bv_val, &dn->bv_val[dnlen-len] ) == 0 ) { - if( be == NULL ) { - be = &backends[i]; - - if( manageDSAit && len == dnlen && - !SLAP_GLUE_SUBORDINATE( be ) ) { - continue; - } - } else { - be = &backends[i]; - } return be; } } @@ -693,6 +706,26 @@ be_issuffix( return 0; } +int +be_issubordinate( + Backend *be, + struct berval *bvsubordinate ) +{ + int i; + + if ( be->be_nsuffix == NULL ) { + return 0; + } + + for ( i = 0; !BER_BVISNULL( &be->be_nsuffix[i] ); i++ ) { + if ( dnIsSuffix( bvsubordinate, &be->be_nsuffix[i] ) ) { + return 1; + } + } + + return 0; +} + int be_isroot_dn( Backend *be, struct berval *ndn ) { @@ -713,7 +746,10 @@ be_slurp_update( Operation *op ) int be_shadow_update( Operation *op ) { - return ( SLAP_SYNC_SHADOW( op->o_bd ) || + /* This assumes that all internal ops (connid == -1) on a syncrepl + * database are syncrepl operations. + */ + return (( SLAP_SYNC_SHADOW( op->o_bd ) && op->o_connid == -1 ) || ( SLAP_SHADOW( op->o_bd ) && be_isupdate_dn( op->o_bd, &op->o_ndn ) ) ); } @@ -742,33 +778,82 @@ be_isroot( Operation *op ) int be_isroot_pw( Operation *op ) { - int result; + return be_rootdn_bind( op, NULL ) == LDAP_SUCCESS; +} - if ( ! be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) { - return 0; +/* + * checks if binding as rootdn + * + * return value: + * SLAP_CB_CONTINUE if not the rootdn, or if rootpw is null + * LDAP_SUCCESS if rootdn & rootpw + * LDAP_INVALID_CREDENTIALS if rootdn & !rootpw + * + * if rs != NULL + * if LDAP_SUCCESS, op->orb_edn is set + * if LDAP_INVALID_CREDENTIALS, response is sent to client + */ +int +be_rootdn_bind( Operation *op, SlapReply *rs ) +{ + int rc; +#ifdef SLAPD_SPASSWD + void *old_authctx = NULL; +#endif + + assert( op->o_tag == LDAP_REQ_BIND ); + assert( op->orb_method == LDAP_AUTH_SIMPLE ); + + if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) { + return SLAP_CB_CONTINUE; + } + + if ( BER_BVISNULL( &op->o_bd->be_rootpw ) ) { + /* give the database a chance */ + return SLAP_CB_CONTINUE; } if ( BER_BVISEMPTY( &op->o_bd->be_rootpw ) ) { - return 0; + /* rootdn bind explicitly disallowed */ + rc = LDAP_INVALID_CREDENTIALS; + if ( rs ) { + goto send_result; + } + + return rc; } -#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) - ldap_pvt_thread_mutex_lock( &passwd_mutex ); #ifdef SLAPD_SPASSWD - lutil_passwd_sasl_conn = op->o_conn->c_sasl_authctx; -#endif + ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)slap_sasl_bind, + op->o_conn->c_sasl_authctx, 0, &old_authctx, NULL ); #endif - result = lutil_passwd( &op->o_bd->be_rootpw, &op->orb_cred, NULL, NULL ); + rc = lutil_passwd( &op->o_bd->be_rootpw, &op->orb_cred, NULL, NULL ); -#if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD ) #ifdef SLAPD_SPASSWD - lutil_passwd_sasl_conn = NULL; -#endif - ldap_pvt_thread_mutex_unlock( &passwd_mutex ); + ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)slap_sasl_bind, + old_authctx, 0, NULL, NULL ); #endif - return result == 0; + rc = ( rc == 0 ? LDAP_SUCCESS : LDAP_INVALID_CREDENTIALS ); + if ( rs ) { +send_result:; + rs->sr_err = rc; + + Debug( LDAP_DEBUG_TRACE, "%s: rootdn=\"%s\" bind%s\n", + op->o_log_prefix, op->o_bd->be_rootdn.bv_val, + rc == LDAP_SUCCESS ? " succeeded" : " failed" ); + + if ( rc == LDAP_SUCCESS ) { + /* Set to the pretty rootdn */ + ber_dupbv( &op->orb_edn, &op->o_bd->be_rootdn ); + + } else { + send_ldap_result( op, rs ); + } + } + + return rc; } int @@ -790,43 +875,13 @@ be_entry_release_rw( int backend_unbind( Operation *op, SlapReply *rs ) { - int i; - - for ( i = 0; i < nbackends; i++ ) { -#if defined( LDAP_SLAPI ) - if ( op->o_pb ) { - int rc; - if ( i == 0 ) slapi_int_pblock_set_operation( op->o_pb, op ); - slapi_pblock_set( op->o_pb, SLAPI_BACKEND, (void *)&backends[i] ); - rc = slapi_int_call_plugins( &backends[i], - SLAPI_PLUGIN_PRE_UNBIND_FN, (Slapi_PBlock *)op->o_pb ); - if ( rc < 0 ) { - /* - * A preoperation plugin failure will abort the - * entire operation. - */ - Debug(LDAP_DEBUG_TRACE, - "do_bind: Unbind preoperation plugin failed\n", - 0, 0, 0); - return 0; - } - } -#endif /* defined( LDAP_SLAPI ) */ + BackendDB *be; - if ( backends[i].be_unbind ) { - op->o_bd = &backends[i]; - (*backends[i].be_unbind)( op, rs ); - } - -#if defined( LDAP_SLAPI ) - if ( op->o_pb != NULL && slapi_int_call_plugins( &backends[i], - SLAPI_PLUGIN_POST_UNBIND_FN, (Slapi_PBlock *)op->o_pb ) < 0 ) - { - Debug(LDAP_DEBUG_TRACE, - "do_unbind: Unbind postoperation plugins failed\n", - 0, 0, 0); + LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { + if ( be->be_unbind ) { + op->o_bd = be; + be->be_unbind( op, rs ); } -#endif /* defined( LDAP_SLAPI ) */ } return 0; @@ -836,11 +891,11 @@ int backend_connection_init( Connection *conn ) { - int i; + BackendDB *be; - for ( i = 0; i < nbackends; i++ ) { - if ( backends[i].be_connection_init ) { - (*backends[i].be_connection_init)( &backends[i], conn); + LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { + if ( be->be_connection_init ) { + be->be_connection_init( be, conn ); } } @@ -851,18 +906,18 @@ int backend_connection_destroy( Connection *conn ) { - int i; + BackendDB *be; - for ( i = 0; i < nbackends; i++ ) { - if ( backends[i].be_connection_destroy ) { - (*backends[i].be_connection_destroy)( &backends[i], conn); + LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { + if ( be->be_connection_destroy ) { + be->be_connection_destroy( be, conn); } } return 0; } -static int +int backend_check_controls( Operation *op, SlapReply *rs ) @@ -879,27 +934,34 @@ backend_check_controls( /* unrecognized control */ if ( (*ctrls)->ldctl_iscritical ) { /* should not be reachable */ - Debug( LDAP_DEBUG_ANY, - "backend_check_controls: unrecognized control: %s\n", + Debug( LDAP_DEBUG_ANY, "backend_check_controls: " + "unrecognized critical control: %s\n", (*ctrls)->ldctl_oid, 0, 0 ); assert( 0 ); + } else { + Debug( LDAP_DEBUG_TRACE, "backend_check_controls: " + "unrecognized non-critical control: %s\n", + (*ctrls)->ldctl_oid, 0, 0 ); } break; case LDAP_COMPARE_FALSE: - if ( !op->o_bd->be_ctrls[ cid ] ) - { - /* Per RFC 2251 (and LDAPBIS discussions), if the control - * is recognized and appropriate for the operation (which - * we've already verified), then the server should make - * use of the control when performing the operation. - * - * Here we find that operation extended by the control - * is not unavailable in a particular context, hence the - * return of unwillingToPerform. + if ( !op->o_bd->be_ctrls[cid] && (*ctrls)->ldctl_iscritical ) { +#ifdef SLAP_CONTROL_X_WHATFAILED + if ( get_whatFailed( op ) ) { + char *oids[ 2 ]; + oids[ 0 ] = (*ctrls)->ldctl_oid; + oids[ 1 ] = NULL; + slap_ctrl_whatFailed_add( op, rs, oids ); + } +#endif + /* RFC 4511 allows unavailableCriticalExtension to be + * returned when the server is unwilling to perform + * an operation extended by a recognized critical + * control. */ - rs->sr_text = "control unavailable in context"; - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "critical control unavailable in context"; + rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; goto done; } break; @@ -909,13 +971,26 @@ backend_check_controls( default: /* unreachable */ - rs->sr_err = "unable to check control"; + Debug( LDAP_DEBUG_ANY, + "backend_check_controls: unable to check control: %s\n", + (*ctrls)->ldctl_oid, 0, 0 ); + assert( 0 ); + + rs->sr_text = "unable to check control"; rs->sr_err = LDAP_OTHER; goto done; } } } +#if 0 /* temporarily removed */ + /* check should be generalized */ + if( get_relax(op) && !be_isroot(op)) { + rs->sr_text = "requires manager authorization"; + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + } +#endif + done:; return rs->sr_err; } @@ -930,13 +1005,19 @@ backend_check_restrictions( slap_mask_t requires; slap_mask_t opflag; slap_mask_t exopflag = 0; - slap_ssf_set_t *ssf; + slap_ssf_set_t ssfs, *ssf; int updateop = 0; int starttls = 0; int session = 0; + restrictops = frontendDB->be_restrictops; + requires = frontendDB->be_requires; + ssfs = frontendDB->be_ssf_set; + ssf = &ssfs; + if ( op->o_bd ) { - int rc = SLAP_CB_CONTINUE; + slap_ssf_t *fssf, *bssf; + int rc = SLAP_CB_CONTINUE, i; if ( op->o_bd->be_chk_controls ) { rc = ( *op->o_bd->be_chk_controls )( op, rs ); @@ -950,14 +1031,13 @@ backend_check_restrictions( return rs->sr_err; } - restrictops = op->o_bd->be_restrictops; - requires = op->o_bd->be_requires; - ssf = &op->o_bd->be_ssf_set; - - } else { - restrictops = frontendDB->be_restrictops; - requires = frontendDB->be_requires; - ssf = &frontendDB->be_ssf_set; + restrictops |= op->o_bd->be_restrictops; + requires |= op->o_bd->be_requires; + bssf = &op->o_bd->be_ssf_set.sss_ssf; + fssf = &ssfs.sss_ssf; + for ( i=0; io_tag ) { @@ -1120,7 +1200,10 @@ backend_check_restrictions( } #ifdef SLAP_X_LISTENER_MOD - if ( op->o_conn->c_listener && ! ( op->o_conn->c_listener->sl_perms & ( !BER_BVISEMPTY( &op->o_ndn ) ? S_IWUSR : S_IWOTH ) ) ) { + if ( op->o_conn->c_listener && + ! ( op->o_conn->c_listener->sl_perms & ( !BER_BVISEMPTY( &op->o_ndn ) + ? (S_IWUSR|S_IWOTH) : S_IWOTH ) ) ) + { /* no "w" mode means readonly */ rs->sr_text = "modifications not allowed on this listener"; rs->sr_err = LDAP_UNWILLING_TO_PERFORM; @@ -1199,7 +1282,8 @@ backend_check_restrictions( if ( !starttls && !updateop ) { if ( op->o_conn->c_listener && !( op->o_conn->c_listener->sl_perms & - ( !BER_BVISEMPTY( &op->o_dn ) ? S_IRUSR : S_IROTH ))) + ( !BER_BVISEMPTY( &op->o_dn ) + ? (S_IRUSR|S_IROTH) : S_IROTH ))) { /* no "r" mode means no read */ rs->sr_text = "read not allowed on this listener"; @@ -1252,23 +1336,21 @@ be_entry_get_rw( int rw, Entry **e ) { - int rc; - *e = NULL; - if (op->o_bd == NULL) { - rc = LDAP_NO_SUCH_OBJECT; - } else if ( op->o_bd->be_fetch ) { - rc = ( op->o_bd->be_fetch )( op, ndn, - oc, at, rw, e ); - } else { - rc = LDAP_UNWILLING_TO_PERFORM; + if ( op->o_bd == NULL ) { + return LDAP_NO_SUCH_OBJECT; } - return rc; + + if ( op->o_bd->be_fetch ) { + return op->o_bd->be_fetch( op, ndn, oc, at, rw, e ); + } + + return LDAP_UNWILLING_TO_PERFORM; } int -backend_group( +fe_acl_group( Operation *op, Entry *target, struct berval *gr_ndn, @@ -1277,14 +1359,23 @@ backend_group( AttributeDescription *group_at ) { Entry *e; + void *o_priv = op->o_private, *e_priv = NULL; Attribute *a; int rc; GroupAssertion *g; Backend *be = op->o_bd; + OpExtra *oex; - if ( op->o_abandon ) return SLAPD_ABANDON; + LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) { + if ( oex->oe_key == (void *)backend_group ) + break; + } + + if ( oex && ((OpExtraDB *)oex)->oe_db ) + op->o_bd = ((OpExtraDB *)oex)->oe_db; - op->o_bd = select_backend( gr_ndn, 0, 0 ); + if ( !op->o_bd || !SLAP_DBHIDDEN( op->o_bd )) + op->o_bd = select_backend( gr_ndn, 0 ); for ( g = op->o_groups; g; g = g->ga_next ) { if ( g->ga_be != op->o_bd || g->ga_oc != group_oc || @@ -1305,132 +1396,163 @@ backend_group( if ( target && dn_match( &target->e_nname, gr_ndn ) ) { e = target; rc = 0; + } else { + op->o_private = NULL; rc = be_entry_get_rw( op, gr_ndn, group_oc, group_at, 0, &e ); + e_priv = op->o_private; + op->o_private = o_priv; } - if ( e ) { -#ifdef LDAP_SLAPI - if ( op->o_pb != NULL ) { - init_group_pblock( op, target, e, op_ndn, group_at ); - - rc = call_group_preop_plugins( op ); - if ( rc == LDAP_SUCCESS ) { - goto done; - } - } -#endif /* LDAP_SLAPI */ + if ( e ) { a = attr_find( e->e_attrs, group_at ); if ( a ) { - /* If the attribute is a subtype of labeledURI, treat this as - * a dynamic group ala groupOfURLs + /* If the attribute is a subtype of labeledURI, + * treat this as a dynamic group ala groupOfURLs */ - if (is_at_subtype( group_at->ad_type, + if ( is_at_subtype( group_at->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) { int i; LDAPURLDesc *ludp; struct berval bv, nbase; Filter *filter; - Entry *user; + Entry *user = NULL; + void *user_priv = NULL; Backend *b2 = op->o_bd; if ( target && dn_match( &target->e_nname, op_ndn ) ) { user = target; - } else { - op->o_bd = select_backend( op_ndn, 0, 0 ); - rc = be_entry_get_rw(op, op_ndn, NULL, NULL, 0, &user ); } - if ( rc == 0 ) { - rc = 1; - for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { - if ( ldap_url_parse( a->a_vals[i].bv_val, &ludp ) != - LDAP_URL_SUCCESS ) - { - continue; + rc = LDAP_COMPARE_FALSE; + for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { + if ( ldap_url_parse( a->a_vals[i].bv_val, &ludp ) != + LDAP_URL_SUCCESS ) + { + continue; + } + + BER_BVZERO( &nbase ); + + /* host, attrs and extensions parts must be empty */ + if ( ( ludp->lud_host && *ludp->lud_host ) + || ludp->lud_attrs + || ludp->lud_exts ) + { + goto loopit; + } + + ber_str2bv( ludp->lud_dn, 0, 0, &bv ); + if ( dnNormalize( 0, NULL, NULL, &bv, &nbase, + op->o_tmpmemctx ) != LDAP_SUCCESS ) + { + goto loopit; + } + + switch ( ludp->lud_scope ) { + case LDAP_SCOPE_BASE: + if ( !dn_match( &nbase, op_ndn ) ) { + goto loopit; } - BER_BVZERO( &nbase ); - /* host part must be empty */ - /* attrs and extensions parts must be empty */ - if ( ( ludp->lud_host && *ludp->lud_host ) || - ludp->lud_attrs || ludp->lud_exts ) - { + break; + case LDAP_SCOPE_ONELEVEL: + dnParent( op_ndn, &bv ); + if ( !dn_match( &nbase, &bv ) ) { + goto loopit; + } + break; + case LDAP_SCOPE_SUBTREE: + if ( !dnIsSuffix( op_ndn, &nbase ) ) { goto loopit; } - ber_str2bv( ludp->lud_dn, 0, 0, &bv ); - if ( dnNormalize( 0, NULL, NULL, &bv, &nbase, - op->o_tmpmemctx ) != LDAP_SUCCESS ) + break; + case LDAP_SCOPE_SUBORDINATE: + if ( dn_match( &nbase, op_ndn ) || + !dnIsSuffix( op_ndn, &nbase ) ) { goto loopit; } - switch ( ludp->lud_scope ) { - case LDAP_SCOPE_BASE: - if ( !dn_match( &nbase, op_ndn ) ) { - goto loopit; - } - break; - case LDAP_SCOPE_ONELEVEL: - dnParent( op_ndn, &bv ); - if ( !dn_match( &nbase, &bv ) ) { - goto loopit; - } - break; - case LDAP_SCOPE_SUBTREE: - if ( !dnIsSuffix( op_ndn, &nbase ) ) { - goto loopit; - } - break; -#ifdef LDAP_SCOPE_SUBORDINATE - case LDAP_SCOPE_SUBORDINATE: - if ( dn_match( &nbase, op_ndn ) || - !dnIsSuffix( op_ndn, &nbase ) ) - { + } + + /* NOTE: this could be NULL + * if no filter is provided, + * or if filter parsing fails. + * In the latter case, + * we should give up. */ + if ( ludp->lud_filter != NULL && ludp->lud_filter != '\0') { + filter = str2filter_x( op, ludp->lud_filter ); + if ( filter == NULL ) { + /* give up... */ + rc = LDAP_OTHER; + goto loopit; + } + + /* only get user if required + * and not available yet */ + if ( user == NULL ) { + int rc2; + + op->o_bd = select_backend( op_ndn, 0 ); + op->o_private = NULL; + rc2 = be_entry_get_rw( op, op_ndn, NULL, NULL, 0, &user ); + user_priv = op->o_private; + op->o_private = o_priv; + if ( rc2 != 0 ) { + /* give up... */ + rc = LDAP_OTHER; goto loopit; } -#endif } - filter = str2filter_x( op, ludp->lud_filter ); - if ( filter ) { - if ( test_filter( NULL, user, filter ) == - LDAP_COMPARE_TRUE ) - { - rc = 0; - } - filter_free_x( op, filter ); + + if ( test_filter( NULL, user, filter ) == + LDAP_COMPARE_TRUE ) + { + rc = 0; } + filter_free_x( op, filter, 1 ); + } loopit: - ldap_free_urldesc( ludp ); - if ( !BER_BVISNULL( &nbase ) ) { - op->o_tmpfree( nbase.bv_val, op->o_tmpmemctx ); - } - if ( rc == 0 ) break; + ldap_free_urldesc( ludp ); + if ( !BER_BVISNULL( &nbase ) ) { + op->o_tmpfree( nbase.bv_val, op->o_tmpmemctx ); } - if ( user != target ) { - be_entry_release_r( op, user ); + if ( rc != LDAP_COMPARE_FALSE ) { + break; } } + + if ( user != NULL && user != target ) { + op->o_private = user_priv; + be_entry_release_r( op, user ); + op->o_private = o_priv; + } op->o_bd = b2; + } else { - rc = value_find_ex( group_at, - SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | - SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a->a_nvals, op_ndn, op->o_tmpmemctx ); + rc = attr_valfind( a, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + op_ndn, NULL, op->o_tmpmemctx ); + if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) { + rc = LDAP_COMPARE_FALSE; + } } + } else { rc = LDAP_NO_SUCH_ATTRIBUTE; } - if (e != target ) { + + if ( e != target ) { + op->o_private = e_priv; be_entry_release_r( op, e ); + op->o_private = o_priv; } + } else { rc = LDAP_NO_SUCH_OBJECT; } -#ifdef LDAP_SLAPI - if ( op->o_pb ) call_group_postop_plugins( op ); -#endif /* LDAP_SLAPI */ - if ( op->o_tag != LDAP_REQ_BIND && !op->o_do_not_cache ) { g = op->o_tmpalloc( sizeof( GroupAssertion ) + gr_ndn->bv_len, op->o_tmpmemctx ); @@ -1443,65 +1565,45 @@ loopit: g->ga_next = op->o_groups; op->o_groups = g; } + done: op->o_bd = be; return rc; } -#ifdef LDAP_SLAPI -static int backend_compute_output_attr(computed_attr_context *c, Slapi_Attr *a, Slapi_Entry *e) +int +backend_group( + Operation *op, + Entry *target, + struct berval *gr_ndn, + struct berval *op_ndn, + ObjectClass *group_oc, + AttributeDescription *group_at ) { - BerVarray v; - int rc; - BerVarray *vals = (BerVarray *)c->cac_private; - Operation *op = NULL; - int i, j; - - slapi_pblock_get( c->cac_pb, SLAPI_OPERATION, &op ); - if ( op == NULL ) { - return 1; - } + int rc; + BackendDB *be_orig; + OpExtraDB oex; - if ( op->o_conn && access_allowed( op, - e, a->a_desc, NULL, ACL_AUTH, - &c->cac_acl_state ) == 0 ) { - return 1; + if ( op->o_abandon ) { + return SLAPD_ABANDON; } - for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) ; - - v = op->o_tmpalloc( sizeof(struct berval) * (i+1), - op->o_tmpmemctx ); - for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { - if ( op->o_conn && access_allowed( op, - e, a->a_desc, - &a->a_nvals[i], - ACL_AUTH, &c->cac_acl_state ) == 0 ) { - continue; - } - ber_dupbv_x( &v[j], - &a->a_nvals[i], op->o_tmpmemctx ); - if ( !BER_BVISNULL( &v[j] ) ) { - j++; - } - } + oex.oe_db = op->o_bd; + oex.oe.oe_key = (void *)backend_group; + LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next); - if ( j == 0 ) { - op->o_tmpfree( v, op->o_tmpmemctx ); - *vals = NULL; - rc = 1; - } else { - BER_BVZERO( &v[j] ); - *vals = v; - rc = 0; - } + be_orig = op->o_bd; + op->o_bd = frontendDB; + rc = frontendDB->be_group( op, target, gr_ndn, + op_ndn, group_oc, group_at ); + op->o_bd = be_orig; + LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next); return rc; } -#endif /* LDAP_SLAPI */ int -backend_attribute( +fe_acl_attribute( Operation *op, Entry *target, struct berval *edn, @@ -1510,21 +1612,48 @@ backend_attribute( slap_access_t access ) { Entry *e = NULL; + void *o_priv = op->o_private, *e_priv = NULL; Attribute *a = NULL; int freeattr = 0, i, j, rc = LDAP_SUCCESS; AccessControlState acl_state = ACL_STATE_INIT; Backend *be = op->o_bd; + OpExtra *oex; + + LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) { + if ( oex->oe_key == (void *)backend_attribute ) + break; + } + + if ( oex && ((OpExtraDB *)oex)->oe_db ) + op->o_bd = ((OpExtraDB *)oex)->oe_db; - op->o_bd = select_backend( edn, 0, 0 ); + if ( !op->o_bd || !SLAP_DBHIDDEN( op->o_bd )) + op->o_bd = select_backend( edn, 0 ); if ( target && dn_match( &target->e_nname, edn ) ) { e = target; } else { + op->o_private = NULL; rc = be_entry_get_rw( op, edn, NULL, entry_at, 0, &e ); + e_priv = op->o_private; + op->o_private = o_priv; } if ( e ) { + if ( entry_at == slap_schema.si_ad_entry || entry_at == slap_schema.si_ad_children ) { + assert( vals == NULL ); + + rc = LDAP_SUCCESS; + if ( op->o_conn && access > ACL_NONE && + access_allowed( op, e, entry_at, NULL, + access, &acl_state ) == 0 ) + { + rc = LDAP_INSUFFICIENT_ACCESS; + } + goto freeit; + } + a = attr_find( e->e_attrs, entry_at ); if ( a == NULL ) { SlapReply rs = { 0 }; @@ -1556,23 +1685,21 @@ backend_attribute( if ( a ) { BerVarray v; - if ( op->o_conn && access > ACL_NONE && access_allowed( op, - e, entry_at, NULL, access, - &acl_state ) == 0 ) { + if ( op->o_conn && access > ACL_NONE && + access_allowed( op, e, entry_at, NULL, + access, &acl_state ) == 0 ) + { rc = LDAP_INSUFFICIENT_ACCESS; goto freeit; } - for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) - ; - + i = a->a_numvals; v = op->o_tmpalloc( sizeof(struct berval) * ( i + 1 ), op->o_tmpmemctx ); - for ( i = 0,j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) + for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { if ( op->o_conn && access > ACL_NONE && - access_allowed( op, e, - entry_at, + access_allowed( op, e, entry_at, &a->a_nvals[i], access, &acl_state ) == 0 ) @@ -1596,31 +1723,10 @@ backend_attribute( rc = LDAP_SUCCESS; } } -#ifdef LDAP_SLAPI - else if ( op->o_pb ) { - /* try any computed attributes */ - computed_attr_context ctx; - - slapi_int_pblock_set_operation( op->o_pb, op ); - - ctx.cac_pb = op->o_pb; - ctx.cac_attrs = NULL; - ctx.cac_userattrs = 0; - ctx.cac_opattrs = 0; - ctx.cac_acl_state = acl_state; - ctx.cac_private = (void *)vals; - - rc = compute_evaluator( &ctx, entry_at->ad_cname.bv_val, e, backend_compute_output_attr ); - if ( rc == 1 ) { - rc = LDAP_INSUFFICIENT_ACCESS; - - } else { - rc = LDAP_SUCCESS; - } - } -#endif /* LDAP_SLAPI */ freeit: if ( e != target ) { + op->o_private = e_priv; be_entry_release_r( op, e ); + op->o_private = o_priv; } if ( freeattr ) { attr_free( a ); @@ -1631,20 +1737,32 @@ freeit: if ( e != target ) { return rc; } -#ifdef LDAP_SLAPI -static int backend_compute_output_attr_access(computed_attr_context *c, Slapi_Attr *a, Slapi_Entry *e) +int +backend_attribute( + Operation *op, + Entry *target, + struct berval *edn, + AttributeDescription *entry_at, + BerVarray *vals, + slap_access_t access ) { - struct berval *nval = (struct berval *)c->cac_private; - Operation *op = NULL; + int rc; + BackendDB *be_orig; + OpExtraDB oex; - slapi_pblock_get( c->cac_pb, SLAPI_OPERATION, &op ); - if ( op == NULL ) { - return 1; - } + oex.oe_db = op->o_bd; + oex.oe.oe_key = (void *)backend_attribute; + LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next); + + be_orig = op->o_bd; + op->o_bd = frontendDB; + rc = frontendDB->be_attribute( op, target, edn, + entry_at, vals, access ); + op->o_bd = be_orig; + LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next); - return access_allowed( op, e, a->a_desc, nval, ACL_AUTH, NULL ) == 0; + return rc; } -#endif /* LDAP_SLAPI */ int backend_access( @@ -1657,22 +1775,28 @@ backend_access( slap_mask_t *mask ) { Entry *e = NULL; + void *o_priv = op->o_private, *e_priv = NULL; int rc = LDAP_INSUFFICIENT_ACCESS; Backend *be = op->o_bd; /* pedantic */ - assert( op ); - assert( op->o_conn ); - assert( edn ); + assert( op != NULL ); + assert( op->o_conn != NULL ); + assert( edn != NULL ); assert( access > ACL_NONE ); - op->o_bd = select_backend( edn, 0, 0 ); + if ( !op->o_bd ) { + op->o_bd = select_backend( edn, 0 ); + } if ( target && dn_match( &target->e_nname, edn ) ) { e = target; } else { + op->o_private = NULL; rc = be_entry_get_rw( op, edn, NULL, entry_at, 0, &e ); + e_priv = op->o_private; + op->o_private = o_priv; } if ( e ) { @@ -1734,31 +1858,11 @@ backend_access( } rc = LDAP_SUCCESS; } -#ifdef LDAP_SLAPI - else if ( op->o_pb ) { - /* try any computed attributes */ - computed_attr_context ctx; - - slapi_int_pblock_set_operation( op->o_pb, op ); - - ctx.cac_pb = op->o_pb; - ctx.cac_attrs = NULL; - ctx.cac_userattrs = 0; - ctx.cac_opattrs = 0; - ctx.cac_private = (void *)nval; - - rc = compute_evaluator( &ctx, entry_at->ad_cname.bv_val, e, backend_compute_output_attr_access ); - if ( rc == 1 ) { - rc = LDAP_INSUFFICIENT_ACCESS; - - } else { - rc = LDAP_SUCCESS; - } - } -#endif /* LDAP_SLAPI */ } freeit: if ( e != target ) { + op->o_private = e_priv; be_entry_release_r( op, e ); + op->o_private = o_priv; } if ( freeattr ) { attr_free( a ); @@ -1769,13 +1873,20 @@ freeit: if ( e != target ) { return rc; } -int backend_operational( +int +fe_aux_operational( Operation *op, SlapReply *rs ) { - Attribute **ap; - int rc = 0; - BackendDB *be_orig; + Attribute **ap; + int rc = LDAP_SUCCESS; + BackendDB *be_orig = op->o_bd; + OpExtra *oex; + + LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) { + if ( oex->oe_key == (void *)backend_operational ) + break; + } for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) /* just count them */ ; @@ -1785,84 +1896,58 @@ int backend_operational( * and the backend supports specific operational attributes, * add them to the attribute list */ - if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs && - ad_inlist( slap_schema.si_ad_entryDN, rs->sr_attrs ))) + if ( !( rs->sr_flags & REP_NO_ENTRYDN ) + && ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs && + ad_inlist( slap_schema.si_ad_entryDN, rs->sr_attrs ) ) ) ) { *ap = slap_operational_entryDN( rs->sr_entry ); ap = &(*ap)->a_next; } - if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs && - ad_inlist( slap_schema.si_ad_subschemaSubentry, rs->sr_attrs ))) + if ( !( rs->sr_flags & REP_NO_SUBSCHEMA) + && ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs && + ad_inlist( slap_schema.si_ad_subschemaSubentry, rs->sr_attrs ) ) ) ) { *ap = slap_operational_subschemaSubentry( op->o_bd ); ap = &(*ap)->a_next; } /* Let the overlays have a chance at this */ - be_orig = op->o_bd; - if ( SLAP_ISOVERLAY( be_orig )) - op->o_bd = select_backend( be_orig->be_nsuffix, 0, 0 ); + if ( oex && ((OpExtraDB *)oex)->oe_db ) + op->o_bd = ((OpExtraDB *)oex)->oe_db; - if (( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) && - op->o_bd && op->o_bd->be_operational != NULL ) + if ( !op->o_bd || !SLAP_DBHIDDEN( op->o_bd )) + op->o_bd = select_backend( &op->o_req_ndn, 0 ); + + if ( op->o_bd != NULL && !be_match( op->o_bd, frontendDB ) && + ( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) && + op->o_bd->be_operational != NULL ) { - Attribute *a; - - a = rs->sr_operational_attrs; - rs->sr_operational_attrs = NULL; rc = op->o_bd->be_operational( op, rs ); - *ap = rs->sr_operational_attrs; - if ( a != NULL ) { - rs->sr_operational_attrs = a; - } - - for ( ; *ap; ap = &(*ap)->a_next ) - /* just count them */ ; } op->o_bd = be_orig; return rc; } -#ifdef LDAP_SLAPI -static void init_group_pblock( Operation *op, Entry *target, - Entry *e, struct berval *op_ndn, AttributeDescription *group_at ) -{ - slapi_int_pblock_set_operation( op->o_pb, op ); - - slapi_pblock_set( op->o_pb, - SLAPI_X_GROUP_ENTRY, (void *)e ); - slapi_pblock_set( op->o_pb, - SLAPI_X_GROUP_OPERATION_DN, (void *)op_ndn->bv_val ); - slapi_pblock_set( op->o_pb, - SLAPI_X_GROUP_ATTRIBUTE, (void *)group_at->ad_cname.bv_val ); - slapi_pblock_set( op->o_pb, - SLAPI_X_GROUP_TARGET_ENTRY, (void *)target ); -} - -static int call_group_preop_plugins( Operation *op ) +int backend_operational( Operation *op, SlapReply *rs ) { int rc; + BackendDB *be_orig; + OpExtraDB oex; - rc = slapi_int_call_plugins( op->o_bd, - SLAPI_X_PLUGIN_PRE_GROUP_FN, op->o_pb ); - if ( rc < 0 ) { - if (( slapi_pblock_get( op->o_pb, SLAPI_RESULT_CODE, - (void *)&rc ) != 0 ) || rc == LDAP_SUCCESS ) - { - rc = LDAP_NO_SUCH_ATTRIBUTE; - } - } else { - rc = LDAP_SUCCESS; - } + oex.oe_db = op->o_bd; + oex.oe.oe_key = (void *)backend_operational; + LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next); - return rc; -} + /* Moved this into the frontend so global overlays are called */ -static void call_group_postop_plugins( Operation *op ) -{ - (void) slapi_int_call_plugins( op->o_bd, SLAPI_X_PLUGIN_POST_GROUP_FN, op->o_pb ); + be_orig = op->o_bd; + op->o_bd = frontendDB; + rc = frontendDB->be_operational( op, rs ); + op->o_bd = be_orig; + LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next); + + return rc; } -#endif /* LDAP_SLAPI */