diff options
Diffstat (limited to 'ldap/servers/slapd/back-ldbm/id2entry.c')
-rw-r--r-- | ldap/servers/slapd/back-ldbm/id2entry.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/ldap/servers/slapd/back-ldbm/id2entry.c b/ldap/servers/slapd/back-ldbm/id2entry.c new file mode 100644 index 00000000..7c5a00c2 --- /dev/null +++ b/ldap/servers/slapd/back-ldbm/id2entry.c @@ -0,0 +1,250 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* id2entry.c - routines to deal with the id2entry index */ + +#include "back-ldbm.h" + +/* + * The caller MUST check for DB_LOCK_DEADLOCK and DB_RUNRECOVERY returned + */ +int +id2entry_add_ext( backend *be, struct backentry *e, back_txn *txn, int encrypt ) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private; + ldbm_instance *inst = (ldbm_instance *) be->be_instance_info; + DB *db = NULL; + DB_TXN *db_txn = NULL; + DBT data = {0}; + DBT key = {0}; + int len, rc; + char temp_id[sizeof(ID)]; + struct backentry *encrypted_entry = NULL; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> id2entry_add( %lu, \"%s\" )\n", + (u_long)e->ep_id, backentry_get_ndn(e), 0 ); + + if ( (rc = dblayer_get_id2entry( be, &db )) != 0 ) { + LDAPDebug( LDAP_DEBUG_ANY, "Could not open/create id2entry\n", + 0, 0, 0 ); + return( -1 ); + } + + id_internal_to_stored(e->ep_id,temp_id); + + key.dptr = temp_id; + key.dsize = sizeof(temp_id); + + /* Encrypt attributes in this entry if necessary */ + if (encrypt) { + rc = attrcrypt_encrypt_entry(be, e, &encrypted_entry); + if (rc) { + LDAPDebug( LDAP_DEBUG_ANY, "attrcrypt_encrypt_entry failed in id2entry_add\n", + 0, 0, 0 ); + return ( -1 ); + } + } + + { + Slapi_Entry *entry_to_use = encrypted_entry ? encrypted_entry->ep_entry : e->ep_entry; + data.dptr = slapi_entry2str_with_options( entry_to_use, &len, SLAPI_DUMP_STATEINFO | SLAPI_DUMP_UNIQUEID); + data.dsize = len + 1; + /* If we had an encrypted entry, we no longer need it */ + if (encrypted_entry) { + backentry_free(&encrypted_entry); + } + } + + if (NULL != txn) { + db_txn = txn->back_txn_txn; + } + + /* call pre-entry-store plugin */ + plugin_call_entrystore_plugins( (char **) &data.dptr, &data.dsize ); + + /* store it */ + rc = db->put( db, db_txn, &key, &data, 0); + /* DBDB looks like we're freeing memory allocated by another DLL, which is bad */ + free( data.dptr ); + + dblayer_release_id2entry( be, db ); + + if (0 == rc) + { + /* DBDB the fact that we don't check the return code here is + * indicitive that there may be a latent race condition lurking + * ---what happens if the entry is already in the cache by this point? + */ + /* + * For ldbm_back_add and ldbm_back_modify, this entry had been already + * reserved as a tentative entry. So, it should be safe. + * For ldbm_back_modify, the original entry having the same dn/id + * should be in the cache. Thus, this entry e won't be put into the + * entry cache. It'll be added by cache_replace. + */ + (void) cache_add( &inst->inst_cache, e, NULL ); + } + + LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry_add %d\n", rc, 0, 0 ); + return( rc ); +} + +int +id2entry_add( backend *be, struct backentry *e, back_txn *txn ) +{ + return id2entry_add_ext(be,e,txn,1); +} + +/* + * The caller MUST check for DB_LOCK_DEADLOCK and DB_RUNRECOVERY returned + */ +int +id2entry_delete( backend *be, struct backentry *e, back_txn *txn ) +{ + DB *db = NULL; + DB_TXN *db_txn = NULL; + DBT key = {0}; + int rc; + char temp_id[sizeof(ID)]; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> id2entry_delete( %lu, \"%s\" )\n", + (u_long)e->ep_id, backentry_get_ndn(e), 0 ); + + if ( (rc = dblayer_get_id2entry( be, &db )) != 0 ) { + LDAPDebug( LDAP_DEBUG_ANY, "Could not open/create id2entry\n", + 0, 0, 0 ); + return( -1 ); + } + + id_internal_to_stored(e->ep_id,temp_id); + + key.dptr = temp_id; + key.dsize = sizeof(temp_id); + + if (NULL != txn) { + db_txn = txn->back_txn_txn; + } + + rc = db->del( db,db_txn,&key,0 ); + dblayer_release_id2entry( be, db ); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry_delete %d\n", rc, 0, 0 ); + return( rc ); +} + +struct backentry * +id2entry( backend *be, ID id, back_txn *txn, int *err ) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private; + ldbm_instance *inst = (ldbm_instance *) be->be_instance_info; + DB *db = NULL; + DB_TXN *db_txn = NULL; + DBT key = {0}; + DBT data = {0}; + struct backentry *e; + Slapi_Entry *ee; + char temp_id[sizeof(ID)]; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> id2entry( %lu )\n", (u_long)id, 0, 0 ); + + if ( (e = cache_find_id( &inst->inst_cache, id )) != NULL ) { + LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry %p (cache)\n", e, 0, + 0 ); + return( e ); + } + + if ( (*err = dblayer_get_id2entry( be, &db )) != 0 ) { + LDAPDebug( LDAP_DEBUG_ANY, "Could not open id2entry err %d\n", + *err, 0, 0 ); + return( NULL ); + } + + + id_internal_to_stored(id,temp_id); + + key.data = temp_id; + key.size = sizeof(temp_id); + + /* DBDB need to improve this, we're mallocing, freeing, all over the place here */ + data.flags = DB_DBT_MALLOC; + + if (NULL != txn) { + db_txn = txn->back_txn_txn; + } + do { + *err = db->get( db, db_txn, &key, &data, 0 ); + if ( 0 != *err && + DB_NOTFOUND != *err && DB_LOCK_DEADLOCK != *err ) + { + LDAPDebug( LDAP_DEBUG_ANY, "id2entry error %d\n", + *err, 0, 0 ); + } + } + while ( DB_LOCK_DEADLOCK == *err && txn == NULL ); + + if ( 0 != *err && DB_NOTFOUND != *err && DB_LOCK_DEADLOCK != *err ) + { + LDAPDebug( LDAP_DEBUG_ANY, "id2entry get error %d\n", + *err, 0, 0 ); + dblayer_release_id2entry( be, db ); + return( NULL ); + } + + if ( data.dptr == NULL ) { + LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry( %lu ) not found\n", + (u_long)id, 0, 0 ); + dblayer_release_id2entry( be, db ); + return( NULL ); + } + + /* call post-entry plugin */ + plugin_call_entryfetch_plugins( (char **) &data.dptr, &data.dsize ); + + if ( (ee = slapi_str2entry( data.dptr, 0 )) != NULL ) { + int retval = 0; + struct backentry *imposter = NULL; + + PR_ASSERT(slapi_entry_get_uniqueid(ee) != NULL); /* All entries should have uniqueids */ + e = backentry_init( ee ); /* ownership of the entry is passed into the backentry */ + e->ep_id = id; + + /* Decrypt any encrypted attributes in this entry, before adding it to the cache */ + retval = attrcrypt_decrypt_entry(be, e); + if (retval) { + LDAPDebug( LDAP_DEBUG_ANY, "attrcrypt_decrypt_entry failed in id2entry\n", + 0, 0, 0 ); + } + + retval = cache_add( &inst->inst_cache, e, &imposter ); + if (1 == retval) { + /* This means that someone else put the entry in the cache + while we weren't looking ! So, we need to use the pointer + returned and free the one we made earlier */ + if (imposter) + { + backentry_free(&e); + e = imposter; + } + } else if (-1 == retval) { + /* the entry is in idtable but not in dntable, i.e., the entry + * could have been renamed */ + LDAPDebug( LDAP_DEBUG_TRACE, + "id2entry: failed to put entry (id %lu, dn %s) into entry cache\n", + (u_long)id, backentry_get_ndn(e), 0 ); + } + } else { + LDAPDebug( LDAP_DEBUG_ANY, "str2entry returned NULL for id %lu, string=\"%s\"\n", (u_long)id, (char*)data.data, 0); + e = NULL; + } + + free( data.data ); + + dblayer_release_id2entry( be, db ); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry( %lu ) %p (disk)\n", (u_long)id, e, + 0 ); + return( e ); +} + |