1
0

id2entry.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* id2entry.c - routines to deal with the id2entry index */
  42. #include "back-ldbm.h"
  43. /*
  44. * The caller MUST check for DB_LOCK_DEADLOCK and DB_RUNRECOVERY returned
  45. */
  46. int
  47. id2entry_add_ext( backend *be, struct backentry *e, back_txn *txn, int encrypt )
  48. {
  49. ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
  50. DB *db = NULL;
  51. DB_TXN *db_txn = NULL;
  52. DBT data;
  53. DBT key;
  54. int len, rc;
  55. char temp_id[sizeof(ID)];
  56. struct backentry *encrypted_entry = NULL;
  57. LDAPDebug( LDAP_DEBUG_TRACE, "=> id2entry_add( %lu, \"%s\" )\n",
  58. (u_long)e->ep_id, backentry_get_ndn(e), 0 );
  59. if ( (rc = dblayer_get_id2entry( be, &db )) != 0 ) {
  60. LDAPDebug( LDAP_DEBUG_ANY, "Could not open/create id2entry\n",
  61. 0, 0, 0 );
  62. return( -1 );
  63. }
  64. id_internal_to_stored(e->ep_id,temp_id);
  65. memset(&key, 0, sizeof(key));
  66. key.dptr = temp_id;
  67. key.dsize = sizeof(temp_id);
  68. /* Encrypt attributes in this entry if necessary */
  69. if (encrypt) {
  70. rc = attrcrypt_encrypt_entry(be, e, &encrypted_entry);
  71. if (rc) {
  72. LDAPDebug( LDAP_DEBUG_ANY, "attrcrypt_encrypt_entry failed in id2entry_add\n",
  73. 0, 0, 0 );
  74. return ( -1 );
  75. }
  76. }
  77. {
  78. Slapi_Entry *entry_to_use = encrypted_entry ? encrypted_entry->ep_entry : e->ep_entry;
  79. memset(&data, 0, sizeof(data));
  80. data.dptr = slapi_entry2str_with_options( entry_to_use, &len, SLAPI_DUMP_STATEINFO | SLAPI_DUMP_UNIQUEID);
  81. data.dsize = len + 1;
  82. /* If we had an encrypted entry, we no longer need it */
  83. if (encrypted_entry) {
  84. backentry_free(&encrypted_entry);
  85. }
  86. }
  87. if (NULL != txn) {
  88. db_txn = txn->back_txn_txn;
  89. }
  90. /* call pre-entry-store plugin */
  91. plugin_call_entrystore_plugins( (char **) &data.dptr, &data.dsize );
  92. /* store it */
  93. rc = db->put( db, db_txn, &key, &data, 0);
  94. /* DBDB looks like we're freeing memory allocated by another DLL, which is bad */
  95. slapi_ch_free( &(data.dptr) );
  96. dblayer_release_id2entry( be, db );
  97. if (0 == rc)
  98. {
  99. /* DBDB the fact that we don't check the return code here is
  100. * indicitive that there may be a latent race condition lurking
  101. * ---what happens if the entry is already in the cache by this point?
  102. */
  103. /*
  104. * For ldbm_back_add and ldbm_back_modify, this entry had been already
  105. * reserved as a tentative entry. So, it should be safe.
  106. * For ldbm_back_modify, the original entry having the same dn/id
  107. * should be in the cache. Thus, this entry e won't be put into the
  108. * entry cache. It'll be added by cache_replace.
  109. */
  110. (void) cache_add( &inst->inst_cache, e, NULL );
  111. }
  112. LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry_add %d\n", rc, 0, 0 );
  113. return( rc );
  114. }
  115. int
  116. id2entry_add( backend *be, struct backentry *e, back_txn *txn )
  117. {
  118. return id2entry_add_ext(be,e,txn,1);
  119. }
  120. /*
  121. * The caller MUST check for DB_LOCK_DEADLOCK and DB_RUNRECOVERY returned
  122. */
  123. int
  124. id2entry_delete( backend *be, struct backentry *e, back_txn *txn )
  125. {
  126. DB *db = NULL;
  127. DB_TXN *db_txn = NULL;
  128. DBT key = {0};
  129. int rc;
  130. char temp_id[sizeof(ID)];
  131. LDAPDebug( LDAP_DEBUG_TRACE, "=> id2entry_delete( %lu, \"%s\" )\n",
  132. (u_long)e->ep_id, backentry_get_ndn(e), 0 );
  133. if ( (rc = dblayer_get_id2entry( be, &db )) != 0 ) {
  134. LDAPDebug( LDAP_DEBUG_ANY, "Could not open/create id2entry\n",
  135. 0, 0, 0 );
  136. return( -1 );
  137. }
  138. id_internal_to_stored(e->ep_id,temp_id);
  139. key.dptr = temp_id;
  140. key.dsize = sizeof(temp_id);
  141. if (NULL != txn) {
  142. db_txn = txn->back_txn_txn;
  143. }
  144. rc = db->del( db,db_txn,&key,0 );
  145. dblayer_release_id2entry( be, db );
  146. LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry_delete %d\n", rc, 0, 0 );
  147. return( rc );
  148. }
  149. struct backentry *
  150. id2entry( backend *be, ID id, back_txn *txn, int *err )
  151. {
  152. ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
  153. DB *db = NULL;
  154. DB_TXN *db_txn = NULL;
  155. DBT key = {0};
  156. DBT data = {0};
  157. struct backentry *e;
  158. Slapi_Entry *ee;
  159. char temp_id[sizeof(ID)];
  160. LDAPDebug( LDAP_DEBUG_TRACE, "=> id2entry( %lu )\n", (u_long)id, 0, 0 );
  161. if ( (e = cache_find_id( &inst->inst_cache, id )) != NULL ) {
  162. LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry %p (cache)\n", e, 0,
  163. 0 );
  164. return( e );
  165. }
  166. if ( (*err = dblayer_get_id2entry( be, &db )) != 0 ) {
  167. LDAPDebug( LDAP_DEBUG_ANY, "Could not open id2entry err %d\n",
  168. *err, 0, 0 );
  169. return( NULL );
  170. }
  171. id_internal_to_stored(id,temp_id);
  172. key.data = temp_id;
  173. key.size = sizeof(temp_id);
  174. /* DBDB need to improve this, we're mallocing, freeing, all over the place here */
  175. data.flags = DB_DBT_MALLOC;
  176. if (NULL != txn) {
  177. db_txn = txn->back_txn_txn;
  178. }
  179. do {
  180. *err = db->get( db, db_txn, &key, &data, 0 );
  181. if ( (0 != *err) &&
  182. (DB_NOTFOUND != *err) && (DB_LOCK_DEADLOCK != *err) )
  183. {
  184. LDAPDebug( LDAP_DEBUG_ANY,
  185. "id2entry: libdb returned error %d (%s)\n",
  186. *err, dblayer_strerror( *err ), 0 );
  187. }
  188. }
  189. while ( (DB_LOCK_DEADLOCK == *err) && (txn == NULL) );
  190. if ( (0 != *err) && (DB_NOTFOUND != *err) && (DB_LOCK_DEADLOCK != *err) )
  191. {
  192. if ( (ENOMEM == *err) && (data.dptr == NULL) )
  193. {
  194. /*
  195. * Now we are setting slapi_ch_malloc and its friends to libdb
  196. * by ENV->set_alloc in dblayer.c. As long as the functions are
  197. * used by libdb, it won't reach here.
  198. */
  199. LDAPDebug( LDAP_DEBUG_ANY,
  200. "malloc failed in libdb; terminating the server; OS error %d (%s)\n",
  201. *err, slapd_system_strerror( *err ), 0 );
  202. exit (1);
  203. }
  204. dblayer_release_id2entry( be, db );
  205. return( NULL );
  206. }
  207. if ( data.dptr == NULL ) {
  208. LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry( %lu ) not found\n",
  209. (u_long)id, 0, 0 );
  210. dblayer_release_id2entry( be, db );
  211. return( NULL );
  212. }
  213. /* call post-entry plugin */
  214. plugin_call_entryfetch_plugins( (char **) &data.dptr, &data.dsize );
  215. if ( (ee = slapi_str2entry( data.dptr, 0 )) != NULL ) {
  216. int retval = 0;
  217. struct backentry *imposter = NULL;
  218. PR_ASSERT(slapi_entry_get_uniqueid(ee) != NULL); /* All entries should have uniqueids */
  219. e = backentry_init( ee ); /* ownership of the entry is passed into the backentry */
  220. e->ep_id = id;
  221. /* Decrypt any encrypted attributes in this entry, before adding it to the cache */
  222. retval = attrcrypt_decrypt_entry(be, e);
  223. if (retval) {
  224. LDAPDebug( LDAP_DEBUG_ANY, "attrcrypt_decrypt_entry failed in id2entry\n",
  225. 0, 0, 0 );
  226. }
  227. retval = cache_add( &inst->inst_cache, e, &imposter );
  228. if (1 == retval) {
  229. /* This means that someone else put the entry in the cache
  230. while we weren't looking ! So, we need to use the pointer
  231. returned and free the one we made earlier */
  232. if (imposter)
  233. {
  234. backentry_free(&e);
  235. e = imposter;
  236. }
  237. } else if (-1 == retval) {
  238. /* the entry is in idtable but not in dntable, i.e., the entry
  239. * could have been renamed */
  240. LDAPDebug( LDAP_DEBUG_TRACE,
  241. "id2entry: failed to put entry (id %lu, dn %s) into entry cache\n",
  242. (u_long)id, backentry_get_ndn(e), 0 );
  243. }
  244. } else {
  245. LDAPDebug( LDAP_DEBUG_ANY, "str2entry returned NULL for id %lu, string=\"%s\"\n", (u_long)id, (char*)data.data, 0);
  246. e = NULL;
  247. }
  248. slapi_ch_free( &(data.data) );
  249. dblayer_release_id2entry( be, db );
  250. LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry( %lu ) %p (disk)\n", (u_long)id, e,
  251. 0 );
  252. return( e );
  253. }