dse.c 87 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /*
  13. * dse.c - DSE (DSA-Specific Entry) persistent storage.
  14. *
  15. * The DSE store is an LDIF file contained in the file dse.ldif.
  16. * The file is located in the directory specified with '-D'
  17. * when staring the server.
  18. *
  19. * In core, the DSEs are stored in an AVL tree, keyed on
  20. * DN. Whenever a modification is made to a DSE, the
  21. * in-core entry is updated, then dse_write_file() is
  22. * called to commit the changes to disk.
  23. *
  24. * This is designed for a small number of DSEs, say
  25. * a maximum of 10 or 20. If large numbers of DSEs
  26. * need to be stored, this approach of writing out
  27. * the entire contents on every modification will
  28. * be insufficient.
  29. *
  30. */
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <fcntl.h>
  34. #include <errno.h>
  35. #include <prio.h>
  36. #include <prcountr.h>
  37. #include "slap.h"
  38. #include <pwd.h>
  39. /* #define SLAPI_DSE_DEBUG */ /* define this to force trace log */
  40. /* messages to always be logged */
  41. #ifdef SLAPI_DSE_DEBUG
  42. #define SLAPI_DSE_TRACELEVEL LDAP_DEBUG_ANY
  43. #else /* SLAPI_DSE_DEBUG */
  44. #define SLAPI_DSE_TRACELEVEL LDAP_DEBUG_TRACE
  45. #endif /* SLAPI_DSE_DEBUG */
  46. #define SCHEMA_VIOLATION -2
  47. #define STOP_TRAVERSAL -2
  48. /* This is returned by dupentry_replace if the duplicate entry was found and
  49. replaced. This is returned up through the avl_insert() in
  50. dse_replace_entry(). Otherwise, if avl_insert() returns 0, the
  51. entry was added i.e. a duplicate was not found.
  52. */
  53. #define DSE_ENTRY_WAS_REPLACED -3
  54. /* This is returned by dupentry_merge if the duplicate entry was found and
  55. merged. This is returned up through the avl_insert() in dse_add_entry_pb().
  56. Otherwise, if avl_insert() returns 0, the
  57. entry was added i.e. a duplicate was not found.
  58. */
  59. #define DSE_ENTRY_WAS_MERGED -4
  60. /* some functions can be used either from within a lock or "standalone" */
  61. #define DSE_USE_LOCK 1
  62. #define DSE_NO_LOCK 0
  63. struct dse_callback
  64. {
  65. int operation;
  66. int flags;
  67. Slapi_DN *base;
  68. int scope;
  69. char *filter; /* NULL means match all entries */
  70. Slapi_Filter *slapifilter; /* NULL means match all entries */
  71. int (*fn)(Slapi_PBlock *,Slapi_Entry *,Slapi_Entry *,int*,char*,void *);
  72. void *fn_arg;
  73. struct slapdplugin *plugin;
  74. struct dse_callback *next;
  75. };
  76. struct dse
  77. {
  78. char *dse_filename; /* these are the primary files which get read from */
  79. char *dse_tmpfile; /* and written to when changes are made via LDAP */
  80. char *dse_fileback; /* contain the latest info, just before a new change */
  81. char *dse_filestartOK; /* contain the latest info with which the server has successfully started */
  82. Avlnode *dse_tree;
  83. struct dse_callback *dse_callback;
  84. Slapi_RWLock *dse_rwlock; /* a read-write lock to protect the whole dse backend */
  85. char **dse_filelist; /* these are additional read only files used to */
  86. /* initialize the dse */
  87. int dse_is_updateable; /* if non-zero, this DSE can be written to */
  88. int dse_readonly_error_reported; /* used to ensure that read-only errors are logged only once */
  89. };
  90. struct dse_node
  91. {
  92. Slapi_Entry *entry;
  93. };
  94. /* search set stuff - used to pass search results to the frontend */
  95. typedef struct dse_search_set
  96. {
  97. DataList dl;
  98. int current_entry;
  99. } dse_search_set;
  100. static int dse_permission_to_write(struct dse* pdse, int loglevel);
  101. static int dse_write_file_nolock(struct dse* pdse);
  102. static int dse_apply_nolock(struct dse* pdse, IFP fp, caddr_t arg);
  103. static int dse_replace_entry( struct dse* pdse, Slapi_Entry *e, int write_file, int use_lock );
  104. static dse_search_set* dse_search_set_new ();
  105. static void dse_search_set_delete (dse_search_set *ss);
  106. static void dse_search_set_clean (dse_search_set *ss);
  107. static void dse_free_entry (void **data);
  108. static void dse_search_set_add_entry (dse_search_set *ss, Slapi_Entry *e);
  109. static Slapi_Entry* dse_search_set_get_next_entry (dse_search_set *ss);
  110. static int dse_add_entry_pb(struct dse* pdse, Slapi_Entry *e, Slapi_PBlock *pb);
  111. static struct dse_node *dse_find_node( struct dse* pdse, const Slapi_DN *dn );
  112. static int dse_modify_plugin(Slapi_Entry *pre_entry, Slapi_Entry *post_entry, char *returntext);
  113. static int dse_add_plugin(Slapi_Entry *entry, char *returntext);
  114. static int dse_delete_plugin(Slapi_Entry *entry, char *returntext);
  115. static int dse_pre_modify_plugin(Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, LDAPMod **mods);
  116. /*
  117. richm: In almost all modes e.g. db2ldif, ldif2db, etc. we do not need/want
  118. to write out the dse.ldif and ldbm.ldif files. The only mode which really
  119. needs to write out the file is the regular server mode. The variable
  120. dont_ever_write_dse_files tells dse_write_file_nolock whether or not to write
  121. the .ldif file for the entry. The default is 1, which means never write the
  122. file. The server, when it starts up in regular mode, must call
  123. dse_unset_dont_ever_write_dse_files() to enable this file to be written
  124. */
  125. static int dont_ever_write_dse_files = 1;
  126. /* Forward declarations */
  127. static int entry_dn_cmp( caddr_t d1, caddr_t d2 );
  128. static int dupentry_disallow( caddr_t d1, caddr_t d2 );
  129. static int dupentry_merge( caddr_t d1, caddr_t d2 );
  130. static int dse_write_entry( caddr_t data, caddr_t arg );
  131. static int ldif_record_end( char *p );
  132. static int dse_call_callback(struct dse* pdse, Slapi_PBlock *pb, int operation, int flags, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char* returntext);
  133. /*
  134. * Map a DN onto a dse_node.
  135. * Returns NULL if not found.
  136. * You must have a read or write lock on the dse_rwlock while
  137. * using the returned node.
  138. */
  139. static struct dse_node *
  140. dse_find_node( struct dse* pdse, const Slapi_DN *dn )
  141. {
  142. struct dse_node *n = NULL;
  143. if ( NULL != dn )
  144. {
  145. struct dse_node searchNode;
  146. Slapi_Entry *fe= slapi_entry_alloc();
  147. slapi_entry_init(fe, NULL, NULL);
  148. slapi_entry_set_sdn(fe,dn);
  149. searchNode.entry= fe;
  150. n = (struct dse_node *)avl_find( pdse->dse_tree, &searchNode, entry_dn_cmp );
  151. slapi_entry_free(fe);
  152. }
  153. return n;
  154. }
  155. static int counters_created= 0;
  156. PR_DEFINE_COUNTER(dse_entries_exist);
  157. /*
  158. * Map a DN onto a real Entry.
  159. * Returns NULL if not found.
  160. */
  161. static Slapi_Entry *
  162. dse_get_entry_copy( struct dse* pdse, const Slapi_DN *dn, int use_lock )
  163. {
  164. Slapi_Entry *e= NULL;
  165. struct dse_node *n;
  166. if (use_lock == DSE_USE_LOCK && pdse->dse_rwlock)
  167. slapi_rwlock_rdlock(pdse->dse_rwlock);
  168. n = dse_find_node( pdse, dn );
  169. if(n!=NULL)
  170. {
  171. e = slapi_entry_dup(n->entry);
  172. }
  173. if (use_lock == DSE_USE_LOCK && pdse->dse_rwlock)
  174. slapi_rwlock_unlock(pdse->dse_rwlock);
  175. return e;
  176. }
  177. static struct dse_callback *
  178. dse_callback_new(int operation,
  179. int flags,
  180. const Slapi_DN *base,
  181. int scope,
  182. const char *filter,
  183. dseCallbackFn fn,
  184. void *fn_arg,
  185. struct slapdplugin *plugin)
  186. {
  187. struct dse_callback *p= NULL;
  188. p = (struct dse_callback *)slapi_ch_calloc(1, sizeof(struct dse_callback));
  189. if (p!=NULL) {
  190. p->operation= operation;
  191. p->flags = flags;
  192. p->base= slapi_sdn_dup(base);
  193. p->scope= scope;
  194. if ( NULL == filter ) {
  195. p->filter= NULL;
  196. p->slapifilter= NULL;
  197. } else {
  198. p->filter= slapi_ch_strdup(filter);
  199. p->slapifilter= slapi_str2filter( p->filter );
  200. filter_normalize(p->slapifilter);
  201. }
  202. p->fn= fn;
  203. p->fn_arg= fn_arg;
  204. p->plugin = plugin;
  205. p->next= NULL;
  206. }
  207. return p;
  208. }
  209. static void
  210. dse_callback_delete(struct dse_callback **pp)
  211. {
  212. if (pp!=NULL) {
  213. slapi_sdn_free(&((*pp)->base));
  214. slapi_ch_free((void**)&((*pp)->filter));
  215. slapi_filter_free((*pp)->slapifilter,1);
  216. slapi_ch_free((void**)pp);
  217. }
  218. }
  219. static void
  220. dse_callback_deletelist(struct dse_callback **pp)
  221. {
  222. if(pp!=NULL)
  223. {
  224. struct dse_callback *p, *n;
  225. for(p= *pp;p!=NULL;)
  226. {
  227. n= p->next;
  228. dse_callback_delete(&p);
  229. p= n;
  230. }
  231. }
  232. }
  233. /*
  234. Makes a copy of the entry passed in, so it's const
  235. */
  236. static struct dse_node *
  237. dse_node_new(const Slapi_Entry *entry)
  238. {
  239. struct dse_node *p= NULL;
  240. p= (struct dse_node *)slapi_ch_malloc(sizeof(struct dse_node));
  241. if(p!=NULL)
  242. {
  243. p->entry= slapi_entry_dup(entry);
  244. }
  245. if(!counters_created)
  246. {
  247. PR_CREATE_COUNTER(dse_entries_exist,"DSE","entries","");
  248. counters_created= 1;
  249. }
  250. PR_INCREMENT_COUNTER(dse_entries_exist);
  251. return p;
  252. }
  253. static void
  254. dse_node_delete(struct dse_node **pp)
  255. {
  256. slapi_entry_free((*pp)->entry);
  257. slapi_ch_free((void **)&(*pp));
  258. PR_DECREMENT_COUNTER(dse_entries_exist);
  259. }
  260. static void
  261. dse_callback_addtolist(struct dse_callback **pplist, struct dse_callback *p)
  262. {
  263. if(pplist!=NULL)
  264. {
  265. p->next= NULL;
  266. if(*pplist==NULL)
  267. {
  268. *pplist= p;
  269. }
  270. else
  271. {
  272. struct dse_callback *t= *pplist;
  273. for(;t->next!=NULL;t= t->next);
  274. t->next= p;
  275. }
  276. }
  277. }
  278. static void
  279. dse_callback_removefromlist(struct dse_callback **pplist, int operation, int flags, const Slapi_DN *base, int scope, const char *filter, dseCallbackFn fn)
  280. {
  281. if (pplist != NULL) {
  282. struct dse_callback *t= *pplist;
  283. struct dse_callback *prev= NULL;
  284. for(; t!=NULL; ) {
  285. if ((t->operation & operation) && (t->flags & flags) &&
  286. (t->fn == fn) && (scope == t->scope) &&
  287. (slapi_sdn_compare(base,t->base) == 0) &&
  288. ((NULL == filter && NULL == t->filter) || /* both are NULL OR */
  289. ((filter && t->filter) && /* both are not NULL AND match. */
  290. (strcasecmp(filter, t->filter) == 0)))) {
  291. if (prev == NULL) {
  292. *pplist= t->next;
  293. } else {
  294. prev->next= t->next;
  295. }
  296. dse_callback_delete(&t);
  297. t= NULL;
  298. } else {
  299. prev= t;
  300. t= t->next;
  301. }
  302. }
  303. }
  304. }
  305. /*
  306. * Create a new dse structure.
  307. */
  308. struct dse *
  309. dse_new( char *filename, char *tmpfilename, char *backfilename, char *startokfilename, const char *configdir)
  310. {
  311. struct dse *pdse= NULL;
  312. char *realconfigdir = NULL;
  313. if (configdir!=NULL)
  314. {
  315. realconfigdir = slapi_ch_strdup(configdir);
  316. }
  317. else
  318. {
  319. realconfigdir = config_get_configdir();
  320. }
  321. if(realconfigdir!=NULL)
  322. {
  323. pdse= (struct dse *)slapi_ch_calloc(1, sizeof(struct dse));
  324. if(pdse!=NULL)
  325. {
  326. pdse->dse_rwlock = slapi_new_rwlock();
  327. /* Set the full path name for the config DSE entry */
  328. if (!strstr(filename, realconfigdir))
  329. {
  330. pdse->dse_filename = slapi_ch_smprintf("%s/%s", realconfigdir, filename );
  331. }
  332. else
  333. pdse->dse_filename = slapi_ch_strdup(filename);
  334. if (!strstr(tmpfilename, realconfigdir)) {
  335. pdse->dse_tmpfile = slapi_ch_smprintf("%s/%s", realconfigdir, tmpfilename );
  336. }
  337. else
  338. pdse->dse_tmpfile = slapi_ch_strdup(tmpfilename);
  339. if ( backfilename != NULL )
  340. {
  341. if (!strstr(backfilename, realconfigdir)) {
  342. pdse->dse_fileback = slapi_ch_smprintf("%s/%s", realconfigdir, backfilename );
  343. }
  344. else
  345. pdse->dse_fileback = slapi_ch_strdup(backfilename);
  346. }
  347. else
  348. pdse->dse_fileback = NULL;
  349. if ( startokfilename != NULL )
  350. {
  351. if (!strstr(startokfilename, realconfigdir)) {
  352. pdse->dse_filestartOK = slapi_ch_smprintf("%s/%s", realconfigdir, startokfilename );
  353. }
  354. else
  355. pdse->dse_filestartOK = slapi_ch_strdup(startokfilename);
  356. }
  357. else
  358. pdse->dse_filestartOK = NULL;
  359. pdse->dse_tree= NULL;
  360. pdse->dse_callback= NULL;
  361. pdse->dse_is_updateable = dse_permission_to_write(pdse,
  362. SLAPI_LOG_TRACE);
  363. }
  364. slapi_ch_free( (void **) &realconfigdir );
  365. }
  366. return pdse;
  367. }
  368. /*
  369. * Create a new dse structure with a file list
  370. */
  371. struct dse *
  372. dse_new_with_filelist(char *filename, char *tmpfilename, char *backfilename, char *startokfilename, const char *configdir,
  373. char **filelist)
  374. {
  375. struct dse *newdse = dse_new(filename, tmpfilename, backfilename, startokfilename, configdir);
  376. newdse->dse_filelist = filelist;
  377. return newdse;
  378. }
  379. static int
  380. dse_internal_delete_entry( caddr_t data, caddr_t arg )
  381. {
  382. struct dse_node *n = (struct dse_node *)data;
  383. dse_node_delete(&n);
  384. return 0;
  385. }
  386. /*
  387. * Get rid of a dse structure.
  388. */
  389. int
  390. dse_destroy(struct dse *pdse)
  391. {
  392. int nentries = 0;
  393. if (NULL == pdse) {
  394. return 0; /* no one checks this return value */
  395. }
  396. if (pdse->dse_rwlock)
  397. slapi_rwlock_wrlock(pdse->dse_rwlock);
  398. slapi_ch_free((void **)&(pdse->dse_filename));
  399. slapi_ch_free((void **)&(pdse->dse_tmpfile));
  400. slapi_ch_free((void **)&(pdse->dse_fileback));
  401. slapi_ch_free((void **)&(pdse->dse_filestartOK));
  402. dse_callback_deletelist(&pdse->dse_callback);
  403. charray_free(pdse->dse_filelist);
  404. nentries = avl_free(pdse->dse_tree, dse_internal_delete_entry);
  405. if (pdse->dse_rwlock) {
  406. slapi_rwlock_unlock(pdse->dse_rwlock);
  407. slapi_destroy_rwlock(pdse->dse_rwlock);
  408. }
  409. slapi_ch_free((void **)&pdse);
  410. LDAPDebug( SLAPI_DSE_TRACELEVEL, "Removed [%d] entries from the dse tree.\n",
  411. nentries,0,0 );
  412. return 0; /* no one checks this return value */
  413. }
  414. /*
  415. * Get rid of a dse structure.
  416. */
  417. int
  418. dse_deletedse(Slapi_PBlock *pb)
  419. {
  420. struct dse *pdse = NULL;
  421. slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &pdse);
  422. if (pdse)
  423. {
  424. dse_destroy(pdse);
  425. }
  426. /* data is freed, so make sure no one tries to use it */
  427. slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, NULL);
  428. return 0;
  429. }
  430. static char* subordinatecount = "numsubordinates";
  431. /*
  432. * Get the number of subordinates for this entry.
  433. */
  434. static size_t
  435. dse_numsubordinates(Slapi_Entry *entry)
  436. {
  437. int ret= 0;
  438. Slapi_Attr *read_attr = NULL;
  439. size_t current_sub_count = 0;
  440. /* Get the present value of the subcount attr, or 0 if not present */
  441. ret = slapi_entry_attr_find(entry,subordinatecount,&read_attr);
  442. if (0 == ret)
  443. {
  444. /* decode the value */
  445. Slapi_Value *sval;
  446. slapi_attr_first_value( read_attr,&sval );
  447. if (sval!=NULL)
  448. {
  449. const struct berval *bval = slapi_value_get_berval( sval );
  450. if( NULL != bval )
  451. current_sub_count = atol(bval->bv_val);
  452. }
  453. }
  454. return current_sub_count;
  455. }
  456. /*
  457. * Update the numsubordinates count.
  458. * mod_op is either an Add or Delete.
  459. */
  460. static void
  461. dse_updateNumSubordinates(Slapi_Entry *entry, int op)
  462. {
  463. int ret= 0;
  464. int mod_op = 0;
  465. Slapi_Attr *read_attr = NULL;
  466. size_t current_sub_count = 0;
  467. int already_present = 0;
  468. /* For now, we're only interested in subordinatecount.
  469. We first examine the present value for the attribute.
  470. If it isn't present and we're adding, we assign value 1 to the attribute and add it.
  471. If it is present, we increment or decrement depending upon whether we're adding or deleting.
  472. If the value after decrementing is zero, we remove it.
  473. */
  474. /* Get the present value of the subcount attr, or 0 if not present */
  475. ret = slapi_entry_attr_find(entry,subordinatecount,&read_attr);
  476. if (0 == ret)
  477. {
  478. /* decode the value */
  479. Slapi_Value *sval;
  480. slapi_attr_first_value( read_attr,&sval );
  481. if (sval!=NULL)
  482. {
  483. const struct berval *bval = slapi_value_get_berval( sval );
  484. if (bval!=NULL)
  485. {
  486. already_present = 1;
  487. current_sub_count = atol(bval->bv_val);
  488. }
  489. }
  490. }
  491. /* are we adding ? */
  492. if ( (SLAPI_OPERATION_ADD == op) && !already_present)
  493. {
  494. /* If so, and the parent entry does not already have a subcount attribute, we need to add it */
  495. mod_op = LDAP_MOD_ADD;
  496. }
  497. else
  498. {
  499. if (SLAPI_OPERATION_DELETE == op)
  500. {
  501. if (!already_present)
  502. {
  503. /* This means that something is wrong---deleting a child but no subcount present on parent */
  504. slapi_log_error( SLAPI_LOG_FATAL, "dse",
  505. "numsubordinates assertion failure\n" );
  506. return;
  507. }
  508. else
  509. {
  510. if (current_sub_count == 1)
  511. {
  512. mod_op = LDAP_MOD_DELETE;
  513. }
  514. else
  515. {
  516. mod_op = LDAP_MOD_REPLACE;
  517. }
  518. }
  519. }
  520. else
  521. {
  522. mod_op = LDAP_MOD_REPLACE;
  523. }
  524. }
  525. /* Now compute the new value */
  526. if (SLAPI_OPERATION_ADD == op)
  527. {
  528. current_sub_count++;
  529. }
  530. else
  531. {
  532. current_sub_count--;
  533. }
  534. {
  535. char value_buffer[20]; /* enough digits for 2^64 children */
  536. struct berval *vals[2];
  537. struct berval val;
  538. vals[0] = &val;
  539. vals[1] = NULL;
  540. sprintf(value_buffer,"%lu",(long unsigned int)current_sub_count);
  541. val.bv_val = value_buffer;
  542. val.bv_len = strlen (val.bv_val);
  543. switch(mod_op)
  544. {
  545. case LDAP_MOD_ADD:
  546. attrlist_merge( &entry->e_attrs, subordinatecount, vals);
  547. break;
  548. case LDAP_MOD_REPLACE:
  549. attrlist_replace( &entry->e_attrs, subordinatecount, vals);
  550. break;
  551. case LDAP_MOD_DELETE:
  552. attrlist_delete( &entry->e_attrs, subordinatecount);
  553. break;
  554. }
  555. }
  556. }
  557. /* the write lock should always be acquired before calling this function */
  558. static void
  559. dse_updateNumSubOfParent(struct dse *pdse, const Slapi_DN *child, int op)
  560. {
  561. Slapi_DN parent;
  562. slapi_sdn_init(&parent);
  563. slapi_sdn_get_parent(child, &parent);
  564. if ( !slapi_sdn_isempty(&parent) )
  565. {
  566. /* no lock because caller should already have the write lock */
  567. Slapi_Entry *parententry= dse_get_entry_copy( pdse, &parent, DSE_NO_LOCK );
  568. if( parententry!=NULL )
  569. {
  570. /* Decrement the numsubordinate count of the parent entry */
  571. dse_updateNumSubordinates(parententry, op);
  572. /* no lock because caller should always have the write lock */
  573. dse_replace_entry( pdse, parententry, 0, DSE_NO_LOCK );
  574. slapi_entry_free(parententry);
  575. }
  576. }
  577. slapi_sdn_done(&parent);
  578. }
  579. /* check if a file is valid, or if a provided backup file can be used.
  580. * there is no way to determine if the file contents is usable, the only
  581. * checks that can be done is that the file exists and that it is not size 0
  582. */
  583. int
  584. dse_check_file(char *filename, char *backupname)
  585. {
  586. int rc= 0; /* Fail */
  587. PRFileInfo64 prfinfo;
  588. if (PR_GetFileInfo64( filename, &prfinfo ) == PR_SUCCESS) {
  589. if ( prfinfo.size > 0)
  590. return (1);
  591. else {
  592. rc = PR_Delete (filename);
  593. }
  594. }
  595. if (backupname)
  596. rc = PR_Rename (backupname, filename);
  597. else
  598. return (0);
  599. if ( PR_GetFileInfo64( filename, &prfinfo ) == PR_SUCCESS && prfinfo.size > 0 ) {
  600. slapi_log_error(SLAPI_LOG_FATAL, "dse",
  601. "The configuration file %s was restored from backup %s\n", filename, backupname);
  602. return (1);
  603. } else {
  604. slapi_log_error(SLAPI_LOG_FATAL, "dse",
  605. "The configuration file %s was not restored from backup %s, error %d\n",
  606. filename, backupname, rc);
  607. return (0);
  608. }
  609. }
  610. static int
  611. dse_read_one_file(struct dse *pdse, const char *filename, Slapi_PBlock *pb,
  612. int primary_file )
  613. {
  614. Slapi_Entry *e= NULL;
  615. char *entrystr= NULL;
  616. char *buf = NULL;
  617. char *lastp = NULL;
  618. int rc= 0; /* Fail */
  619. PRInt32 nr = 0;
  620. PRFileInfo64 prfinfo;
  621. PRFileDesc *prfd = 0;
  622. int schema_flags = 0;
  623. slapi_pblock_get(pb, SLAPI_SCHEMA_FLAGS, &schema_flags);
  624. if ( (NULL != pdse) && (NULL != filename) )
  625. {
  626. /* check if the "real" file exists and cam be used, if not try tmp as backup */
  627. rc = dse_check_file((char *)filename, pdse->dse_tmpfile);
  628. if (!rc)
  629. rc = dse_check_file((char *)filename, pdse->dse_fileback);
  630. if ( (rc = PR_GetFileInfo64( filename, &prfinfo )) != PR_SUCCESS )
  631. {
  632. slapi_log_error(SLAPI_LOG_FATAL, "dse",
  633. "The configuration file %s could not be accessed, error %d\n",
  634. filename, rc);
  635. rc = 0; /* Fail */
  636. }
  637. else if (( prfd = PR_Open( filename, PR_RDONLY, SLAPD_DEFAULT_FILE_MODE )) == NULL )
  638. {
  639. slapi_log_error(SLAPI_LOG_FATAL, "dse",
  640. "The configuration file %s could not be read. "
  641. SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
  642. filename,
  643. PR_GetError(), slapd_pr_strerror(PR_GetError()));
  644. rc = 0; /* Fail */
  645. }
  646. else
  647. {
  648. int done= 0;
  649. /* read the entire file into core */
  650. buf = slapi_ch_malloc( prfinfo.size + 1 );
  651. if (( nr = slapi_read_buffer( prfd, buf, prfinfo.size )) < 0 )
  652. {
  653. slapi_log_error(SLAPI_LOG_FATAL, "dse",
  654. "Could only read %d of %ld bytes from config file %s\n",
  655. nr, (long int)prfinfo.size, filename);
  656. rc = 0; /* Fail */
  657. done= 1;
  658. }
  659. (void)PR_Close( prfd );
  660. buf[ nr ] = '\0';
  661. if(!done)
  662. {
  663. int lineno = 1;
  664. int lines = 0;
  665. int dont_check_dups = 0;
  666. int str2entry_flags = SLAPI_STR2ENTRY_EXPAND_OBJECTCLASSES |
  667. SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF ;
  668. if (schema_flags & DSE_SCHEMA_LOCKED)
  669. str2entry_flags |= SLAPI_STR2ENTRY_NO_SCHEMA_LOCK;
  670. PR_ASSERT(pb);
  671. slapi_pblock_get(pb, SLAPI_DSE_DONT_CHECK_DUPS, &dont_check_dups);
  672. if ( !dont_check_dups ) {
  673. str2entry_flags |= SLAPI_STR2ENTRY_REMOVEDUPVALS;
  674. }
  675. /* Convert LDIF to entry structures */
  676. rc= 1; /* assume we will succeed */
  677. while (( entrystr = dse_read_next_entry( buf, &lastp )) != NULL )
  678. {
  679. char *p, *q;
  680. char errbuf[256];
  681. size_t estrlen = strlen(entrystr);
  682. size_t cpylen =
  683. (estrlen<sizeof(errbuf))?estrlen:sizeof(errbuf)-1;
  684. memcpy(errbuf, entrystr, cpylen);
  685. errbuf[cpylen] = '\0';
  686. lines = 1;
  687. p = entrystr;
  688. while ((q = strchr(p, '\n'))) {
  689. p = q + 1;
  690. lines++;
  691. }
  692. e = slapi_str2entry( entrystr, str2entry_flags );
  693. if ( e != NULL )
  694. {
  695. int returncode = 0;
  696. char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= {0};
  697. slapi_log_error(SLAPI_LOG_TRACE, "dse_read_one_file",
  698. " processing entry \"%s\" in file %s%s "
  699. "(lineno: %d)\n",
  700. slapi_entry_get_dn_const(e), filename,
  701. primary_file ? " (primary file)" : "",
  702. lineno);
  703. /* remove the numsubordinates attr, which may be bogus */
  704. slapi_entry_attr_delete(e, subordinatecount);
  705. /* set the "primary file" flag if appropriate */
  706. slapi_pblock_set( pb, SLAPI_DSE_IS_PRIMARY_FILE, &primary_file );
  707. if(dse_call_callback(pdse, pb, DSE_OPERATION_READ,
  708. DSE_FLAG_PREOP, e, NULL, &returncode,
  709. returntext) == SLAPI_DSE_CALLBACK_OK)
  710. {
  711. /*
  712. * This will free the entry if not added, so it is
  713. * definitely consumed by this call
  714. */
  715. if(dse_add_entry_pb(pdse, e, pb) == SCHEMA_VIOLATION){
  716. /* schema violation, return failure */
  717. rc = 0;
  718. }
  719. }
  720. else /* free entry if not used */
  721. {
  722. slapi_log_error(SLAPI_LOG_FATAL,
  723. "dse_read_one_file",
  724. "The entry %s in file %s "
  725. "(lineno: %d) is invalid, "
  726. "error code %d (%s) - %s\n",
  727. slapi_entry_get_dn_const(e),
  728. filename, lineno, returncode,
  729. ldap_err2string(returncode),
  730. returntext);
  731. slapi_entry_free(e);
  732. rc = 0; /* failure */
  733. }
  734. } else {
  735. slapi_log_error( SLAPI_LOG_FATAL, "dse_read_one_file",
  736. "Parsing entry (lineno: %d) "
  737. "in file %s failed.\n",
  738. lineno, filename );
  739. slapi_log_error( SLAPI_LOG_FATAL, "dse_read_one_file",
  740. "Invalid section [%s%s]\n",
  741. errbuf, cpylen==estrlen?"":" ..." );
  742. rc = 0; /* failure */
  743. }
  744. lineno += lines + 1 /* 1 is for a blank line. */;
  745. }
  746. }
  747. slapi_ch_free((void **)&buf);
  748. }
  749. }
  750. return rc;
  751. }
  752. /*
  753. * Read the file we were initialised with into memory.
  754. * If not NULL call entry_filter_fn on each entry as it's read.
  755. * The function is free to modify the entry before it's places
  756. * into the AVL tree. True means add the entry. False means don't.
  757. *
  758. * Return 1 for OK, 0 for Fail.
  759. */
  760. int
  761. dse_read_file(struct dse *pdse, Slapi_PBlock *pb)
  762. {
  763. int rc= 1; /* Good */
  764. int ii;
  765. char **filelist = 0;
  766. char *filename = 0;
  767. filelist = charray_dup(pdse->dse_filelist);
  768. filename = slapi_ch_strdup(pdse->dse_filename);
  769. for (ii = 0; rc && filelist && filelist[ii]; ++ii)
  770. {
  771. if (strcasecmp(filename, filelist[ii])!=0)
  772. {
  773. rc = dse_read_one_file(pdse, filelist[ii], pb, 0 /* not primary */);
  774. }
  775. }
  776. if (rc)
  777. {
  778. rc = dse_read_one_file(pdse, filename, pb, 1 /* primary file */);
  779. }
  780. charray_free(filelist);
  781. slapi_ch_free((void **)&filename);
  782. return rc;
  783. }
  784. /*
  785. * Structure to carry context information whilst
  786. * traversing the tree writing the entries to disk.
  787. */
  788. typedef struct _fpw
  789. {
  790. PRFileDesc *fpw_prfd;
  791. int fpw_rc;
  792. struct dse *fpw_pdse;
  793. } FPWrapper;
  794. static int
  795. dse_rw_permission_to_one_file(const char *name, int loglevel)
  796. {
  797. PRErrorCode prerr = 0;
  798. const char *accesstype = "";
  799. if ( NULL == name ) {
  800. return 1; /* file won't be used -- return "sufficient permission" */
  801. }
  802. if ( PR_Access( name, PR_ACCESS_EXISTS ) == PR_SUCCESS ) {
  803. /* file exists: check for read and write permission */
  804. if ( PR_Access( name, PR_ACCESS_WRITE_OK ) != PR_SUCCESS ) {
  805. prerr = PR_GetError();
  806. accesstype = "write";
  807. } else if ( PR_Access( name, PR_ACCESS_READ_OK ) != PR_SUCCESS ) {
  808. prerr = PR_GetError();
  809. accesstype = "read";
  810. }
  811. } else {
  812. /* file does not exist: make sure we can create it */
  813. PRFileDesc *prfd;
  814. prfd = PR_Open( name, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE,
  815. SLAPD_DEFAULT_FILE_MODE );
  816. if ( NULL == prfd ) {
  817. prerr = PR_GetError();
  818. accesstype = "create";
  819. } else {
  820. PR_Close( prfd );
  821. PR_Delete( name );
  822. }
  823. }
  824. if ( prerr != 0 ) {
  825. slapi_log_error( loglevel, "dse", "Unable to %s \"%s\": "
  826. SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  827. accesstype, name, prerr, slapd_pr_strerror(prerr));
  828. return 0; /* insufficient permission */
  829. } else {
  830. return 1; /* sufficient permission */
  831. }
  832. }
  833. /*
  834. * Check that we have permission to write to all the files that
  835. * dse_write_file_nolock() uses.
  836. * Returns a non-zero value if sufficient permission and 0 if not.
  837. */
  838. static int
  839. dse_permission_to_write(struct dse* pdse, int loglevel)
  840. {
  841. int rc = 1; /* sufficient permission */
  842. if ( NULL != pdse->dse_filename ) {
  843. if ( !dse_rw_permission_to_one_file( pdse->dse_filename, loglevel ) ||
  844. !dse_rw_permission_to_one_file( pdse->dse_fileback, loglevel ) ||
  845. !dse_rw_permission_to_one_file( pdse->dse_tmpfile, loglevel )) {
  846. rc = 0; /* insufficient permission */
  847. }
  848. }
  849. return rc;
  850. }
  851. /*
  852. * Check for read-only status and return an appropriate error to the
  853. * LDAP client.
  854. * Returns 0 if no error was returned and non-zero if one was.
  855. */
  856. static int
  857. dse_check_for_readonly_error(Slapi_PBlock *pb, struct dse* pdse)
  858. {
  859. int rc = 0; /* default: no error */
  860. if (pdse->dse_rwlock)
  861. slapi_rwlock_rdlock(pdse->dse_rwlock);
  862. if ( !pdse->dse_is_updateable ) {
  863. if ( !pdse->dse_readonly_error_reported ) {
  864. if ( NULL != pdse->dse_filename ) {
  865. slapi_log_error( SLAPI_LOG_FATAL, "dse",
  866. "The DSE database stored in \"%s\" is not writeable\n",
  867. pdse->dse_filename );
  868. /* log the details too */
  869. (void)dse_permission_to_write(pdse, SLAPI_LOG_FATAL);
  870. }
  871. pdse->dse_readonly_error_reported = 1;
  872. }
  873. rc = 1; /* return an error to the client */
  874. }
  875. if (pdse->dse_rwlock)
  876. slapi_rwlock_unlock(pdse->dse_rwlock);
  877. if ( rc != 0 ) {
  878. slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
  879. "DSE database is read-only", 0, NULL );
  880. }
  881. return rc; /* no error */
  882. }
  883. /*
  884. * Write the AVL tree of entries back to the LDIF file.
  885. */
  886. static int
  887. dse_write_file_nolock(struct dse* pdse)
  888. {
  889. FPWrapper fpw;
  890. int rc = 0;
  891. if (dont_ever_write_dse_files)
  892. return rc;
  893. fpw.fpw_rc = 0;
  894. fpw.fpw_prfd = NULL;
  895. if ( NULL != pdse->dse_filename )
  896. {
  897. if (( fpw.fpw_prfd = PR_Open( pdse->dse_tmpfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, SLAPD_DEFAULT_FILE_MODE )) == NULL )
  898. {
  899. rc = PR_GetOSError();
  900. slapi_log_error( SLAPI_LOG_FATAL, "dse", "Cannot open "
  901. "temporary DSE file \"%s\" for update: OS error %d (%s)\n",
  902. pdse->dse_tmpfile, rc, slapd_system_strerror( rc ));
  903. }
  904. else
  905. {
  906. fpw.fpw_pdse = pdse;
  907. if ( avl_apply( pdse->dse_tree, dse_write_entry, &fpw, STOP_TRAVERSAL, AVL_INORDER ) == STOP_TRAVERSAL )
  908. {
  909. rc = fpw.fpw_rc;
  910. slapi_log_error( SLAPI_LOG_FATAL, "dse", "Cannot write "
  911. " temporary DSE file \"%s\": OS error %d (%s)\n",
  912. pdse->dse_tmpfile, rc, slapd_system_strerror( rc ));
  913. (void)PR_Close( fpw.fpw_prfd );
  914. fpw.fpw_prfd = NULL;
  915. }
  916. else
  917. {
  918. (void)PR_Close( fpw.fpw_prfd );
  919. fpw.fpw_prfd = NULL;
  920. if ( pdse->dse_fileback != NULL )
  921. {
  922. rc = slapi_destructive_rename( pdse->dse_filename, pdse->dse_fileback );
  923. if ( rc != 0 )
  924. {
  925. slapi_log_error( SLAPI_LOG_FATAL, "dse", "Cannot backup"
  926. " DSE file \"%s\" to \"%s\": OS error %d (%s)\n",
  927. pdse->dse_filename, pdse->dse_fileback,
  928. rc, slapd_system_strerror( rc ));
  929. }
  930. }
  931. rc = slapi_destructive_rename( pdse->dse_tmpfile, pdse->dse_filename );
  932. if ( rc != 0 )
  933. {
  934. slapi_log_error( SLAPI_LOG_FATAL, "dse", "Cannot rename"
  935. " temporary DSE file \"%s\" to \"%s\":"
  936. " OS error %d (%s)\n",
  937. pdse->dse_tmpfile, pdse->dse_filename,
  938. rc, slapd_system_strerror( rc ));
  939. }
  940. }
  941. }
  942. if (fpw.fpw_prfd)
  943. (void)PR_Close(fpw.fpw_prfd);
  944. }
  945. return rc;
  946. }
  947. /*
  948. * Local function for writing an entry to a file.
  949. * Called by the AVL code during traversal.
  950. */
  951. static int
  952. dse_write_entry( caddr_t data, caddr_t arg )
  953. {
  954. struct dse_node *n = (struct dse_node *)data;
  955. FPWrapper *fpw = (FPWrapper *)arg;
  956. char *s;
  957. PRInt32 len;
  958. if ( NULL != n && NULL != n->entry )
  959. {
  960. int returncode;
  961. char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= "";
  962. /* need to make a duplicate here for two reasons:
  963. 1) we don't want to hold on to the raw data in the node for any longer
  964. than we have to; we will usually be inside the dse write lock, but . . .
  965. 2) the write callback may modify the entry, so we want to pass it a
  966. writeable copy rather than the raw avl tree data pointer
  967. */
  968. Slapi_Entry *ec = slapi_entry_dup(n->entry);
  969. if(dse_call_callback(fpw->fpw_pdse, NULL, DSE_OPERATION_WRITE,
  970. DSE_FLAG_PREOP, ec, NULL, &returncode, returntext)
  971. == SLAPI_DSE_CALLBACK_OK)
  972. {
  973. /*
  974. * 3-August-2000 mcs: We used to pass the SLAPI_DUMP_NOOPATTRS
  975. * option to slapi_entry2str_with_options() so that operational
  976. * attributes were NOT stored in the DSE LDIF files. But now
  977. * we store all attribute types.
  978. */
  979. if (( s = slapi_entry2str_with_options( ec, &len, 0 )) != NULL )
  980. {
  981. if ( slapi_write_buffer( fpw->fpw_prfd, s, len ) != len )
  982. {
  983. fpw->fpw_rc = PR_GetOSError();;
  984. slapi_ch_free((void **) &s);
  985. return STOP_TRAVERSAL;
  986. }
  987. if ( slapi_write_buffer( fpw->fpw_prfd, "\n", 1 ) != 1 )
  988. {
  989. fpw->fpw_rc = PR_GetOSError();;
  990. slapi_ch_free((void **) &s);
  991. return STOP_TRAVERSAL;
  992. }
  993. slapi_ch_free((void **) &s);
  994. }
  995. }
  996. slapi_entry_free(ec);
  997. }
  998. return 0;
  999. }
  1000. /*
  1001. * Adds an entry to the dse backend. The passed in entry will be
  1002. * free'd always.
  1003. *
  1004. * return -1 for duplicate entry
  1005. * return -2 for schema violation (SCHEMA_VIOLATION)
  1006. */
  1007. static int
  1008. dse_add_entry_pb(struct dse* pdse, Slapi_Entry *e, Slapi_PBlock *pb)
  1009. {
  1010. int dont_write_file = 0, merge = 0; /* defaults */
  1011. int rc= 0;
  1012. struct dse_node *n = dse_node_new(e); /* copies e */
  1013. Slapi_Entry *schemacheckentry= NULL; /* to use for schema checking */
  1014. PR_ASSERT(pb);
  1015. slapi_pblock_get(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
  1016. slapi_pblock_get(pb, SLAPI_DSE_MERGE_WHEN_ADDING, &merge);
  1017. /* keep write lock during both tree update and file write operations */
  1018. if (pdse->dse_rwlock)
  1019. slapi_rwlock_wrlock(pdse->dse_rwlock);
  1020. if (merge)
  1021. {
  1022. rc= avl_insert( &(pdse->dse_tree), n, entry_dn_cmp, dupentry_merge );
  1023. }
  1024. else
  1025. {
  1026. rc= avl_insert( &(pdse->dse_tree), n, entry_dn_cmp, dupentry_disallow );
  1027. }
  1028. if (-1 != rc) {
  1029. /* update num sub of parent with no lock; we already hold the write lock */
  1030. if (0 == rc) { /* entry was added, not merged; update numsub */
  1031. dse_updateNumSubOfParent(pdse, slapi_entry_get_sdn_const(e),
  1032. SLAPI_OPERATION_ADD);
  1033. } else { /* entry was merged, free temp unused data */
  1034. dse_node_delete(&n);
  1035. }
  1036. if (!dont_write_file) {
  1037. dse_write_file_nolock(pdse);
  1038. }
  1039. } else { /* duplicate entry ignored */
  1040. dse_node_delete(&n); /* This also deletes the contained entry */
  1041. }
  1042. if (pdse->dse_rwlock)
  1043. slapi_rwlock_unlock(pdse->dse_rwlock);
  1044. if (rc == -1)
  1045. {
  1046. /* duplicate entry ignored */
  1047. schemacheckentry = dse_get_entry_copy( pdse,
  1048. slapi_entry_get_sdn_const(e),
  1049. DSE_USE_LOCK );
  1050. }
  1051. else /* entry added or merged */
  1052. {
  1053. /* entry was added or merged */
  1054. if (0 == rc) /* 0 return means entry was added, not merged */
  1055. {
  1056. /* save a search of the tree, since we added the entry, the
  1057. contents of e should be the same as what is in the tree */
  1058. schemacheckentry = slapi_entry_dup(e);
  1059. }
  1060. else /* merged */
  1061. {
  1062. /* schema check the new merged entry, so get it from the tree */
  1063. schemacheckentry = dse_get_entry_copy( pdse,
  1064. slapi_entry_get_sdn_const(e),
  1065. DSE_USE_LOCK );
  1066. }
  1067. }
  1068. if ( NULL != schemacheckentry )
  1069. {
  1070. /*
  1071. * Verify that the new or merged entry conforms to the schema.
  1072. * Errors are logged by slapi_entry_schema_check().
  1073. */
  1074. if(slapi_entry_schema_check( pb, schemacheckentry )){
  1075. rc = SCHEMA_VIOLATION;
  1076. }
  1077. slapi_entry_free(schemacheckentry);
  1078. }
  1079. /* Callers expect e (SLAPI_ADD_ENTRY) to be freed */
  1080. /* This function duplicates 'e' for dse_node 'n' and schemacheckentry.
  1081. * 'e' should not have been consumed */
  1082. slapi_entry_free(e);
  1083. return rc;
  1084. }
  1085. /*
  1086. * Local function for comparing two entries by DN. Store the entries
  1087. * so that when they are printed out, the child entries are below their
  1088. * ancestor entries
  1089. */
  1090. static int
  1091. entry_dn_cmp( caddr_t d1, caddr_t d2 )
  1092. {
  1093. struct dse_node *n1 = (struct dse_node *)d1;
  1094. struct dse_node *n2 = (struct dse_node *)d2;
  1095. const Slapi_DN *dn1 = slapi_entry_get_sdn_const(n1->entry);
  1096. const Slapi_DN *dn2 = slapi_entry_get_sdn_const(n2->entry);
  1097. int retval = slapi_sdn_compare(dn1, dn2);
  1098. if (retval != 0)
  1099. {
  1100. if (slapi_sdn_issuffix(dn1, dn2))
  1101. {
  1102. retval = 1;
  1103. }
  1104. else if (slapi_sdn_issuffix(dn2, dn1))
  1105. {
  1106. retval = -1;
  1107. }
  1108. else
  1109. {
  1110. /* put fewer rdns before more rdns */
  1111. int rc = 0;
  1112. char **dnlist1 = slapi_ldap_explode_dn(slapi_sdn_get_ndn(dn1), 0);
  1113. char **dnlist2 = slapi_ldap_explode_dn(slapi_sdn_get_ndn(dn2), 0);
  1114. int len1 = 0;
  1115. int len2 = 0;
  1116. if (dnlist1)
  1117. for (len1 = 0; dnlist1[len1]; ++len1);
  1118. if (dnlist2)
  1119. for (len2 = 0; dnlist2[len2]; ++len2);
  1120. if (len1 == len2)
  1121. {
  1122. len1--;
  1123. for (; (rc == 0) && (len1 >= 0); --len1)
  1124. {
  1125. rc = strcmp(dnlist1[len1], dnlist2[len1]);
  1126. }
  1127. if (rc)
  1128. retval = rc;
  1129. }
  1130. else
  1131. retval = len1 - len2;
  1132. if (dnlist1)
  1133. slapi_ldap_value_free(dnlist1);
  1134. if (dnlist2)
  1135. slapi_ldap_value_free(dnlist2);
  1136. }
  1137. }
  1138. /* else entries are equal if dns are equal */
  1139. return retval;
  1140. }
  1141. static int
  1142. dupentry_disallow( caddr_t d1, caddr_t d2 )
  1143. {
  1144. return -1;
  1145. }
  1146. static int
  1147. dupentry_replace( caddr_t d1, caddr_t d2 )
  1148. {
  1149. /*
  1150. * Hack attack: since we don't have the address of the pointer
  1151. * in the avl node, we have to replace the e_dn and e_attrs
  1152. * members of the entry which is in the AVL tree with our
  1153. * new entry DN and attrs. We then point the "new" entry's
  1154. * e_dn and e_attrs pointers to point to the values we just
  1155. * replaced, on the assumption that the caller will be freeing
  1156. * these.
  1157. */
  1158. struct dse_node *n1 = (struct dse_node *)d1; /* OLD */
  1159. struct dse_node *n2 = (struct dse_node *)d2; /* NEW */
  1160. Slapi_Entry *e= n1->entry;
  1161. n1->entry= n2->entry;
  1162. n2->entry= e;
  1163. return DSE_ENTRY_WAS_REPLACED;
  1164. }
  1165. static int
  1166. dupentry_merge( caddr_t d1, caddr_t d2 )
  1167. {
  1168. struct dse_node *n1 = (struct dse_node *)d1; /* OLD */
  1169. struct dse_node *n2 = (struct dse_node *)d2; /* NEW */
  1170. Slapi_Entry *e1= n1->entry;
  1171. Slapi_Entry *e2= n2->entry;
  1172. int rc = 0;
  1173. Slapi_Attr *newattr = 0;
  1174. for (rc = slapi_entry_first_attr(e2, &newattr);
  1175. !rc && newattr;
  1176. rc = slapi_entry_next_attr(e2, newattr, &newattr)) {
  1177. char *type = 0;
  1178. slapi_attr_get_type(newattr, &type);
  1179. if (type) {
  1180. /* insure there are no duplicate values in e1 */
  1181. rc = slapi_entry_merge_values_sv(e1, type,
  1182. attr_get_present_values(newattr));
  1183. }
  1184. }
  1185. return DSE_ENTRY_WAS_MERGED;
  1186. }
  1187. /*
  1188. * Add an entry to the DSE without locking the DSE avl tree.
  1189. * Replaces the entry if it already exists.
  1190. *
  1191. * The given entry e is never consumed. It is the responsibility of the
  1192. * caller to free it when it is no longer needed.
  1193. *
  1194. * The write_file flag is used if we want to update the entry in memory
  1195. * but we do not want to write out the file. For example, if we update
  1196. * the numsubordinates in the entry, this is an operational attribute that
  1197. * we do not want saved to disk.
  1198. */
  1199. static int
  1200. dse_replace_entry( struct dse* pdse, Slapi_Entry *e, int write_file, int use_lock )
  1201. {
  1202. int rc= -1;
  1203. if ( NULL != e )
  1204. {
  1205. struct dse_node *n= dse_node_new(e);
  1206. if (use_lock && pdse->dse_rwlock)
  1207. slapi_rwlock_wrlock(pdse->dse_rwlock);
  1208. rc = avl_insert( &(pdse->dse_tree), n, entry_dn_cmp, dupentry_replace );
  1209. if (write_file)
  1210. dse_write_file_nolock(pdse);
  1211. /* If the entry was replaced i.e. not added as a new entry, we need to
  1212. free the old data, which is set in dupentry_replace */
  1213. if (DSE_ENTRY_WAS_REPLACED == rc) {
  1214. dse_node_delete(&n);
  1215. rc = 0; /* for return to caller */
  1216. }
  1217. if (use_lock && pdse->dse_rwlock)
  1218. slapi_rwlock_unlock(pdse->dse_rwlock);
  1219. }
  1220. return rc;
  1221. }
  1222. /*
  1223. * Return -1 if p does not point to a valid LDIF
  1224. * end-of-record delimiter (a NULL, two newlines, or two
  1225. * pairs of CRLF). Otherwise, return the length of
  1226. * the delimiter found.
  1227. */
  1228. static int
  1229. ldif_record_end( char *p )
  1230. {
  1231. if ( NULL != p )
  1232. {
  1233. if ( '\0' == *p )
  1234. {
  1235. return 0;
  1236. }
  1237. else if ( '\n' == *p && '\n' == *( p + 1 ))
  1238. {
  1239. return 2;
  1240. }
  1241. else if ( '\r' == *p && '\n' == *( p + 1 ) && '\r' == *( p + 2 ) && '\n' == *( p + 3 ))
  1242. {
  1243. return 4;
  1244. }
  1245. }
  1246. return -1;
  1247. }
  1248. char *
  1249. dse_read_next_entry( char *buf, char **lastp )
  1250. {
  1251. char *p, *start;
  1252. if ( NULL == buf )
  1253. {
  1254. *lastp = NULL;
  1255. return NULL;
  1256. }
  1257. p = start = ( NULL == *lastp ) ? buf : *lastp;
  1258. /* Skip over any leading record delimiters */
  1259. while ( '\n' == *p || '\r' == *p )
  1260. {
  1261. p++;
  1262. }
  1263. if ( '\0' == *p )
  1264. {
  1265. *lastp = NULL;
  1266. return NULL;
  1267. }
  1268. while ( '\0' != *p )
  1269. {
  1270. int rc;
  1271. if (( rc = ldif_record_end( p )) >= 0 )
  1272. {
  1273. /* Found end of LDIF record */
  1274. *p = '\0';
  1275. p += rc;
  1276. break;
  1277. }
  1278. else
  1279. {
  1280. p++;
  1281. }
  1282. }
  1283. *lastp = p;
  1284. return start;
  1285. }
  1286. /*
  1287. * Apply the function to each entry. The caller is responsible for locking
  1288. * the rwlock in the dse for the appropriate type of operation e.g. for
  1289. * searching, a read lock, for modifying in place, a write lock
  1290. */
  1291. static int
  1292. dse_apply_nolock(struct dse* pdse,IFP fp,caddr_t arg)
  1293. {
  1294. avl_apply( pdse->dse_tree, fp, arg, STOP_TRAVERSAL, AVL_INORDER );
  1295. return 1;
  1296. }
  1297. /*
  1298. * Remove the entry from the tree.
  1299. * Returns 1 if entry is removed and 0 if not.
  1300. */
  1301. static int
  1302. dse_delete_entry(struct dse* pdse, Slapi_PBlock *pb, const Slapi_Entry *e)
  1303. {
  1304. int dont_write_file = 0;
  1305. struct dse_node *n= dse_node_new(e);
  1306. struct dse_node *deleted_node = NULL;
  1307. slapi_pblock_get(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
  1308. /* keep write lock for both tree deleting and file writing */
  1309. if (pdse->dse_rwlock)
  1310. slapi_rwlock_wrlock(pdse->dse_rwlock);
  1311. if ((deleted_node = (struct dse_node *)avl_delete(&pdse->dse_tree,
  1312. n, entry_dn_cmp)))
  1313. dse_node_delete(&deleted_node);
  1314. dse_node_delete(&n);
  1315. if (!dont_write_file)
  1316. {
  1317. /* Decrement the numsubordinate count of the parent entry */
  1318. dse_updateNumSubOfParent(pdse, slapi_entry_get_sdn_const(e),
  1319. SLAPI_OPERATION_DELETE);
  1320. dse_write_file_nolock(pdse);
  1321. }
  1322. if (pdse->dse_rwlock)
  1323. slapi_rwlock_unlock(pdse->dse_rwlock);
  1324. return 1;
  1325. }
  1326. /*
  1327. * Returns a SLAPI_BIND_xxx retun code.
  1328. */
  1329. int
  1330. dse_bind( Slapi_PBlock *pb ) /* JCM There should only be one exit point from this function! */
  1331. {
  1332. ber_tag_t method; /* The bind method */
  1333. struct berval *cred; /* The bind credentials */
  1334. Slapi_Value **bvals;
  1335. struct dse* pdse;
  1336. Slapi_Attr *attr;
  1337. Slapi_DN *sdn = NULL;
  1338. Slapi_Entry *ec= NULL;
  1339. /*Get the parameters*/
  1340. if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
  1341. slapi_pblock_get( pb, SLAPI_BIND_TARGET_SDN, &sdn ) < 0 ||
  1342. slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) < 0 ||
  1343. slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred ) < 0){
  1344. slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
  1345. return SLAPI_BIND_FAIL;
  1346. }
  1347. /* always allow noauth simple binds */
  1348. if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 )
  1349. {
  1350. /*
  1351. * report success to client, but return
  1352. * SLAPI_BIND_FAIL so we don't
  1353. * authorize based on noauth credentials
  1354. */
  1355. slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
  1356. return( SLAPI_BIND_FAIL );
  1357. }
  1358. ec = dse_get_entry_copy(pdse, sdn, DSE_USE_LOCK);
  1359. if ( ec == NULL )
  1360. {
  1361. slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
  1362. return( SLAPI_BIND_FAIL );
  1363. }
  1364. switch ( method )
  1365. {
  1366. case LDAP_AUTH_SIMPLE:
  1367. {
  1368. Slapi_Value cv;
  1369. if ( slapi_entry_attr_find( ec, "userpassword", &attr ) != 0 )
  1370. {
  1371. slapi_send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL );
  1372. slapi_entry_free(ec);
  1373. return SLAPI_BIND_FAIL;
  1374. }
  1375. bvals= attr_get_present_values( attr );
  1376. slapi_value_init_berval(&cv,cred);
  1377. if ( slapi_pw_find_sv( bvals, &cv ) != 0 )
  1378. {
  1379. slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
  1380. slapi_entry_free(ec);
  1381. value_done(&cv);
  1382. return SLAPI_BIND_FAIL;
  1383. }
  1384. value_done(&cv);
  1385. }
  1386. break;
  1387. default:
  1388. slapi_send_ldap_result( pb, LDAP_STRONG_AUTH_NOT_SUPPORTED, NULL, "auth method not supported", 0, NULL );
  1389. slapi_entry_free(ec);
  1390. return SLAPI_BIND_FAIL;
  1391. }
  1392. slapi_entry_free(ec);
  1393. /* success: front end will send result */
  1394. return SLAPI_BIND_SUCCESS;
  1395. }
  1396. int
  1397. dse_unbind( Slapi_PBlock *pb )
  1398. {
  1399. return 0;
  1400. }
  1401. /*
  1402. * This structure is simply to pass parameters to dse_search_filter_entry.
  1403. */
  1404. struct magicSearchStuff
  1405. {
  1406. Slapi_PBlock *pb;
  1407. struct dse *pdse;
  1408. int scope;
  1409. const Slapi_DN *basedn;
  1410. Slapi_Filter *filter;
  1411. int nentries;
  1412. char **attrs; /*Attributes*/
  1413. int attrsonly; /*Should we just return the attributes found?*/
  1414. dse_search_set *ss; /* for the temporary results - to pass to the dse search callbacks */
  1415. };
  1416. /*
  1417. * The function which is called on each node of the AVL tree.
  1418. */
  1419. static int
  1420. dse_search_filter_entry(caddr_t data, caddr_t arg)
  1421. {
  1422. struct dse_node *n = (struct dse_node *)data;
  1423. struct magicSearchStuff *p= (struct magicSearchStuff *)arg;
  1424. if(slapi_sdn_scope_test( slapi_entry_get_sdn_const(n->entry), p->basedn, p->scope))
  1425. {
  1426. if(slapi_vattr_filter_test( p->pb, n->entry, p->filter, 1 /* verify access */ )==0)
  1427. {
  1428. Slapi_Entry *ec = slapi_entry_dup( n->entry );
  1429. p->nentries++;
  1430. if (!p->ss)
  1431. {
  1432. p->ss = dse_search_set_new();
  1433. }
  1434. dse_search_set_add_entry(p->ss, ec); /* consumes the entry */
  1435. } else {
  1436. /*
  1437. slapd_log_error_proc("dse_search_filter_entry",
  1438. "filter test failed: dn %s did not match filter %d\n",
  1439. slapi_entry_get_dn_const(n->entry), p->filter->f_choice);
  1440. */
  1441. }
  1442. } else {
  1443. /*
  1444. slapd_log_error_proc("dse_search_filter_entry",
  1445. "scope test failed: dn %s is not in scope %d of dn [%s]\n",
  1446. slapi_entry_get_dn_const(n->entry), p->scope,
  1447. slapi_sdn_get_dn(p->basedn));
  1448. */
  1449. }
  1450. return 0;
  1451. }
  1452. /*
  1453. * The function which kicks off the traversal of the AVL tree.
  1454. * Returns the number of entries returned.
  1455. */
  1456. /* jcm: Not very efficient if there are many DSE entries. */
  1457. /* jcm: It applies the filter to every node in the tree regardless */
  1458. static int
  1459. do_dse_search(struct dse* pdse, Slapi_PBlock *pb, int scope, const Slapi_DN *basedn, Slapi_Filter *filter, char **attrs, int attrsonly)
  1460. {
  1461. struct magicSearchStuff stuff;
  1462. stuff.pb= pb;
  1463. stuff.pdse= pdse;
  1464. stuff.scope= scope;
  1465. stuff.basedn= basedn;
  1466. stuff.filter= filter;
  1467. stuff.nentries= 0;
  1468. stuff.attrs= attrs;
  1469. stuff.attrsonly= attrsonly;
  1470. stuff.ss = NULL;
  1471. /*
  1472. * If this is a persistent search and the client is only interested in
  1473. * entries that change, we skip looking through the DSE entries.
  1474. */
  1475. if ( pb->pb_op == NULL
  1476. || !operation_is_flag_set( pb->pb_op, OP_FLAG_PS_CHANGESONLY )) {
  1477. if (pdse->dse_rwlock)
  1478. slapi_rwlock_rdlock(pdse->dse_rwlock);
  1479. dse_apply_nolock(pdse,dse_search_filter_entry,(caddr_t)&stuff);
  1480. if (pdse->dse_rwlock)
  1481. slapi_rwlock_unlock(pdse->dse_rwlock);
  1482. }
  1483. if (stuff.ss) /* something was found which matched our criteria */
  1484. {
  1485. Slapi_Entry *e = NULL;
  1486. for (e = dse_search_set_get_next_entry(stuff.ss);
  1487. e;
  1488. e = dse_search_set_get_next_entry(stuff.ss))
  1489. {
  1490. int returncode = 0;
  1491. char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= "";
  1492. if(dse_call_callback(pdse, pb, SLAPI_OPERATION_SEARCH,
  1493. DSE_FLAG_PREOP, e, NULL, &returncode, returntext)
  1494. == SLAPI_DSE_CALLBACK_OK)
  1495. {
  1496. dse_search_set *ss = NULL;
  1497. slapi_pblock_get (pb, SLAPI_SEARCH_RESULT_SET, &ss);
  1498. /* if this is the first entry - allocate dse_search_set structure */
  1499. if (ss == NULL)
  1500. {
  1501. ss = dse_search_set_new ();
  1502. slapi_pblock_set (pb, SLAPI_SEARCH_RESULT_SET, ss);
  1503. }
  1504. /* make another reference to e (stuff.ss references it too)
  1505. the stuff.ss reference is removed by dse_search_set_clean()
  1506. below, leaving ss as the sole owner of the memory */
  1507. dse_search_set_add_entry(ss, e);
  1508. } else {
  1509. stuff.nentries--; /* rejected entry */
  1510. /* this leaves a freed pointer in stuff.ss, but that's ok because
  1511. it should never be referenced, and the reference is removed by
  1512. the call to dse_search_set_clean() below */
  1513. slapi_entry_free(e);
  1514. }
  1515. }
  1516. dse_search_set_clean(stuff.ss);
  1517. }
  1518. /* the pblock ss now contains the "real" search result set and the copies of
  1519. the entries allocated in dse_search_filter_entry; any entries rejected by
  1520. the search callback were freed above by the call to slapi_entry_free() */
  1521. return stuff.nentries;
  1522. }
  1523. /*
  1524. * -1 means something went wrong.
  1525. * 0 means everything went ok.
  1526. */
  1527. int
  1528. dse_search(Slapi_PBlock *pb) /* JCM There should only be one exit point from this function! */
  1529. {
  1530. int scope; /*Scope of the search*/
  1531. Slapi_Filter *filter; /*The filter*/
  1532. char **attrs; /*Attributes*/
  1533. int attrsonly; /*Should we just return the attributes found?*/
  1534. /*int nentries= 0; Number of entries found thus far*/
  1535. struct dse* pdse;
  1536. int returncode= LDAP_SUCCESS;
  1537. int isrootdse= 0;
  1538. char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= "";
  1539. Slapi_DN *basesdn = NULL;
  1540. int estimate = 0; /* estimated search result set size */
  1541. /*
  1542. * Get private information created in the init routine.
  1543. * Also get the parameters of the search operation. These come
  1544. * more or less directly from the client.
  1545. */
  1546. if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
  1547. slapi_pblock_get( pb, SLAPI_SEARCH_TARGET_SDN, &basesdn ) < 0 ||
  1548. slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope ) < 0 ||
  1549. slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter ) < 0 ||
  1550. slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS, &attrs ) < 0 ||
  1551. slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly ) <0)
  1552. {
  1553. slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
  1554. return(-1);
  1555. }
  1556. /*
  1557. * Sadly the root dse is still a special case. We must not allow
  1558. * acl checks on it, or allow onelevel or subtree searches on it.
  1559. */
  1560. isrootdse= slapi_sdn_isempty(basesdn);
  1561. switch(scope)
  1562. {
  1563. case LDAP_SCOPE_BASE:
  1564. {
  1565. Slapi_Entry *baseentry= NULL;
  1566. baseentry = dse_get_entry_copy(pdse, basesdn, DSE_USE_LOCK);
  1567. if ( baseentry == NULL )
  1568. {
  1569. slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
  1570. slapi_log_error(SLAPI_LOG_PLUGIN,"dse_search", "node %s was not found\n",
  1571. slapi_sdn_get_dn(basesdn));
  1572. return -1;
  1573. }
  1574. /*
  1575. * We don't want to do an acl check for the root dse... because the acl
  1576. * code thinks it's a suffix of every target... so every acl applies to
  1577. * the root dse... which is wrong.
  1578. */
  1579. if(slapi_vattr_filter_test( pb, baseentry, filter, !isrootdse /* verify access */ )==0)
  1580. {
  1581. /* Callbacks modify a copy of the entry */
  1582. if(dse_call_callback(pdse, pb, SLAPI_OPERATION_SEARCH,
  1583. DSE_FLAG_PREOP, baseentry, NULL, &returncode, returntext)
  1584. == SLAPI_DSE_CALLBACK_OK)
  1585. {
  1586. dse_search_set *ss;
  1587. ss = dse_search_set_new ();
  1588. slapi_pblock_set (pb, SLAPI_SEARCH_RESULT_SET, ss);
  1589. dse_search_set_add_entry (ss, baseentry); /* consumes the entry */
  1590. baseentry= NULL;
  1591. estimate = 1; /* scope base */
  1592. }
  1593. }
  1594. slapi_entry_free(baseentry);
  1595. }
  1596. break;
  1597. case LDAP_SCOPE_ONELEVEL:
  1598. /* FALL THROUGH */
  1599. case LDAP_SCOPE_SUBTREE:
  1600. if(!isrootdse)
  1601. {
  1602. estimate = do_dse_search(pdse, pb, scope, basesdn, filter, attrs, attrsonly);
  1603. }
  1604. break;
  1605. }
  1606. slapi_pblock_set (pb, SLAPI_SEARCH_RESULT_SET_SIZE_ESTIMATE, &estimate);
  1607. /* Search is done, send LDAP_SUCCESS */
  1608. return 0;
  1609. }
  1610. /*
  1611. * -1 means something went wrong.
  1612. * 0 means everything went ok.
  1613. */
  1614. static int
  1615. dse_modify_return( int rv, Slapi_Entry *ec, Slapi_Entry *ecc )
  1616. {
  1617. slapi_entry_free(ec);
  1618. slapi_entry_free(ecc);
  1619. return rv;
  1620. }
  1621. int
  1622. dse_modify(Slapi_PBlock *pb) /* JCM There should only be one exit point from this function! */
  1623. {
  1624. int err; /*House keeping stuff*/
  1625. LDAPMod **mods; /*Used to apply the modifications*/
  1626. char *errbuf = NULL; /* To get error back */
  1627. struct dse* pdse;
  1628. Slapi_Entry *ec = NULL;
  1629. Slapi_Entry *ecc = NULL;
  1630. int returncode = LDAP_SUCCESS;
  1631. char returntext[SLAPI_DSE_RETURNTEXT_SIZE] = "";
  1632. Slapi_DN *sdn = NULL;
  1633. int dont_write_file = 0; /* default */
  1634. int rc = SLAPI_DSE_CALLBACK_DO_NOT_APPLY;
  1635. int retval = -1;
  1636. int need_be_postop = 0;
  1637. int plugin_started = 0;
  1638. int internal_op = 0;
  1639. PRBool global_lock_owned = PR_FALSE;
  1640. PR_ASSERT(pb);
  1641. if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
  1642. /* slapi_pblock_get( pb, SLAPI_MODIFY_TARGET, &dn ) < 0 || */
  1643. slapi_pblock_get( pb, SLAPI_MODIFY_TARGET_SDN, &sdn ) < 0 ||
  1644. slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ) < 0 || (NULL == pdse)) {
  1645. returncode = LDAP_OPERATIONS_ERROR;
  1646. goto done;
  1647. }
  1648. slapi_pblock_get(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
  1649. if ( !dont_write_file && dse_check_for_readonly_error(pb,pdse)) {
  1650. /* already returned result */
  1651. return retval;
  1652. }
  1653. internal_op = operation_is_flag_set(pb->pb_op, OP_FLAG_INTERNAL);
  1654. /* Find the entry we are about to modify. */
  1655. ec = dse_get_entry_copy(pdse, sdn, DSE_USE_LOCK);
  1656. if ( ec == NULL ) {
  1657. returncode = LDAP_NO_SUCH_OBJECT;
  1658. goto done;
  1659. }
  1660. /* Check acl */
  1661. err = plugin_call_acl_mods_access ( pb, ec, mods, &errbuf );
  1662. if ( err != LDAP_SUCCESS ) {
  1663. returncode = err;
  1664. if (errbuf) {
  1665. PL_strncpyz(returntext, errbuf, sizeof(returntext));
  1666. slapi_ch_free_string(&errbuf);
  1667. }
  1668. goto done;
  1669. }
  1670. /* Save away a copy of the entry, before modifications */
  1671. slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup( ec )); /* JCM - When does this get free'd? */
  1672. /* richm - it is freed in modify.c */
  1673. /* Modify a copy of the entry*/
  1674. ecc = slapi_entry_dup( ec );
  1675. err = entry_apply_mods( ecc, mods );
  1676. /* Possibly acquire the global backend lock */
  1677. if (global_backend_lock_requested()) {
  1678. global_backend_lock_lock();
  1679. global_lock_owned = PR_TRUE;
  1680. }
  1681. /* XXXmcs: should we expand objectclass values here?? */
  1682. /* give the dse callbacks the first crack at the modify */
  1683. rc = dse_call_callback(pdse, pb, SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, ec, ecc, &returncode, returntext);
  1684. if (SLAPI_DSE_CALLBACK_OK == rc) {
  1685. /* next, give the be plugins a crack at it */
  1686. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &returncode);
  1687. slapi_pblock_set(pb, SLAPI_MODIFY_EXISTING_ENTRY, ecc);
  1688. rc = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN);
  1689. need_be_postop = 1; /* if the be preops were called, have to call the be postops too */
  1690. if (!returncode) {
  1691. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  1692. }
  1693. if (!rc && !returncode) {
  1694. /* finally, give the betxn plugins a crack at it */
  1695. rc = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN);
  1696. if (!returncode) {
  1697. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  1698. }
  1699. if (rc || returncode) {
  1700. LDAPDebug( SLAPI_DSE_TRACELEVEL,
  1701. "dse_modify: SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN failed - rc %d LDAP error %d:%s\n",
  1702. rc, returncode, ldap_err2string(returncode));
  1703. }
  1704. } else {
  1705. LDAPDebug( SLAPI_DSE_TRACELEVEL,
  1706. "dse_modify: SLAPI_PLUGIN_BE_PRE_MODIFY_FN failed - rc %d LDAP error %d:%s\n",
  1707. rc, returncode, ldap_err2string(returncode));
  1708. }
  1709. if (rc || returncode) {
  1710. char *ldap_result_message = NULL;
  1711. rc = SLAPI_DSE_CALLBACK_ERROR;
  1712. if (!returncode) {
  1713. LDAPDebug0Args( SLAPI_DSE_TRACELEVEL,
  1714. "dse_modify: PRE_MODIFY plugin returned non-zero but did not set an LDAP error\n");
  1715. returncode = LDAP_OPERATIONS_ERROR;
  1716. }
  1717. if (!returntext[0]) {
  1718. slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
  1719. if (ldap_result_message && ldap_result_message[0]) {
  1720. PL_strncpyz(returntext, ldap_result_message, sizeof(returntext));
  1721. }
  1722. }
  1723. } else {
  1724. /*
  1725. * If we are using dynamic plugins, and we are modifying a plugin
  1726. * we need to do some additional checks. First, check if we are
  1727. * enabling/disabling a plugin. Then make sure the plugin still
  1728. * starts after applying the plugin changes.
  1729. */
  1730. rc = SLAPI_DSE_CALLBACK_OK;
  1731. if(config_get_dynamic_plugins() &&
  1732. slapi_entry_attr_hasvalue(ec, SLAPI_ATTR_OBJECTCLASS, "nsSlapdPlugin") )
  1733. {
  1734. if((plugin_started = dse_modify_plugin(ec, ecc, returntext)) == -1){
  1735. returncode = LDAP_UNWILLING_TO_PERFORM;
  1736. rc = SLAPI_DSE_CALLBACK_ERROR;
  1737. retval = -1;
  1738. goto done;
  1739. }
  1740. /*
  1741. * If this is not a internal operation, make sure the plugin
  1742. * can be restarted.
  1743. */
  1744. if(!internal_op){
  1745. if(dse_pre_modify_plugin(ec, ecc, mods)){
  1746. char *errtext;
  1747. slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext);
  1748. if (errtext) {
  1749. PL_strncpyz(returntext,
  1750. "Failed to apply plugin config change, "
  1751. "check the errors log for more info.",
  1752. sizeof(returntext));
  1753. }
  1754. returncode = LDAP_UNWILLING_TO_PERFORM;
  1755. rc = SLAPI_DSE_CALLBACK_ERROR;
  1756. retval = -1;
  1757. goto done;
  1758. }
  1759. }
  1760. }
  1761. }
  1762. }
  1763. switch(rc) {
  1764. case SLAPI_DSE_CALLBACK_ERROR:
  1765. /* Error occured in the callback -- return error code from callback */
  1766. goto done;
  1767. break;
  1768. case SLAPI_DSE_CALLBACK_DO_NOT_APPLY:
  1769. /* Callback says don't apply the changes -- return Success */
  1770. returncode = LDAP_SUCCESS;
  1771. returntext[0] = '\0';
  1772. retval = 0;
  1773. goto done;
  1774. break;
  1775. case SLAPI_DSE_CALLBACK_OK: {
  1776. /* The callback may alter the mods in the pblock. This happens
  1777. for example in the schema code. Since the schema attributes
  1778. are managed exclusively by the schema code, we should not
  1779. apply those mods. However, for reasons unknown to me, we
  1780. must in the general case call entry_apply_mods before calling
  1781. the modify callback above. In the case of schema, the schema
  1782. code will remove the schema attributes from the mods. So, we
  1783. reapply the mods to the entry for the attributes we manage in
  1784. the dse code (e.g. aci)
  1785. */
  1786. int reapply_mods = 0; /* default is to not reapply entry_apply_mods */
  1787. slapi_pblock_get(pb, SLAPI_DSE_REAPPLY_MODS, &reapply_mods);
  1788. /* Callback says apply the changes */
  1789. if ( reapply_mods ) {
  1790. LDAPMod **modsagain = NULL; /*Used to apply the modifications*/
  1791. slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &modsagain );
  1792. if (NULL != modsagain) {
  1793. /* the dse modify callback must have modified ecc back to it's
  1794. original state, before the earlier apply_mods, but without the
  1795. attributes it did not want us to apply mods to */
  1796. err = entry_apply_mods( ecc, modsagain );
  1797. }
  1798. }
  1799. if (err != 0) {
  1800. returncode = err;
  1801. returntext[0] = '\0';
  1802. retval = -1;
  1803. goto done;
  1804. }
  1805. break;
  1806. }
  1807. }
  1808. /* We're applying the mods... check that the entry still obeys the schema */
  1809. if ( slapi_entry_schema_check( pb, ecc ) != 0 ) {
  1810. char *errtext;
  1811. slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext);
  1812. if (errtext) {
  1813. PL_strncpyz(returntext, errtext, sizeof(returntext));
  1814. }
  1815. returncode = LDAP_OBJECT_CLASS_VIOLATION;
  1816. retval = -1;
  1817. goto done;
  1818. }
  1819. /* Check if the attribute values in the mods obey the syntaxes */
  1820. if ( slapi_mods_syntax_check( pb, mods, 0 ) != 0 ) {
  1821. char *errtext;
  1822. slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext);
  1823. if (errtext) {
  1824. PL_strncpyz(returntext, errtext, sizeof(returntext));
  1825. }
  1826. returncode = LDAP_INVALID_SYNTAX;
  1827. retval = -1;
  1828. goto done;
  1829. }
  1830. /* Change the entry itself both on disk and in the AVL tree */
  1831. /* dse_replace_entry free's the existing entry. */
  1832. if (dse_replace_entry( pdse, ecc, !dont_write_file, DSE_USE_LOCK )!=0 ) {
  1833. returncode = LDAP_OPERATIONS_ERROR;
  1834. retval = -1;
  1835. goto done;
  1836. }
  1837. retval = 0; /* so far, so good */
  1838. slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, slapi_entry_dup(ecc) ); /* JCM - When does this get free'd? */
  1839. /* richm - it is freed in modify.c */
  1840. /* give the dse callbacks the first crack at the modify */
  1841. rc = dse_call_callback(pdse, pb, SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP, ec, ecc, &returncode, returntext);
  1842. done:
  1843. if (rc != SLAPI_DSE_CALLBACK_DO_NOT_APPLY) {
  1844. /* make sure OPRETURN is set */
  1845. slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &err);
  1846. if ((retval || returncode) && !err) {
  1847. slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, retval ? &retval : &returncode);
  1848. }
  1849. /* next, give the betxn plugins a crack at it */
  1850. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &returncode);
  1851. slapi_pblock_set(pb, SLAPI_MODIFY_EXISTING_ENTRY, ecc);
  1852. if (need_be_postop) {
  1853. plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN);
  1854. if (!returncode) {
  1855. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  1856. }
  1857. if (returncode && !returntext[0]) {
  1858. char *ldap_result_message = NULL;
  1859. slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
  1860. if (ldap_result_message && ldap_result_message[0]) {
  1861. PL_strncpyz(returntext, ldap_result_message, sizeof(returntext));
  1862. }
  1863. }
  1864. plugin_call_plugins(pb, SLAPI_PLUGIN_BE_POST_MODIFY_FN);
  1865. if (!returncode) {
  1866. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  1867. }
  1868. }
  1869. }
  1870. if (global_lock_owned) {
  1871. global_backend_lock_unlock();
  1872. }
  1873. slapi_send_ldap_result( pb, returncode, NULL, returntext[0] ? returntext : NULL, 0, NULL );
  1874. return dse_modify_return(retval, ec, ecc);
  1875. }
  1876. static int
  1877. dse_pre_modify_plugin(Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, LDAPMod **mods)
  1878. {
  1879. char *enabled = NULL;
  1880. int restart_plugin = 1;
  1881. int rc = 0;
  1882. int i;
  1883. /*
  1884. * Only check the mods if the plugin is enabled - no need to restart a plugin if it's not running.
  1885. */
  1886. if ( (enabled = slapi_entry_attr_get_charptr(entryBefore, ATTR_PLUGIN_ENABLED)) &&
  1887. !strcasecmp(enabled, "on"))
  1888. {
  1889. for(i = 0; mods && mods[i]; i++){
  1890. if (strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_ENABLED) == 0){
  1891. /* we already stop/started the pugin - don't do it again */
  1892. restart_plugin = 0;
  1893. break;
  1894. }
  1895. }
  1896. if(restart_plugin){ /* for all other plugin config changes, restart the plugin */
  1897. if(plugin_restart(entryBefore, entryAfter) != LDAP_SUCCESS){
  1898. slapi_log_error(SLAPI_LOG_FATAL,"dse_pre_modify_plugin",
  1899. "The configuration change for plugin (%s) could not be applied.\n",
  1900. slapi_entry_get_dn(entryBefore));
  1901. rc = -1;
  1902. }
  1903. }
  1904. }
  1905. slapi_ch_free_string(&enabled);
  1906. return rc;
  1907. }
  1908. /*
  1909. * If this is modifying a plugin, check if we are disabling/enabling it - update the
  1910. * global plugins as needed.
  1911. *
  1912. * Return 1 if the plugin was successfully started
  1913. * Return 2 if the plugin was successfully stopped
  1914. * Return -1 on error
  1915. * Return 0 if nothing was done
  1916. */
  1917. static int
  1918. dse_modify_plugin(Slapi_Entry *pre_entry, Slapi_Entry *post_entry, char *returntext)
  1919. {
  1920. int rc = LDAP_SUCCESS;
  1921. if( slapi_entry_attr_hasvalue(pre_entry, "nsslapd-pluginEnabled", "on") &&
  1922. slapi_entry_attr_hasvalue(post_entry, "nsslapd-pluginEnabled", "off") )
  1923. {
  1924. /*
  1925. * Plugin has been disabled
  1926. */
  1927. if(plugin_delete(post_entry, returntext, 0 /* not locked */)){
  1928. rc = -1;
  1929. } else {
  1930. rc = 2; /* plugin disabled */
  1931. slapi_log_error(SLAPI_LOG_PLUGIN,"dse_modify_plugin", "Disabled plugin (%s)\n",
  1932. slapi_entry_get_dn(post_entry));
  1933. }
  1934. } else if ( slapi_entry_attr_hasvalue(pre_entry, "nsslapd-pluginEnabled", "off") &&
  1935. slapi_entry_attr_hasvalue(post_entry, "nsslapd-pluginEnabled", "on") )
  1936. {
  1937. /*
  1938. * Plugin has been enabled
  1939. */
  1940. if(plugin_add(post_entry, returntext, 0 /* not locked */)){
  1941. rc = -1;
  1942. } else {
  1943. rc = 1; /* plugin started */
  1944. slapi_log_error(SLAPI_LOG_PLUGIN,"dse_modify_plugin", "Enabled plugin (%s)\n",
  1945. slapi_entry_get_dn(post_entry));
  1946. }
  1947. }
  1948. return rc;
  1949. }
  1950. /*
  1951. * Add the plugin to the global plugin list
  1952. */
  1953. static int
  1954. dse_add_plugin(Slapi_Entry *entry, char *returntext)
  1955. {
  1956. int rc = LDAP_SUCCESS;
  1957. if (!slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "nsSlapdPlugin") ||
  1958. !config_get_dynamic_plugins() )
  1959. {
  1960. /*
  1961. * This is not a plugin, or we are not allowing dynamic updates.
  1962. */
  1963. return rc;
  1964. }
  1965. rc = plugin_add(entry, returntext, 0 /* not locked */);
  1966. return rc;
  1967. }
  1968. /*
  1969. * Delete the plugin from the global plugin list
  1970. */
  1971. static int
  1972. dse_delete_plugin(Slapi_Entry *entry, char *returntext)
  1973. {
  1974. int rc = LDAP_SUCCESS;
  1975. if (!slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "nsSlapdPlugin") ||
  1976. slapi_entry_attr_hasvalue(entry, "nsslapd-PluginEnabled", "off") ||
  1977. !config_get_dynamic_plugins() )
  1978. {
  1979. /*
  1980. * This is not a plugin, this plugin was not enabled to begin with, or we
  1981. * are not allowing dynamic updates .
  1982. */
  1983. return rc;
  1984. }
  1985. rc = plugin_delete(entry, returntext, 0 /* not locked */);
  1986. return rc;
  1987. }
  1988. static int
  1989. dse_add_return( int rv, Slapi_Entry *e)
  1990. {
  1991. slapi_entry_free(e);
  1992. return rv;
  1993. }
  1994. /*
  1995. * -1 means something went wrong.
  1996. * 0 means everything went ok.
  1997. */
  1998. int
  1999. dse_add(Slapi_PBlock *pb) /* JCM There should only be one exit point from this function! */
  2000. {
  2001. Slapi_Entry *e = NULL; /*The new entry to add*/
  2002. Slapi_Entry *e_copy = NULL; /* copy of added entry */
  2003. char *errbuf = NULL;
  2004. int rc = LDAP_SUCCESS;
  2005. int error = -1;
  2006. int dont_write_file = 0; /* default */
  2007. struct dse* pdse;
  2008. int returncode = LDAP_SUCCESS;
  2009. char returntext[SLAPI_DSE_RETURNTEXT_SIZE] = "";
  2010. Slapi_DN *sdn = NULL;
  2011. Slapi_DN parent;
  2012. int need_be_postop = 0;
  2013. PRBool global_lock_owned = PR_FALSE;
  2014. /*
  2015. * Get the database, the dn and the entry to add
  2016. */
  2017. if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
  2018. slapi_pblock_get( pb, SLAPI_ADD_TARGET_SDN, &sdn ) < 0 ||
  2019. slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e ) < 0 || (NULL == pdse)) {
  2020. rc = LDAP_OPERATIONS_ERROR;
  2021. goto done;
  2022. }
  2023. slapi_pblock_get(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
  2024. if ( !dont_write_file && dse_check_for_readonly_error(pb,pdse)) {
  2025. return( error ); /* result already sent */
  2026. }
  2027. /*
  2028. * Check to make sure the entry passes the schema check
  2029. */
  2030. if ( slapi_entry_schema_check( pb, e ) != 0 ) {
  2031. char *errtext;
  2032. LDAPDebug( SLAPI_DSE_TRACELEVEL,
  2033. "dse_add: entry failed schema check\n", 0, 0, 0 );
  2034. slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext);
  2035. if (errtext && errtext[0]) {
  2036. PL_strncpyz(returntext, errtext, sizeof(returntext));
  2037. }
  2038. rc = LDAP_OBJECT_CLASS_VIOLATION;
  2039. e = NULL; /* caller will free upon error */
  2040. goto done;
  2041. }
  2042. /* Check if the attribute values in the entry obey the syntaxes */
  2043. if ( slapi_entry_syntax_check( pb, e, 0 ) != 0 ) {
  2044. char *errtext;
  2045. LDAPDebug( SLAPI_DSE_TRACELEVEL,
  2046. "dse_add: entry failed syntax check\n", 0, 0, 0 );
  2047. slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext);
  2048. if (errtext && errtext[0]) {
  2049. PL_strncpyz(returntext, errtext, sizeof(returntext));
  2050. }
  2051. rc = LDAP_INVALID_SYNTAX;
  2052. e = NULL; /* caller will free upon error */
  2053. goto done;
  2054. }
  2055. /*
  2056. * Attempt to find this dn.
  2057. */
  2058. {
  2059. Slapi_Entry *existingentry= dse_get_entry_copy( pdse, sdn, DSE_USE_LOCK );
  2060. if(existingentry!=NULL) {
  2061. /*
  2062. * If we've reached this code, there is an entry
  2063. * whose dn matches dn, so tell the user and return
  2064. */
  2065. slapi_entry_free(existingentry);
  2066. rc = LDAP_ALREADY_EXISTS;
  2067. e = NULL; /* caller will free upon error */
  2068. goto done;
  2069. }
  2070. }
  2071. /*
  2072. * Get the parent dn and see if the corresponding entry exists.
  2073. * If the parent does not exist, only allow the "root" user to
  2074. * add the entry.
  2075. */
  2076. slapi_sdn_init(&parent);
  2077. slapi_sdn_get_parent(sdn, &parent);
  2078. if ( !slapi_sdn_isempty(&parent) ) {
  2079. Slapi_Entry *parententry= NULL;
  2080. parententry= dse_get_entry_copy( pdse, &parent, DSE_USE_LOCK );
  2081. if( parententry==NULL ) {
  2082. rc = LDAP_NO_SUCH_OBJECT;
  2083. LDAPDebug( SLAPI_DSE_TRACELEVEL, "dse_add: parent does not exist\n", 0, 0, 0 );
  2084. slapi_sdn_done(&parent);
  2085. e = NULL; /* caller will free upon error */
  2086. goto done;
  2087. }
  2088. rc= plugin_call_acl_plugin ( pb, parententry, NULL, NULL, SLAPI_ACL_ADD, ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
  2089. slapi_entry_free(parententry);
  2090. if ( rc!=LDAP_SUCCESS ) {
  2091. LDAPDebug( SLAPI_DSE_TRACELEVEL, "dse_add: no access to parent\n", 0, 0, 0 );
  2092. if (errbuf && errbuf[0]) {
  2093. PL_strncpyz(returntext, errbuf, sizeof(returntext));
  2094. }
  2095. slapi_ch_free_string(&errbuf);
  2096. slapi_sdn_done(&parent);
  2097. e = NULL; /* caller will free upon error */
  2098. goto done;
  2099. }
  2100. } else {
  2101. /* no parent */
  2102. int isroot;
  2103. slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
  2104. if ( !isroot ) {
  2105. LDAPDebug( SLAPI_DSE_TRACELEVEL, "dse_add: no parent and not root\n", 0, 0, 0 );
  2106. rc = LDAP_INSUFFICIENT_ACCESS;
  2107. slapi_sdn_done(&parent);
  2108. e = NULL; /* caller will free upon error */
  2109. goto done;
  2110. }
  2111. }
  2112. slapi_sdn_done(&parent);
  2113. /*
  2114. * Before we add the entry, find out if the syntax of the aci
  2115. * aci attribute values are correct or not. We don't want to add
  2116. * the entry if the syntax is incorrect.
  2117. */
  2118. if ( plugin_call_acl_verify_syntax (pb, e, &errbuf) != 0 ) {
  2119. if (errbuf && errbuf[0]) {
  2120. PL_strncpyz(returntext, errbuf, sizeof(returntext));
  2121. slapi_ch_free_string(&errbuf);
  2122. }
  2123. rc = LDAP_INVALID_SYNTAX;
  2124. e = NULL; /* caller will free upon error */
  2125. goto done;
  2126. }
  2127. /* Possibly acquire the global backend lock */
  2128. if (global_backend_lock_requested()) {
  2129. global_backend_lock_lock();
  2130. global_lock_owned = PR_TRUE;
  2131. }
  2132. if(dse_call_callback(pdse, pb, SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, e,
  2133. NULL, &returncode, returntext)!=SLAPI_DSE_CALLBACK_OK) {
  2134. if (!returncode) {
  2135. LDAPDebug( LDAP_DEBUG_ANY, "dse_add: DSE PREOP callback returned error but did not set returncode\n", 0, 0, 0 );
  2136. returncode = LDAP_OPERATIONS_ERROR;
  2137. }
  2138. rc = returncode;
  2139. e = NULL; /* caller will free upon error */
  2140. goto done;
  2141. }
  2142. /* next, give the be plugins a crack at it */
  2143. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &returncode);
  2144. plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_ADD_FN);
  2145. need_be_postop = 1; /* have to call be postops now */
  2146. if (!returncode) {
  2147. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  2148. }
  2149. if (!returncode) {
  2150. /* finally, give the betxn plugins a crack at it */
  2151. plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN);
  2152. if (!returncode) {
  2153. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  2154. }
  2155. }
  2156. if (returncode) {
  2157. if (!returntext[0]) {
  2158. char *ldap_result_message = NULL;
  2159. slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
  2160. if (ldap_result_message && ldap_result_message[0]) {
  2161. PL_strncpyz(returntext, ldap_result_message, sizeof(returntext));
  2162. }
  2163. }
  2164. rc = returncode;
  2165. e = NULL; /* caller will free upon error */
  2166. goto done;
  2167. }
  2168. /*
  2169. * Check if we are adding a plugin
  2170. */
  2171. if(dse_add_plugin(e, returntext)){
  2172. returncode = LDAP_UNWILLING_TO_PERFORM;
  2173. goto done;
  2174. }
  2175. /* make copy for postop fns because add_entry_pb consumes the given entry */
  2176. e_copy = slapi_entry_dup(e);
  2177. if ( dse_add_entry_pb(pdse, e_copy, pb) != 0) {
  2178. rc = LDAP_OPERATIONS_ERROR;
  2179. e = NULL; /* caller will free upon error */
  2180. goto done;
  2181. }
  2182. /* The postop must be called after the write lock is released. */
  2183. dse_call_callback(pdse, pb, SLAPI_OPERATION_ADD, DSE_FLAG_POSTOP, e, NULL, &returncode, returntext);
  2184. done:
  2185. if (e) {
  2186. slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, slapi_entry_dup( e ));
  2187. }
  2188. /* make sure OPRETURN and RESULT_CODE are set */
  2189. slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &error);
  2190. if (rc || returncode) {
  2191. if (!error) {
  2192. slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, rc ? &rc : &returncode);
  2193. }
  2194. if (!returncode) {
  2195. returncode = rc;
  2196. }
  2197. }
  2198. if (need_be_postop) {
  2199. /* next, give the be txn plugins a crack at it */
  2200. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &returncode);
  2201. plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN);
  2202. /* finally, give the be plugins a crack at it */
  2203. plugin_call_plugins(pb, SLAPI_PLUGIN_BE_POST_ADD_FN);
  2204. if (!returncode) {
  2205. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  2206. }
  2207. }
  2208. if (global_lock_owned) {
  2209. global_backend_lock_unlock();
  2210. }
  2211. slapi_send_ldap_result(pb, returncode, NULL, returntext[0] ? returntext : NULL, 0, NULL );
  2212. return dse_add_return(rc, e);
  2213. }
  2214. /*
  2215. * -1 means something went wrong.
  2216. * 0 means everything went ok.
  2217. */
  2218. static int
  2219. dse_delete_return( int rv, Slapi_Entry *ec)
  2220. {
  2221. slapi_entry_free(ec);
  2222. return rv;
  2223. }
  2224. int
  2225. dse_delete(Slapi_PBlock *pb) /* JCM There should only be one exit point from this function! */
  2226. {
  2227. int rc= -1;
  2228. int dont_write_file = 0; /* default */
  2229. struct dse* pdse = NULL;
  2230. int returncode = LDAP_SUCCESS;
  2231. char returntext[SLAPI_DSE_RETURNTEXT_SIZE] = "";
  2232. char *entry_str = "entry";
  2233. char *errbuf = NULL;
  2234. char *attrs[2] = { NULL, NULL };
  2235. Slapi_DN *sdn = NULL;
  2236. Slapi_Entry *ec = NULL; /* copy of entry to delete */
  2237. Slapi_Entry *orig_entry = NULL;
  2238. int need_be_postop = 0;
  2239. PRBool global_lock_owned = PR_FALSE;
  2240. /*
  2241. * Get the database and the dn
  2242. */
  2243. if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
  2244. slapi_pblock_get( pb, SLAPI_DELETE_TARGET_SDN, &sdn ) < 0 ||
  2245. (pdse == NULL)) {
  2246. returncode = LDAP_OPERATIONS_ERROR;
  2247. goto done;
  2248. }
  2249. slapi_pblock_get(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
  2250. if ( !dont_write_file && dse_check_for_readonly_error(pb,pdse)) {
  2251. return( rc ); /* result already sent */
  2252. }
  2253. ec= dse_get_entry_copy( pdse, sdn, DSE_USE_LOCK );
  2254. if (ec == NULL) {
  2255. returncode = LDAP_NO_SUCH_OBJECT;
  2256. goto done;
  2257. }
  2258. /*
  2259. * Check if this node has any children.
  2260. */
  2261. if(dse_numsubordinates(ec)>0) {
  2262. returncode = LDAP_NOT_ALLOWED_ON_NONLEAF;
  2263. goto done;
  2264. }
  2265. /*
  2266. * Check the access
  2267. */
  2268. attrs[0] = entry_str;
  2269. attrs[1] = NULL;
  2270. returncode= plugin_call_acl_plugin ( pb, ec, attrs, NULL, SLAPI_ACL_DELETE, ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
  2271. if ( returncode!=LDAP_SUCCESS) {
  2272. if (errbuf && errbuf[0]) {
  2273. PL_strncpyz(returntext, errbuf, sizeof(returntext));
  2274. }
  2275. slapi_ch_free_string(&errbuf);
  2276. goto done;
  2277. }
  2278. /* Possibly acquire the global backend lock */
  2279. if (global_backend_lock_requested()) {
  2280. global_backend_lock_lock();
  2281. global_lock_owned = PR_TRUE;
  2282. }
  2283. if(dse_call_callback(pdse, pb, SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, ec, NULL, &returncode,returntext)==SLAPI_DSE_CALLBACK_OK) {
  2284. slapi_pblock_set(pb, SLAPI_DELETE_BEPREOP_ENTRY, ec);
  2285. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &returncode);
  2286. plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_DELETE_FN);
  2287. need_be_postop = 1;
  2288. if (!returncode) {
  2289. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  2290. }
  2291. if (!returncode) {
  2292. plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN);
  2293. if (!returncode) {
  2294. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  2295. }
  2296. if (!returncode) {
  2297. if(dse_delete_entry(pdse, pb, ec)==0) {
  2298. returncode= LDAP_OPERATIONS_ERROR;
  2299. }
  2300. }
  2301. }
  2302. /* Setting SLAPI_ENTRY_PRE_OP here,
  2303. * since some betxn postop may need the pre op entry. */
  2304. slapi_pblock_set(pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup(ec));
  2305. } else {
  2306. goto done;
  2307. }
  2308. dse_call_callback(pdse, pb, SLAPI_OPERATION_DELETE, DSE_FLAG_POSTOP, ec, NULL, &returncode, returntext);
  2309. done:
  2310. slapi_pblock_get(pb, SLAPI_DELETE_BEPOSTOP_ENTRY, &orig_entry);
  2311. slapi_pblock_set(pb, SLAPI_DELETE_BEPOSTOP_ENTRY, ec);
  2312. /* make sure OPRETURN and RESULT_CODE are set */
  2313. slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc);
  2314. if (returncode || rc) {
  2315. if (!rc) {
  2316. slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &returncode);
  2317. }
  2318. if (!returncode) {
  2319. returncode = rc;
  2320. }
  2321. }
  2322. if (need_be_postop) {
  2323. plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN);
  2324. if (!returncode) {
  2325. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  2326. }
  2327. /* finally, give the be plugins a crack at it */
  2328. plugin_call_plugins(pb, SLAPI_PLUGIN_BE_POST_DELETE_FN);
  2329. if (!returncode) {
  2330. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &returncode);
  2331. }
  2332. }
  2333. if (global_lock_owned) {
  2334. global_backend_lock_unlock();
  2335. }
  2336. if (returncode && !returntext[0]) {
  2337. char *ldap_result_message = NULL;
  2338. slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
  2339. if (ldap_result_message && ldap_result_message[0]) {
  2340. PL_strncpyz(returntext, ldap_result_message, sizeof(returntext));
  2341. }
  2342. }
  2343. /*
  2344. * Check if we are deleting a plugin
  2345. */
  2346. if(returncode == LDAP_SUCCESS){
  2347. if(dse_delete_plugin(ec, returntext)){
  2348. rc = LDAP_UNWILLING_TO_PERFORM;
  2349. }
  2350. }
  2351. slapi_pblock_set(pb, SLAPI_DELETE_BEPOSTOP_ENTRY, orig_entry);
  2352. slapi_send_ldap_result( pb, returncode, NULL, returntext, 0, NULL );
  2353. return dse_delete_return(returncode, ec);
  2354. }
  2355. struct dse_callback *
  2356. dse_register_callback(struct dse* pdse,
  2357. int operation,
  2358. int flags,
  2359. const Slapi_DN *base,
  2360. int scope,
  2361. const char *filter,
  2362. dseCallbackFn fn,
  2363. void *fn_arg,
  2364. struct slapdplugin *plugin)
  2365. {
  2366. struct dse_callback *callback = dse_callback_new(operation, flags, base, scope, filter, fn, fn_arg, plugin);
  2367. dse_callback_addtolist(&pdse->dse_callback, callback);
  2368. return callback;
  2369. }
  2370. void
  2371. dse_remove_callback(struct dse* pdse, int operation, int flags, const Slapi_DN *base, int scope, const char *filter, dseCallbackFn fn)
  2372. {
  2373. dse_callback_removefromlist(&pdse->dse_callback, operation, flags, base, scope, filter, fn);
  2374. }
  2375. /*
  2376. * Return values:
  2377. * SLAPI_DSE_CALLBACK_ERROR -- Callback failed.
  2378. * SLAPI_DSE_CALLBACK_OK -- OK, do it.
  2379. * SLAPI_DSE_CALLBACK_DO_NOT_APPLY -- No error, but don't apply changes.
  2380. */
  2381. static int
  2382. dse_call_callback(struct dse* pdse, Slapi_PBlock *pb, int operation, int flags, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char *returntext)
  2383. {
  2384. /* ONREPL callbacks can potentially modify pblock parameters like backend
  2385. * which would cause problems during request processing. We need to save
  2386. * "important" fields before calls and restoring them afterwards */
  2387. int rc = SLAPI_DSE_CALLBACK_OK;
  2388. if (pdse->dse_callback != NULL) {
  2389. struct dse_callback *p = pdse->dse_callback;
  2390. struct dse_callback *next = NULL;
  2391. int result = SLAPI_DSE_CALLBACK_OK;
  2392. while (p != NULL) {
  2393. next = p->next;
  2394. if ((p->operation & operation) && (p->flags & flags)) {
  2395. if(slapi_sdn_scope_test(slapi_entry_get_sdn_const(entryBefore), p->base, p->scope)){
  2396. if(NULL == p->slapifilter || slapi_vattr_filter_test(pb, entryBefore, p->slapifilter, 0) == 0){
  2397. struct slapdplugin *plugin = p->plugin;
  2398. int plugin_started = 1;
  2399. if(plugin){
  2400. /* this is a plugin callback, update the operation counter */
  2401. slapi_plugin_op_started(plugin);
  2402. if(!plugin->plg_started){
  2403. /* must be a task function being called */
  2404. result = SLAPI_DSE_CALLBACK_ERROR;
  2405. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  2406. "Task entry (%s) could not added because the (%s) plugin is disabled.",
  2407. slapi_entry_get_dn(entryBefore), p->plugin->plg_dn);
  2408. plugin_started = 0;
  2409. }
  2410. }
  2411. if(plugin_started){
  2412. result = (*p->fn)(pb, entryBefore,entryAfter,returncode,returntext,p->fn_arg);
  2413. }
  2414. if(result < rc){
  2415. rc = result;
  2416. }
  2417. slapi_plugin_op_finished(plugin);
  2418. }
  2419. }
  2420. }
  2421. p = next;
  2422. }
  2423. }
  2424. return rc;
  2425. }
  2426. int
  2427. slapi_config_register_callback(int operation,
  2428. int flags,
  2429. const char *base,
  2430. int scope,
  2431. const char *filter,
  2432. dseCallbackFn fn,
  2433. void *fn_arg)
  2434. {
  2435. return slapi_config_register_callback_plugin(operation, flags, base, scope, filter, fn, fn_arg, NULL);
  2436. }
  2437. /*
  2438. * We pass in the pblock so we can update the operation counter for "dynamic plugins".
  2439. */
  2440. int
  2441. slapi_config_register_callback_plugin(int operation,
  2442. int flags,
  2443. const char *base,
  2444. int scope,
  2445. const char *filter,
  2446. dseCallbackFn fn,
  2447. void *fn_arg,
  2448. Slapi_PBlock *pb)
  2449. {
  2450. int rc= 0;
  2451. Slapi_Backend *be= slapi_be_select_by_instance_name(DSE_BACKEND);
  2452. if (be != NULL) {
  2453. struct dse* pdse= (struct dse*)be->be_database->plg_private;
  2454. if (pdse!=NULL) {
  2455. Slapi_DN dn;
  2456. slapi_sdn_init_dn_byref(&dn,base);
  2457. /* if a pblock was passed, this is a plugin, so set the f_arg as the plugin */
  2458. rc = (NULL != dse_register_callback(pdse, operation, flags, &dn, scope, filter, fn,
  2459. pb ? (void*)pb->pb_plugin : fn_arg,
  2460. pb ? pb->pb_plugin: NULL));
  2461. slapi_sdn_done(&dn);
  2462. }
  2463. }
  2464. return rc;
  2465. }
  2466. int
  2467. slapi_config_remove_callback(int operation, int flags, const char *base, int scope, const char *filter, dseCallbackFn fn)
  2468. {
  2469. int rc= 0;
  2470. Slapi_Backend *be= slapi_be_select_by_instance_name(DSE_BACKEND);
  2471. if(be != NULL) {
  2472. struct dse* pdse = (struct dse*)be->be_database->plg_private;
  2473. if (pdse != NULL) {
  2474. Slapi_DN dn;
  2475. slapi_sdn_init_dn_byref(&dn,base);
  2476. dse_remove_callback(pdse, operation, flags, &dn, scope, filter, fn);
  2477. slapi_sdn_done(&dn);
  2478. rc= 1;
  2479. }
  2480. }
  2481. return rc;
  2482. }
  2483. void
  2484. dse_set_dont_ever_write_dse_files()
  2485. {
  2486. dont_ever_write_dse_files = 1;
  2487. }
  2488. void
  2489. dse_unset_dont_ever_write_dse_files()
  2490. {
  2491. dont_ever_write_dse_files = 0;
  2492. }
  2493. static dse_search_set*
  2494. dse_search_set_new ()
  2495. {
  2496. dse_search_set *ss;
  2497. ss = (dse_search_set *)slapi_ch_malloc (sizeof (*ss));
  2498. if (ss)
  2499. {
  2500. dl_init (&ss->dl, 0);
  2501. ss->current_entry = -1;
  2502. }
  2503. return ss;
  2504. }
  2505. /* This is similar to delete, but it does not free the entries contained in the
  2506. search set. This is useful in do_dse_search when we copy the entries from
  2507. 1 search set to the other. */
  2508. static void
  2509. dse_search_set_clean(dse_search_set *ss)
  2510. {
  2511. if (ss)
  2512. {
  2513. dl_cleanup(&ss->dl, NULL);
  2514. slapi_ch_free((void **)&ss);
  2515. }
  2516. }
  2517. void
  2518. dse_search_set_release (void **ss)
  2519. {
  2520. dse_search_set_delete(*(dse_search_set **)ss);
  2521. }
  2522. void
  2523. dse_prev_search_results (void *vp)
  2524. {
  2525. Slapi_PBlock *pb = (Slapi_PBlock *)vp;
  2526. dse_search_set *ss;
  2527. slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &ss);
  2528. if (ss) {
  2529. dl_get_prev (&ss->dl, &ss->current_entry);
  2530. }
  2531. }
  2532. static void
  2533. dse_search_set_delete (dse_search_set *ss)
  2534. {
  2535. if (ss)
  2536. {
  2537. dl_cleanup (&ss->dl, dse_free_entry);
  2538. slapi_ch_free ((void**)&ss);
  2539. }
  2540. }
  2541. static void
  2542. dse_free_entry (void **data)
  2543. {
  2544. Slapi_Entry **e;
  2545. if (data)
  2546. {
  2547. e = (Slapi_Entry **)data;
  2548. if (*e)
  2549. slapi_entry_free (*e);
  2550. }
  2551. }
  2552. static void
  2553. dse_search_set_add_entry (dse_search_set *ss, Slapi_Entry *e)
  2554. {
  2555. PR_ASSERT (ss && e);
  2556. dl_add (&ss->dl, e);
  2557. }
  2558. static Slapi_Entry*
  2559. dse_search_set_get_next_entry (dse_search_set *ss)
  2560. {
  2561. PR_ASSERT (ss);
  2562. if (ss->current_entry == -1)
  2563. return (dl_get_first (&ss->dl, &ss->current_entry));
  2564. else
  2565. return (dl_get_next (&ss->dl, &ss->current_entry));
  2566. }
  2567. int
  2568. dse_next_search_entry (Slapi_PBlock *pb)
  2569. {
  2570. dse_search_set *ss;
  2571. Slapi_Entry *e;
  2572. slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &ss);
  2573. /* no entries to return */
  2574. if (ss == NULL)
  2575. {
  2576. slapi_pblock_set (pb, SLAPI_SEARCH_RESULT_ENTRY, NULL);
  2577. return 0;
  2578. }
  2579. e = dse_search_set_get_next_entry (ss);
  2580. slapi_pblock_set (pb, SLAPI_SEARCH_RESULT_ENTRY, e);
  2581. /* we reached the end of the list */
  2582. if (e == NULL)
  2583. {
  2584. pagedresults_set_search_result_pb(pb, NULL, 0);
  2585. dse_search_set_delete (ss);
  2586. slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET, NULL);
  2587. }
  2588. return 0;
  2589. }