X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fbackend.c;h=3233f65e8fe44a12493a5c08a3ae6b1c38efca6f;hb=b60644a07fc620d8e1f367e828355e6babc8d44f;hp=6cb351feacb1f955229fa8b964c6f516eb85d14c;hpb=0de20c028f1bdbc126e06f5a49568eac0d5317c1;p=openldap diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 6cb351feac..3233f65e8f 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-2006 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -196,7 +196,7 @@ int backend_startup_one(Backend *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 ); @@ -248,6 +248,8 @@ int backend_startup(Backend *be) return rc; } } + /* append global access controls */ + acl_append( &be->be_acl, frontendDB->be_acl, -1 ); return backend_startup_one( be ); } @@ -382,16 +384,18 @@ int backend_shutdown( Backend *be ) return 0; } -void backend_destroy_one( BackendDB *bd, int dynamic ) +/* + * 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 ) { - if ( dynamic ) { - LDAP_STAILQ_REMOVE(&backendDB, bd, slap_backend_db, be_next ); - } - - if ( bd->be_syncinfo ) { - syncinfo_free( bd->be_syncinfo ); - } - if ( bd->be_pending_csn_list ) { struct slap_csn_entry *csne; csne = LDAP_TAILQ_FIRST( bd->be_pending_csn_list ); @@ -409,6 +413,20 @@ void backend_destroy_one( BackendDB *bd, int dynamic ) if ( bd->bd_info->bi_db_destroy ) { bd->bd_info->bi_db_destroy( bd ); } +} + +void backend_destroy_one( BackendDB *bd, int dynamic ) +{ + if ( dynamic ) { + LDAP_STAILQ_REMOVE(&backendDB, bd, slap_backend_db, be_next ); + } + + if ( bd->be_syncinfo ) { + syncinfo_free( bd->be_syncinfo ); + } + + backend_stopdown_one( bd ); + ber_bvarray_free( bd->be_suffix ); ber_bvarray_free( bd->be_nsuffix ); if ( !BER_BVISNULL( &bd->be_rootdn ) ) { @@ -422,6 +440,23 @@ void backend_destroy_one( BackendDB *bd, int dynamic ) } acl_destroy( bd->be_acl, frontendDB->be_acl ); limits_destroy( bd->be_limits ); + if ( bd->be_replogfile ) { + ch_free( bd->be_replogfile ); + } + if ( bd->be_replica_argsfile ) { + ch_free( bd->be_replica_argsfile ); + } + if ( bd->be_replica_pidfile ) { + ch_free( bd->be_replica_pidfile ); + } + destroy_replica_info( bd ); + 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 ); + } + if ( dynamic ) { free( bd ); } @@ -465,6 +500,17 @@ int backend_destroy(void) free( bd->be_rootpw.bv_val ); } acl_destroy( bd->be_acl, frontendDB->be_acl ); + + if ( bd->be_replogfile != NULL ) { + free( bd->be_replogfile ); + } + if ( bd->be_replica_argsfile ) { + ch_free( bd->be_replica_argsfile ); + } + if ( bd->be_replica_pidfile ) { + ch_free( bd->be_replica_pidfile ); + } + assert( bd->be_replica == NULL ); } return 0; @@ -484,13 +530,48 @@ BackendInfo* backend_info(const char *type) 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; i= nbackends ) + idx = -1; + nbackends++; + backend_db_insert( be, idx ); + } be->bd_info = bi; @@ -523,11 +612,16 @@ backend_db_init( 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, slap_backend_db, be_next); + ch_free( be ); + be = NULL; + nbackends--; + } + } else { + bi->bi_nDB++; } - - bi->bi_nDB++; return( be ); } @@ -543,7 +637,7 @@ be_db_close( void ) } if ( frontendDB->bd_info->bi_db_close ) { - (*frontendDB->bd_info->bi_db_close)( frontendDB ); + frontendDB->bd_info->bi_db_close( frontendDB ); } } @@ -559,7 +653,7 @@ select_backend( Backend *be, *b2 = NULL; LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { - if ( be->be_nsuffix == NULL ) { + if ( be->be_nsuffix == NULL || SLAP_DBHIDDEN( be )) { continue; } @@ -598,7 +692,13 @@ select_backend( continue; } } else { - b2 = be; + /* If any parts of the tree are glued, use the first + * match regardless of manageDSAit. Otherwise use the + * last match. + */ + if( !( SLAP_DBFLAGS( be ) & ( SLAP_DBFLAG_GLUE_INSTANCE | + SLAP_DBFLAG_GLUE_SUBORDINATE ))) + b2 = be; } return b2; } @@ -648,7 +748,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 ) ) ); } @@ -779,27 +882,26 @@ 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] && (*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. + /* 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 = "critical control unavailable in context"; - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; goto done; } break; @@ -821,11 +923,13 @@ backend_check_controls( } } +#if 0 /* temporarily removed */ /* check should be generalized */ - if( get_manageDIT(op) && !be_isroot(op)) { + 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; @@ -1167,19 +1271,17 @@ 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 @@ -1192,6 +1294,7 @@ fe_acl_group( AttributeDescription *group_at ) { Entry *e; + void *o_priv = op->o_private, *e_priv = NULL; Attribute *a; int rc; GroupAssertion *g; @@ -1219,7 +1322,10 @@ fe_acl_group( 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 ) { a = attr_find( e->e_attrs, group_at ); @@ -1235,13 +1341,17 @@ fe_acl_group( struct berval bv, nbase; Filter *filter; Entry *user; + 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 ); + op->o_private = NULL; rc = be_entry_get_rw(op, op_ndn, NULL, NULL, 0, &user ); + user_priv = op->o_private; + op->o_private = o_priv; } if ( rc == 0 ) { @@ -1283,14 +1393,12 @@ fe_acl_group( goto loopit; } break; -#ifdef LDAP_SCOPE_SUBORDINATE case LDAP_SCOPE_SUBORDINATE: if ( dn_match( &nbase, op_ndn ) || !dnIsSuffix( op_ndn, &nbase ) ) { goto loopit; } -#endif } filter = str2filter_x( op, ludp->lud_filter ); if ( filter ) { @@ -1309,7 +1417,9 @@ loopit: if ( rc == 0 ) break; } if ( user != target ) { + op->o_private = user_priv; be_entry_release_r( op, user ); + op->o_private = o_priv; } } op->o_bd = b2; @@ -1324,8 +1434,10 @@ loopit: } 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; @@ -1383,6 +1495,7 @@ fe_acl_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; @@ -1394,10 +1507,26 @@ fe_acl_attribute( 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 }; @@ -1470,7 +1599,9 @@ fe_acl_attribute( } } 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 ); @@ -1513,6 +1644,7 @@ 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; @@ -1528,7 +1660,10 @@ backend_access( 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 ) { @@ -1592,7 +1727,9 @@ backend_access( } } 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 ); @@ -1610,7 +1747,6 @@ fe_aux_operational( { Attribute **ap; int rc = 0; - BackendDB *be_orig; for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) /* just count them */ ; @@ -1620,28 +1756,30 @@ fe_aux_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; } - if ( op->o_bd != NULL && op->o_bd != frontendDB ) - { - /* Let the overlays have a chance at this */ - be_orig = op->o_bd; - op->o_bd = select_backend( &op->o_ndn, 0, 0 ); + if ( op->o_bd != NULL ) { + BackendDB *be_orig = op->o_bd; - if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) && - op->o_bd != NULL && op->o_bd->be_operational != NULL ) + /* Let the overlays have a chance at this */ + op->o_bd = select_backend( &op->o_req_ndn, 0, 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 ) { rc = op->o_bd->be_operational( op, rs ); }