X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fbackend.c;h=f64e661ea75ba9fcd7ff92e61a44acbb2121ac16;hb=ac3ad635ef0883d96b5424f96b2c43e13b0ad659;hp=84724bb58804dc25aea5a1b4e1c95382eaad7658;hpb=d68041ce50a1a0444d65b8b8e5081870da3ab058;p=openldap diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 84724bb588..f64e661ea7 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -62,19 +62,40 @@ BackendInfo *backendInfo = NULL; int nBackendDB = 0; BackendDB *backendDB = NULL; -ldap_pvt_thread_pool_t syncrepl_pool; -int syncrepl_pool_max = SLAP_MAX_SYNCREPL_THREADS; +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 ); + } + + return -1; + } + + bi->bi_ctrls[ cid ] = 1; + } + } + + return 0; +} int backend_init(void) { int rc = -1; - ldap_pvt_thread_pool_init( &syncrepl_pool, syncrepl_pool_max, 0 ); - if((nBackendInfo != 0) || (backendInfo != NULL)) { /* already initialized */ Debug( LDAP_DEBUG_ANY, - "backend_init: already initialized.\n", 0, 0, 0 ); + "backend_init: already initialized\n", 0, 0, 0 ); return -1; } @@ -132,12 +153,15 @@ 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 */ { @@ -161,12 +185,43 @@ int backend_add(BackendInfo *aBackendInfo) } } +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 { + int i; + + for ( i = 0; i < SLAP_MAX_CIDS; i++ ) { + if ( bi->bi_ctrls[ i ] ) { + be->be_ctrls[ i ] = bi->bi_ctrls[ i ]; + } + } + } + + } + + 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 +229,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; } @@ -235,8 +298,7 @@ int backend_startup(Backend *be) } if( backendInfo[i].bi_open ) { - rc = backendInfo[i].bi_open( - &backendInfo[i] ); + rc = backendInfo[i].bi_open( &backendInfo[i] ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "backend_startup: bi_open %d failed!\n", @@ -244,6 +306,8 @@ int backend_startup(Backend *be) return rc; } } + + (void)backend_init_controls( &backendInfo[i] ); } ldap_pvt_thread_mutex_init( &slapd_rq.rq_mutex ); @@ -374,8 +438,6 @@ int backend_destroy(void) BackendDB *bd; struct slap_csn_entry *csne; - ldap_pvt_thread_pool_destroy( &syncrepl_pool, 1 ); - /* destroy each backend database */ for( i = 0, bd = backendDB; i < nBackendDB; i++, bd++ ) { @@ -500,6 +562,7 @@ backend_db_init( be = &backends[nbackends++]; be->bd_info = bi; + be->be_def_limit = frontendDB->be_def_limit; be->be_dfltaccess = frontendDB->be_dfltaccess; @@ -513,11 +576,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; @@ -541,6 +604,7 @@ be_db_close( void ) if ( frontendDB->bd_info->bi_db_close ) { (*frontendDB->bd_info->bi_db_close)( frontendDB ); } + } Backend * @@ -793,7 +857,7 @@ backend_connection_destroy( return 0; } -static int +int backend_check_controls( Operation *op, SlapReply *rs ) @@ -803,30 +867,51 @@ backend_check_controls( if( ctrls ) { for( ; *ctrls != NULL ; ctrls++ ) { - 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 - * (regardless of the criticality of the control). - * - * Here we find that operation extended by the control - * is not unavailable in a particular context, hence the - * return of unwillingToPerform. - * - * FIXME: As noted above, this check should be done - * regardless of the criticality of the control. The - * frontend infrastructure doesn't (yet) support this. - */ - 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 ] ) + { + /* 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; + goto done; + } + break; + + case LDAP_COMPARE_TRUE: + break; + + default: + /* unreachable */ + rs->sr_text = "unable to check control"; + rs->sr_err = LDAP_OTHER; + goto done; } } } +done:; return rs->sr_err; } @@ -845,8 +930,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; } @@ -1435,13 +1530,21 @@ 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; + } } } @@ -1523,6 +1626,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 ) @@ -1539,15 +1780,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; @@ -1558,21 +1799,10 @@ int backend_operational( 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;