X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fbackend.c;h=9e352079cd3ac438563c1d677a713e3b975a551c;hb=46fab059977aed107f53c96ced0f35cfff8c7836;hp=f7ffd28ae5a777dffc61f4271ee42a5fb601ea55;hpb=0bd2dafd535b8b8d56333aa440692b689272adf7;p=openldap diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index f7ffd28ae5..9e352079cd 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -37,8 +37,6 @@ #include "lutil.h" #include "lber_pvt.h" -#include "ldap_rq.h" - #ifdef LDAP_SLAPI #include "slapi/slapi.h" @@ -57,39 +55,58 @@ 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; +slap_be_head backendDB = LDAP_STAILQ_HEAD_INITIALIZER(backendDB); + +static int +backend_init_controls( BackendInfo *bi ) +{ + if ( bi->bi_controls ) { + int i; + + for ( i = 0; bi->bi_controls[ i ]; i++ ) { + int cid; + + if ( slap_find_control_id( bi->bi_controls[ i ], &cid ) + == LDAP_CONTROL_NOT_FOUND ) + { + if ( !( slapMode & SLAP_TOOL_MODE ) ) { + assert( 0 ); + } -ldap_pvt_thread_pool_t syncrepl_pool; -int syncrepl_pool_max = SLAP_MAX_SYNCREPL_THREADS; + return -1; + } + + bi->bi_ctrls[ cid ] = 1; + } + } + + return 0; +} 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 ); + "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 ); - 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 ; @@ -102,10 +119,11 @@ int backend_init(void) } return rc; } + + LDAP_STAILQ_INSERT_TAIL(&backendInfo, bi, bi_next); } if ( nBackendInfo > 0) { - backendInfo = slap_binfo; return 0; } @@ -132,41 +150,59 @@ int backend_add(BackendInfo *aBackendInfo) return -1; } - if ((rc = aBackendInfo->bi_init(aBackendInfo)) != 0) { + rc = aBackendInfo->bi_init(aBackendInfo); + if ( rc != 0) { Debug( LDAP_DEBUG_ANY, "backend_add: initialization for type \"%s\" failed\n", aBackendInfo->bi_type, 0, 0 ); return rc; - } + } + + (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; +} + +static int +backend_set_controls( BackendDB *be ) +{ + BackendInfo *bi = be->bd_info; - /* 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); + /* 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 rc = 0; + int rc = 0; - assert(be); + assert( be ); be->be_pending_csn_list = (struct be_pcl *) ch_calloc( 1, sizeof( struct be_pcl )); @@ -174,17 +210,25 @@ int backend_startup_one(Backend *be) LDAP_TAILQ_INIT( be->be_pending_csn_list ); Debug( LDAP_DEBUG_TRACE, - "backend_startup: starting \"%s\"\n", + "backend_startup_one: starting \"%s\"\n", be->be_suffix ? be->be_suffix[0].bv_val : "(unknown)", 0, 0 ); + + /* set database controls */ + (void)backend_set_controls( be ); + if ( be->bd_info->bi_db_open ) { rc = be->bd_info->bi_db_open( be ); - if ( rc != 0 ) { + if ( rc == 0 ) { + (void)backend_set_controls( be ); + + } else { Debug( LDAP_DEBUG_ANY, - "backend_startup: bi_db_open failed! (%d)\n", + "backend_startup_one: bi_db_open failed! (%d)\n", rc, 0, 0 ); } } + return rc; } @@ -192,6 +236,7 @@ int backend_startup(Backend *be) { int i; int rc = 0; + BackendInfo *bi; if( ! ( nBackendDB > 0 ) ) { /* no databases */ @@ -228,65 +273,43 @@ 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; } } - } - ldap_pvt_thread_mutex_init( &slapd_rq.rq_mutex ); - LDAP_STAILQ_INIT( &slapd_rq.task_list ); - LDAP_STAILQ_INIT( &slapd_rq.run_list ); + (void)backend_init_controls( bi ); + } /* 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 ); + acl_append( &be->be_acl, frontendDB->be_acl, -1 ); - rc = backend_startup_one( &backendDB[i] ); + rc = backend_startup_one( be ); 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; @@ -294,12 +317,14 @@ 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; } @@ -308,6 +333,7 @@ int backend_shutdown( Backend *be ) { int i; int rc = 0; + BackendInfo *bi; if( be != NULL ) { /* shutdown a specific backend database */ @@ -329,29 +355,27 @@ int backend_shutdown( Backend *be ) } /* 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 ); } 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 ); } } @@ -368,67 +392,65 @@ int backend_shutdown( Backend *be ) return 0; } -int backend_destroy(void) +void backend_destroy_one( BackendDB *bd ) { - int i; - BackendDB *bd; - struct slap_csn_entry *csne; + LDAP_STAILQ_REMOVE(&backendDB, bd, slap_backend_db, be_next ); - ldap_pvt_thread_pool_destroy( &syncrepl_pool, 1 ); + if ( bd->be_syncinfo ) { + syncinfo_free( bd->be_syncinfo ); + } - /* destroy each backend database */ - for( i = 0, bd = backendDB; i < nBackendDB; i++, bd++ ) { + 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; - if ( bd->be_syncinfo ) { - syncinfo_free( bd->be_syncinfo ); + 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->be_pending_csn_list ) { - csne = LDAP_TAILQ_FIRST( bd->be_pending_csn_list ); - while ( csne ) { - struct slap_csn_entry *tmp_csne = 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 ); + free( bd ); +} - 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 ); +int backend_destroy(void) +{ + int i; + BackendDB *bd; + BackendInfo *bi; + + /* destroy each backend database */ + while (( bd = LDAP_STAILQ_FIRST(&backendDB))) { + backend_destroy_one( bd ); } - free( backendDB ); /* destroy each backend type */ - for( i = 0; i < nBackendInfo; i++ ) { - if( backendInfo[i].bi_destroy ) { - backendInfo[i].bi_destroy( - &backendInfo[i] ); + LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next ) { + if( bi->bi_destroy ) { + bi->bi_destroy( bi ); } } -#ifdef SLAPD_MODULES - if (backendInfo != slap_binfo) { - free(backendInfo); - } -#endif /* SLAPD_MODULES */ - nBackendInfo = 0; - backendInfo = NULL; + LDAP_STAILQ_INIT(&backendInfo); /* destroy frontend database */ bd = frontendDB; @@ -455,12 +477,12 @@ 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; } } @@ -481,25 +503,12 @@ backend_db_init( return NULL; } - be = backendDB; - - backendDB = (BackendDB *) ch_realloc( - (char *) backendDB, - (nBackendDB + 1) * sizeof(Backend) ); - - memset( &backendDB[nbackends], '\0', sizeof(Backend) ); - - /* did realloc move our table? if so, fix up dependent pointers */ - if ( be != backendDB ) { - int i; - for ( i=0, be=backendDB; ibe_pcl_mutexp = &be->be_pcl_mutex; - } - } - - be = &backends[nbackends++]; + be = ch_calloc( 1, sizeof(Backend) ); + nbackends++; + LDAP_STAILQ_INSERT_TAIL(&backendDB, be, be_next); be->bd_info = bi; + be->be_def_limit = frontendDB->be_def_limit; be->be_dfltaccess = frontendDB->be_dfltaccess; @@ -513,11 +522,11 @@ backend_db_init( /* assign a default depth limit for alias deref */ be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; - if(bi->bi_db_init) { + if ( bi->bi_db_init ) { rc = bi->bi_db_init( be ); } - if(rc != 0) { + if ( rc != 0 ) { fprintf( stderr, "database init failed (%s)\n", type ); nbackends--; return NULL; @@ -530,17 +539,19 @@ backend_db_init( void be_db_close( void ) { + BackendDB *be; int i; - 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 ); } } if ( frontendDB->bd_info->bi_db_close ) { (*frontendDB->bd_info->bi_db_close)( frontendDB ); } + } Backend * @@ -551,22 +562,21 @@ select_backend( { int i, j; ber_len_t len, dnlen = dn->bv_len; - Backend *be = NULL; + Backend *be, *b2 = NULL; - for ( i = 0; i < nbackends; i++ ) { - if ( backends[i].be_nsuffix == NULL ) { + LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { + if ( be->be_nsuffix == NULL ) { 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 */ @@ -583,25 +593,25 @@ 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( b2 == NULL ) { + b2 = be; if( manageDSAit && len == dnlen && !SLAP_GLUE_SUBORDINATE( be ) ) { continue; } } else { - be = &backends[i]; + b2 = be; } - return be; + return b2; } } } - return be; + return b2; } int @@ -683,20 +693,15 @@ be_isroot_pw( Operation *op ) return 0; } -#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, slap_sasl_bind, + op->o_conn->c_sasl_authctx, NULL ); #endif result = 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, slap_sasl_bind, NULL, NULL ); #endif return result == 0; @@ -721,15 +726,16 @@ be_entry_release_rw( int backend_unbind( Operation *op, SlapReply *rs ) { - int i; + int i = 0; + BackendDB *be; - for ( i = 0; i < nbackends; i++ ) { + LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { #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_pblock_set( op->o_pb, SLAPI_BACKEND, (void *)be ); + rc = slapi_int_call_plugins( be, SLAPI_PLUGIN_PRE_UNBIND_FN, (Slapi_PBlock *)op->o_pb ); if ( rc < 0 ) { /* @@ -744,13 +750,13 @@ backend_unbind( Operation *op, SlapReply *rs ) } #endif /* defined( LDAP_SLAPI ) */ - if ( backends[i].be_unbind ) { - op->o_bd = &backends[i]; - (*backends[i].be_unbind)( op, rs ); + if ( be->be_unbind ) { + op->o_bd = be; + be->be_unbind( op, rs ); } #if defined( LDAP_SLAPI ) - if ( op->o_pb != NULL && slapi_int_call_plugins( &backends[i], + if ( op->o_pb != NULL && slapi_int_call_plugins( be, SLAPI_PLUGIN_POST_UNBIND_FN, (Slapi_PBlock *)op->o_pb ) < 0 ) { Debug(LDAP_DEBUG_TRACE, @@ -758,6 +764,7 @@ backend_unbind( Operation *op, SlapReply *rs ) 0, 0, 0); } #endif /* defined( LDAP_SLAPI ) */ + i++; } return 0; @@ -767,11 +774,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 ); } } @@ -782,18 +789,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 ) @@ -803,28 +810,62 @@ backend_check_controls( if( ctrls ) { for( ; *ctrls != NULL ; ctrls++ ) { - /* KLUDGE: ldctl_iscritical munged by controls.c:get_ctrls() - * to ensure this check is enabled/disabled appropriately. - */ - if( (*ctrls)->ldctl_iscritical && !ldap_charray_inlist( - op->o_bd->be_controls, (*ctrls)->ldctl_oid ) ) - { - /* 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. - */ - rs->sr_text = "control unavailable in context"; - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + int cid; + + switch ( slap_global_control( op, (*ctrls)->ldctl_oid, &cid ) ) { + case LDAP_CONTROL_NOT_FOUND: + /* unrecognized control */ + if ( (*ctrls)->ldctl_iscritical ) { + /* should not be reachable */ + Debug( LDAP_DEBUG_ANY, + "backend_check_controls: unrecognized control: %s\n", + (*ctrls)->ldctl_oid, 0, 0 ); + assert( 0 ); + } + break; + + case LDAP_COMPARE_FALSE: + if ( !op->o_bd->be_ctrls[cid] && (*ctrls)->ldctl_iscritical ) { + /* 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 unavailable in a particular context, and the control + * is marked Critical, hence the return of + * unwillingToPerform. + */ + rs->sr_text = "critical control unavailable in context"; + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + goto done; + } break; + + case LDAP_COMPARE_TRUE: + break; + + default: + /* unreachable */ + 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; } } } + /* check should be generalized */ + if( get_manageDIT(op) && !be_isroot(op)) { + rs->sr_text = "requires manager authorization"; + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + } + +done:; return rs->sr_err; } @@ -843,8 +884,18 @@ backend_check_restrictions( int starttls = 0; int session = 0; - if( op->o_bd ) { - if ( backend_check_controls( op, rs ) != LDAP_SUCCESS ) { + if ( op->o_bd ) { + int rc = SLAP_CB_CONTINUE; + + if ( op->o_bd->be_chk_controls ) { + rc = ( *op->o_bd->be_chk_controls )( op, rs ); + } + + if ( rc == SLAP_CB_CONTINUE ) { + rc = backend_check_controls( op, rs ); + } + + if ( rc != LDAP_SUCCESS ) { return rs->sr_err; } @@ -1018,7 +1069,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; @@ -1097,7 +1151,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"; @@ -1241,7 +1296,7 @@ backend_group( } if ( rc == 0 ) { - rc = 1; + 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 ) @@ -1314,6 +1369,8 @@ loopit: SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, a->a_nvals, op_ndn, op->o_tmpmemctx ); + if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) + rc = LDAP_COMPARE_FALSE; } } else { rc = LDAP_NO_SUCH_ATTRIBUTE; @@ -1433,22 +1490,31 @@ backend_attribute( BER_BVZERO( &anlist[ 1 ].an_name ); rs.sr_attrs = anlist; - rs.sr_attr_flags = slap_attr_flags( rs.sr_attrs ); - - rc = backend_operational( op, &rs ); + /* NOTE: backend_operational() is also called + * when returning results, so it's supposed + * to do no harm to entries */ + rs.sr_entry = e; + rc = backend_operational( op, &rs ); + rs.sr_entry = NULL; + + if ( rc == LDAP_SUCCESS ) { + if ( rs.sr_operational_attrs ) { + freeattr = 1; + a = rs.sr_operational_attrs; - if ( rc == LDAP_SUCCESS && rs.sr_operational_attrs ) { - freeattr = 1; - a = rs.sr_operational_attrs; + } else { + rc = LDAP_NO_SUCH_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; } @@ -1458,11 +1524,10 @@ backend_attribute( 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 ) @@ -1521,6 +1586,144 @@ 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) +{ + struct berval *nval = (struct berval *)c->cac_private; + Operation *op = NULL; + + slapi_pblock_get( c->cac_pb, SLAPI_OPERATION, &op ); + if ( op == NULL ) { + return 1; + } + + return access_allowed( op, e, a->a_desc, nval, ACL_AUTH, NULL ) == 0; +} +#endif /* LDAP_SLAPI */ + +int +backend_access( + Operation *op, + Entry *target, + struct berval *edn, + AttributeDescription *entry_at, + struct berval *nval, + slap_access_t access, + slap_mask_t *mask ) +{ + Entry *e = NULL; + int rc = LDAP_INSUFFICIENT_ACCESS; + Backend *be = op->o_bd; + + /* pedantic */ + assert( op ); + assert( op->o_conn ); + assert( edn ); + assert( access > ACL_NONE ); + + op->o_bd = select_backend( edn, 0, 0 ); + + if ( target && dn_match( &target->e_nname, edn ) ) { + e = target; + + } else { + rc = be_entry_get_rw( op, edn, NULL, entry_at, 0, &e ); + } + + if ( e ) { + Attribute *a = NULL; + int freeattr = 0; + + if ( entry_at == NULL ) { + entry_at = slap_schema.si_ad_entry; + } + + if ( entry_at == slap_schema.si_ad_entry || entry_at == slap_schema.si_ad_children ) + { + if ( access_allowed_mask( op, e, entry_at, + NULL, access, NULL, mask ) == 0 ) + { + rc = LDAP_INSUFFICIENT_ACCESS; + + } else { + rc = LDAP_SUCCESS; + } + + } else { + a = attr_find( e->e_attrs, entry_at ); + if ( a == NULL ) { + SlapReply rs = { 0 }; + AttributeName anlist[ 2 ]; + + anlist[ 0 ].an_name = entry_at->ad_cname; + anlist[ 0 ].an_desc = entry_at; + BER_BVZERO( &anlist[ 1 ].an_name ); + rs.sr_attrs = anlist; + + rs.sr_attr_flags = slap_attr_flags( rs.sr_attrs ); + + /* NOTE: backend_operational() is also called + * when returning results, so it's supposed + * to do no harm to entries */ + rs.sr_entry = e; + rc = backend_operational( op, &rs ); + rs.sr_entry = NULL; + + if ( rc == LDAP_SUCCESS ) { + if ( rs.sr_operational_attrs ) { + freeattr = 1; + a = rs.sr_operational_attrs; + + } else { + rc = LDAP_NO_SUCH_OBJECT; + } + } + } + + if ( a ) { + if ( access_allowed_mask( op, e, entry_at, + nval, access, NULL, mask ) == 0 ) + { + rc = LDAP_INSUFFICIENT_ACCESS; + goto freeit; + } + 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 ) { + be_entry_release_r( op, e ); + } + if ( freeattr ) { + attr_free( a ); + } + } + + op->o_bd = be; + return rc; +} + int backend_operational( Operation *op, SlapReply *rs ) @@ -1537,15 +1740,15 @@ int backend_operational( * and the backend supports specific operational attributes, * add them to the attribute list */ - if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( op->ors_attrs && - ad_inlist( slap_schema.si_ad_entryDN, op->ors_attrs ))) + if ( 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 ) || ( op->ors_attrs && - ad_inlist( slap_schema.si_ad_subschemaSubentry, op->ors_attrs ))) + if ( 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; @@ -1553,24 +1756,13 @@ int backend_operational( /* Let the overlays have a chance at this */ be_orig = op->o_bd; - if ( SLAP_ISOVERLAY( be_orig )) + if ( SLAP_ISOVERLAY( be_orig ) ) op->o_bd = select_backend( be_orig->be_nsuffix, 0, 0 ); - if (( SLAP_OPATTRS( rs->sr_attr_flags ) || op->ors_attrs ) && + if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) && op->o_bd && 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;