]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldif/ldif.c
fix *entry_get() behavior
[openldap] / servers / slapd / back-ldif / ldif.c
1 /* ldif.c - the ldif backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2005-2006 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was originally developed by Eric Stokes for inclusion
18  * in OpenLDAP Software.
19  */
20
21 #include "portable.h"
22 #include <stdio.h>
23 #include <ac/string.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <ac/dirent.h>
27 #include <fcntl.h>
28 #include <ac/errno.h>
29 #include <ac/unistd.h>
30 #include "slap.h"
31 #include "lutil.h"
32 #include "config.h"
33
34 typedef struct enumCookie {
35         Operation *op;
36         SlapReply *rs;
37         Entry **entries;
38         int elen;
39         int eind;
40 } enumCookie;
41
42 struct ldif_info {
43         struct berval li_base_path;
44         enumCookie li_tool_cookie;
45         ID li_tool_current;
46         ldap_pvt_thread_mutex_t  li_mutex;
47 };
48
49 #ifdef _WIN32
50 #define mkdir(a,b)      mkdir(a)
51 #endif
52
53 #define LDIF    ".ldif"
54
55 #define IX_DNL  '{'
56 #define IX_DNR  '}'
57 #ifndef IX_FSL
58 #define IX_FSL  IX_DNL
59 #define IX_FSR  IX_DNR
60 #endif
61
62 #define ENTRY_BUFF_INCREMENT 500
63
64 static ConfigTable ldifcfg[] = {
65         { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
66                 (void *)offsetof(struct ldif_info, li_base_path),
67                 "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
68                         "DESC 'Directory for database content' "
69                         "EQUALITY caseIgnoreMatch "
70                         "SYNTAX OMsDirectoryString )", NULL, NULL },
71         { NULL, NULL, 0, 0, 0, ARG_IGNORED,
72                 NULL, NULL, NULL, NULL }
73 };
74
75 static ConfigOCs ldifocs[] = {
76         { "( OLcfgDbOc:2.1 "
77                 "NAME 'olcLdifConfig' "
78                 "DESC 'LDIF backend configuration' "
79                 "SUP olcDatabaseConfig "
80                 "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg },
81         { NULL, 0, NULL }
82 };
83
84 static void
85 dn2path(struct berval * dn, struct berval * suffixdn, struct berval * base_path,
86         struct berval *res)
87 {
88         char *ptr, *sep, *end;
89
90         assert( dn != NULL );
91         assert( !BER_BVISNULL( dn ) );
92         assert( suffixdn != NULL );
93         assert( !BER_BVISNULL( suffixdn ) );
94         assert( dnIsSuffix( dn, suffixdn ) );
95
96         res->bv_len = dn->bv_len + base_path->bv_len + 1 + STRLENOF( LDIF );
97         res->bv_val = ch_malloc( res->bv_len + 1 );
98         ptr = lutil_strcopy( res->bv_val, base_path->bv_val );
99         *ptr++ = LDAP_DIRSEP[0];
100         ptr = lutil_strcopy( ptr, suffixdn->bv_val );
101         end = dn->bv_val + dn->bv_len - suffixdn->bv_len - 1;
102         while ( end > dn->bv_val ) {
103                 for (sep = end-1; sep >=dn->bv_val && !DN_SEPARATOR( *sep ); sep--);
104                 *ptr++ = LDAP_DIRSEP[0];
105                 ptr = lutil_strncopy( ptr, sep+1, end-sep-1 );
106                 end = sep;
107         }
108         strcpy(ptr, LDIF);
109 #if IX_FSL != IX_DNL
110         ptr = res->bv_val;
111         while( ptr=strchr(ptr, IX_DNL) ) {
112                 *ptr++ = IX_FSL;
113                 ptr = strchr(ptr, IX_DNR);
114                 if ( ptr )
115                         *ptr++ = IX_FSR;
116                 else
117                         break;
118         }
119 #endif
120 }
121
122 static char * slurp_file(int fd) {
123         int read_chars_total = 0;
124         int read_chars = 0;
125         int entry_size;
126         char * entry;
127         char * entry_pos;
128         struct stat st;
129
130         fstat(fd, &st);
131         entry_size = st.st_size;
132         entry = ch_malloc( entry_size+1 );
133         entry_pos = entry;
134         
135         while(1) {
136                 read_chars = read(fd, (void *) entry_pos, entry_size - read_chars_total);
137                 if(read_chars == -1) {
138                         SLAP_FREE(entry);
139                         return NULL;
140                 }
141                 if(read_chars == 0) {
142                         entry[read_chars_total] = '\0';
143                         break;
144                 }
145                 else {
146                         read_chars_total += read_chars;
147                         entry_pos += read_chars;
148                 }
149         }
150         return entry;
151 }
152
153 static int spew_file(int fd, char * spew, int len) {
154         int writeres = 0;
155         
156         while(len > 0) {
157                 writeres = write(fd, spew, len);
158                 if(writeres == -1) {
159                         Debug( LDAP_DEBUG_ANY, "could not spew write: %s\n",
160                                 strerror( errno ), 0, 0 );
161                         return -1;
162                 }
163                 else {
164                         spew += writeres;
165                         len -= writeres;
166                 }
167         }
168         return writeres;
169 }
170
171 static int spew_entry(Entry * e, struct berval * path) {
172         int rs;
173         int openres;
174         int spew_res;
175         int entry_length;
176         char * entry_as_string;
177
178         openres = open(path->bv_val, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR);
179         if(openres == -1) {
180                 if(errno == ENOENT)
181                         rs = LDAP_NO_SUCH_OBJECT;
182                 else
183                         rs = LDAP_UNWILLING_TO_PERFORM;
184                 Debug( LDAP_DEBUG_ANY, "could not open \"%s\": %s\n",
185                         path->bv_val, strerror( errno ), 0 );
186         }
187         else {
188                 struct berval rdn;
189                 int tmp;
190
191                 /* Only save the RDN onto disk */
192                 dnRdn( &e->e_name, &rdn );
193                 if ( rdn.bv_len != e->e_name.bv_len ) {
194                         e->e_name.bv_val[rdn.bv_len] = '\0';
195                         tmp = e->e_name.bv_len;
196                         e->e_name.bv_len = rdn.bv_len;
197                         rdn.bv_len = tmp;
198                 }
199
200                 entry_as_string = entry2str(e, &entry_length);
201
202                 /* Restore full DN */
203                 if ( rdn.bv_len != e->e_name.bv_len ) {
204                         e->e_name.bv_val[e->e_name.bv_len] = ',';
205                         e->e_name.bv_len = rdn.bv_len;
206                 }
207
208                 if(entry_as_string == NULL) {
209                         rs = LDAP_UNWILLING_TO_PERFORM;
210                         close(openres);
211                 }
212                 else {
213                         spew_res = spew_file(openres, entry_as_string, entry_length);
214                         close(openres);
215                         if(spew_res == -1)
216                                 rs = LDAP_UNWILLING_TO_PERFORM;
217                         else
218                                 rs = LDAP_SUCCESS;
219                 }
220         }
221         return rs;
222 }
223
224 static Entry * get_entry_for_fd(int fd,
225         struct berval *pdn,
226         struct berval *pndn)
227 {
228         char * entry = (char *) slurp_file(fd);
229         Entry * ldentry = NULL;
230         
231         /* error reading file */
232         if(entry == NULL) {
233                 goto return_value;
234         }
235
236         ldentry = str2entry(entry);
237         if ( ldentry ) {
238                 struct berval rdn;
239                 rdn = ldentry->e_name;
240                 build_new_dn( &ldentry->e_name, pdn, &rdn, NULL );
241                 ch_free( rdn.bv_val );
242                 rdn = ldentry->e_nname;
243                 build_new_dn( &ldentry->e_nname, pndn, &rdn, NULL );
244                 ch_free( rdn.bv_val );
245         }
246
247  return_value:
248         if(fd != -1) {
249                 if(close(fd) != 0) {
250                         /* log error */
251                 }
252         }
253         if(entry != NULL)
254                 SLAP_FREE(entry);
255         return ldentry;
256 }
257
258 static Entry * get_entry(Operation *op, struct berval *base_path) {
259         struct berval path, pdn, pndn;
260         int fd;
261
262         dnParent(&op->o_req_dn, &pdn);
263         dnParent(&op->o_req_ndn, &pndn);
264         dn2path(&op->o_req_ndn, op->o_bd->be_nsuffix, base_path, &path);
265         fd = open(path.bv_val, O_RDONLY);
266         /* error opening file (mebbe should log error) */
267         if(fd == -1) {
268                 Debug(LDAP_DEBUG_ANY, "failed to open file \"%s\": %s\n",
269                         path.bv_val, strerror(errno), 0 );
270         }
271
272         if(path.bv_val != NULL)
273                 SLAP_FREE(path.bv_val);
274
275         if ( fd != -1 ) {
276                 return get_entry_for_fd(fd, &pdn, &pndn);
277         }
278
279         return NULL;
280 }
281
282 static void fullpath(struct berval *base, struct berval *name, struct berval *res) {
283         char *ptr;
284         res->bv_len = name->bv_len + base->bv_len + 1;
285         res->bv_val = ch_malloc( res->bv_len + 1 );
286         strcpy(res->bv_val, base->bv_val);
287         ptr = res->bv_val + base->bv_len;
288         *ptr++ = LDAP_DIRSEP[0];
289         strcpy(ptr, name->bv_val);
290 }
291
292 typedef struct bvlist {
293         struct bvlist *next;
294         struct berval bv;
295         struct berval num;
296         unsigned int inum;
297         int off;
298 } bvlist;
299
300
301 static int r_enum_tree(enumCookie *ck, struct berval *path,
302         struct berval *pdn, struct berval *pndn)
303 {
304         Entry *e;
305         int fd, rc = LDAP_SUCCESS;
306
307         fd = open( path->bv_val, O_RDONLY );
308         if ( fd < 0 ) {
309                 Debug( LDAP_DEBUG_ANY,
310                         "=> ldif_enum_tree: failed to open %s: %s\n",
311                         path->bv_val, strerror(errno), 0 );
312                 return LDAP_NO_SUCH_OBJECT;
313         }
314
315         e = get_entry_for_fd(fd, pdn, pndn);
316         if ( !e ) {
317                 Debug( LDAP_DEBUG_ANY,
318                         "=> ldif_enum_tree: failed to read entry for %s\n",
319                         path->bv_val, 0, 0 );
320                 return LDAP_BUSY;
321         }
322
323         if ( ck->op->ors_scope == LDAP_SCOPE_BASE ||
324                 ck->op->ors_scope == LDAP_SCOPE_SUBTREE ) {
325                 /* Send right away? */
326                 if ( ck->rs ) {
327                         /*
328                          * if it's a referral, add it to the list of referrals. only do
329                          * this for non-base searches, and don't check the filter
330                          * explicitly here since it's only a candidate anyway.
331                          */
332                         if ( !get_manageDSAit( ck->op )
333                                         && ck->op->ors_scope != LDAP_SCOPE_BASE
334                                         && is_entry_referral( e ) )
335                         {
336                                 BerVarray erefs = get_entry_referrals( ck->op, e );
337                                 ck->rs->sr_ref = referral_rewrite( erefs,
338                                                 &e->e_name, NULL,
339                                                 ck->op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL
340                                                         ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );
341
342                                 ck->rs->sr_entry = e;
343                                 rc = send_search_reference( ck->op, ck->rs );
344                                 ber_bvarray_free( ck->rs->sr_ref );
345                                 ber_bvarray_free( erefs );
346                                 ck->rs->sr_ref = NULL;
347                                 ck->rs->sr_entry = NULL;
348
349                         } else if ( test_filter( ck->op, e, ck->op->ors_filter ) == LDAP_COMPARE_TRUE )
350                         {
351                                 ck->rs->sr_entry = e;
352                                 ck->rs->sr_attrs = ck->op->ors_attrs;
353                                 ck->rs->sr_flags = REP_ENTRY_MODIFIABLE;
354                                 rc = send_search_entry(ck->op, ck->rs);
355                                 ck->rs->sr_entry = NULL;
356                         }
357                         fd = 1;
358                         if ( rc )
359                                 goto done;
360                 } else {
361                 /* Queueing up for tool mode */
362                         if(ck->entries == NULL) {
363                                 ck->entries = (Entry **) ch_malloc(sizeof(Entry *) * ENTRY_BUFF_INCREMENT);
364                                 ck->elen = ENTRY_BUFF_INCREMENT;
365                         }
366                         if(ck->eind >= ck->elen) { /* grow entries if necessary */      
367                                 ck->entries = (Entry **) ch_realloc(ck->entries, sizeof(Entry *) * (ck->elen) * 2);
368                                 ck->elen *= 2;
369                         }
370
371                         ck->entries[ck->eind++] = e;
372                         fd = 0;
373                 }
374         } else {
375                 fd = 1;
376         }
377
378         if ( ck->op->ors_scope != LDAP_SCOPE_BASE ) {
379                 DIR * dir_of_path;
380                 bvlist *list = NULL, *ptr;
381
382                 path->bv_len -= STRLENOF( LDIF );
383                 path->bv_val[path->bv_len] = '\0';
384
385                 dir_of_path = opendir(path->bv_val);
386                 if(dir_of_path == NULL) { /* can't open directory */
387                         if ( errno != ENOENT ) {
388                                 /* it shouldn't be treated as an error
389                                  * only if the directory doesn't exist */
390                                 rc = LDAP_BUSY;
391                                 Debug( LDAP_DEBUG_ANY,
392                                         "=> ldif_enum_tree: failed to opendir %s (%d)\n",
393                                         path->bv_val, errno, 0 );
394                         }
395                         goto done;
396                 }
397         
398                 while(1) {
399                         struct berval fname, itmp;
400                         struct dirent * dir;
401                         bvlist *bvl, **prev;
402
403                         dir = readdir(dir_of_path);
404                         if(dir == NULL) break; /* end of the directory */
405                         fname.bv_len = strlen( dir->d_name );
406                         if ( fname.bv_len <= STRLENOF( LDIF ))
407                                 continue;
408                         if ( strcmp( dir->d_name + (fname.bv_len - STRLENOF(LDIF)), LDIF))
409                                 continue;
410                         fname.bv_val = dir->d_name;
411
412                         bvl = ch_malloc( sizeof(bvlist) );
413                         ber_dupbv( &bvl->bv, &fname );
414                         BER_BVZERO( &bvl->num );
415                         itmp.bv_val = strchr( bvl->bv.bv_val, IX_FSL );
416                         if ( itmp.bv_val ) {
417                                 char *ptr;
418                                 itmp.bv_val++;
419                                 ptr = strchr( itmp.bv_val, IX_FSR );
420                                 if ( ptr ) {
421                                         itmp.bv_len = ptr - itmp.bv_val;
422                                         ber_dupbv( &bvl->num, &itmp );
423                                         bvl->inum = strtoul( itmp.bv_val, NULL, 0 );
424                                         itmp.bv_val[0] = '\0';
425                                         bvl->off = itmp.bv_val - bvl->bv.bv_val;
426                                 }
427                         }
428
429                         for (prev = &list; (ptr = *prev) != NULL; prev = &ptr->next) {
430                                 int cmp = strcmp( bvl->bv.bv_val, ptr->bv.bv_val );
431                                 if ( !cmp && bvl->num.bv_val )
432                                         cmp = bvl->inum - ptr->inum;
433                                 if ( cmp < 0 )
434                                         break;
435                         }
436                         *prev = bvl;
437                         bvl->next = ptr;
438                                 
439                 }
440                 closedir(dir_of_path);
441
442                 if (ck->op->ors_scope == LDAP_SCOPE_ONELEVEL)
443                         ck->op->ors_scope = LDAP_SCOPE_BASE;
444                 else if ( ck->op->ors_scope == LDAP_SCOPE_SUBORDINATE)
445                         ck->op->ors_scope = LDAP_SCOPE_SUBTREE;
446
447                 while ( ( ptr = list ) ) {
448                         struct berval fpath;
449
450                         list = ptr->next;
451
452                         if ( rc == LDAP_SUCCESS ) {
453                                 if ( ptr->num.bv_val )
454                                         AC_MEMCPY( ptr->bv.bv_val + ptr->off, ptr->num.bv_val,
455                                                 ptr->num.bv_len );
456                                 fullpath( path, &ptr->bv, &fpath );
457                                 rc = r_enum_tree(ck, &fpath, &e->e_name, &e->e_nname );
458                                 free(fpath.bv_val);
459                         }
460                         if ( ptr->num.bv_val )
461                                 free( ptr->num.bv_val );
462                         free(ptr->bv.bv_val);
463                         free(ptr);
464                 }
465         }
466 done:
467         if ( fd ) entry_free( e );
468         return rc;
469 }
470
471 static int
472 enum_tree(
473         enumCookie *ck
474 )
475 {
476         struct ldif_info *ni = (struct ldif_info *) ck->op->o_bd->be_private;
477         struct berval path;
478         struct berval pdn, pndn;
479         int rc;
480
481         dnParent( &ck->op->o_req_dn, &pdn );
482         dnParent( &ck->op->o_req_ndn, &pndn );
483         dn2path( &ck->op->o_req_ndn, &ck->op->o_bd->be_nsuffix[0], &ni->li_base_path, &path);
484         rc = r_enum_tree(ck, &path, &pdn, &pndn);
485         ch_free( path.bv_val );
486         return rc;
487 }
488
489 /* Get the parent path plus the LDIF suffix */
490 static void get_parent_path(struct berval * dnpath, struct berval *res) {
491         int dnpathlen = dnpath->bv_len;
492         int i;
493         
494         for(i = dnpathlen;i>0;i--) /* find the first path seperator */
495                 if(dnpath->bv_val[i] == LDAP_DIRSEP[0])
496                         break;
497         res->bv_len = i;
498         res->bv_val = ch_malloc( res->bv_len + 1 + STRLENOF(LDIF) );
499         strncpy(res->bv_val, dnpath->bv_val, i);
500         strcpy(res->bv_val+i, LDIF);
501         res->bv_val[i] = '\0';
502 }
503
504 static int apply_modify_to_entry(Entry * entry,
505                                 Modifications * modlist,
506                                 Operation * op,
507                                 SlapReply * rs)
508 {
509         char textbuf[SLAP_TEXT_BUFLEN];
510         int rc = LDAP_UNWILLING_TO_PERFORM;
511         Modification *mods = NULL;
512
513         if (!acl_check_modlist(op, entry, modlist)) {
514                 return LDAP_INSUFFICIENT_ACCESS;
515         }
516
517         for (; modlist != NULL; modlist = modlist->sml_next) {
518                 mods = &modlist->sml_mod;
519
520                 switch (mods->sm_op) {
521                 case LDAP_MOD_ADD:
522                         rc = modify_add_values(entry, mods,
523                                    get_permissiveModify(op),
524                                    &rs->sr_text, textbuf,
525                                    sizeof( textbuf ) );
526                         break;
527                                 
528                 case LDAP_MOD_DELETE:
529                         rc = modify_delete_values(entry, mods,
530                                 get_permissiveModify(op),
531                                 &rs->sr_text, textbuf,
532                                 sizeof( textbuf ) );
533                         break;
534                                 
535                 case LDAP_MOD_REPLACE:
536                         rc = modify_replace_values(entry, mods,
537                                  get_permissiveModify(op),
538                                  &rs->sr_text, textbuf,
539                                  sizeof( textbuf ) );
540                         break;
541
542                 case LDAP_MOD_INCREMENT:
543                         rc = modify_increment_values( entry,
544                                 mods, get_permissiveModify(op),
545                                 &rs->sr_text, textbuf,
546                                 sizeof( textbuf ) );
547                         break;
548
549                         break;
550
551                 case SLAP_MOD_SOFTADD:
552                         mods->sm_op = LDAP_MOD_ADD;
553                         rc = modify_add_values(entry, mods,
554                                    get_permissiveModify(op),
555                                    &rs->sr_text, textbuf,
556                                    sizeof( textbuf ) );
557                         mods->sm_op = SLAP_MOD_SOFTADD;
558                         if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
559                                 rc = LDAP_SUCCESS;
560                         }
561                         break;
562                 default:
563                         break;
564                 }
565                 if(rc != LDAP_SUCCESS) break;
566         }
567         
568         if(rc == LDAP_SUCCESS) {
569                 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
570                         entry->e_ocflags = 0;
571                 }
572                 /* check that the entry still obeys the schema */
573                 rc = entry_schema_check(op, entry, NULL, 0,
574                           &rs->sr_text, textbuf, sizeof( textbuf ) );
575         }
576         return rc;
577 }
578
579 int
580 ldif_back_referrals( Operation *op, SlapReply *rs )
581 {
582         struct ldif_info        *ni = NULL;
583         Entry                   *entry;
584         int                     rc = LDAP_SUCCESS;
585
586 #if 0
587         if ( op->o_tag == LDAP_REQ_SEARCH ) {
588                 /* let search take care of itself */
589                 return rc;
590         }
591 #endif
592
593         if ( get_manageDSAit( op ) ) {
594                 /* let op take care of DSA management */
595                 return rc;
596         }
597
598         ni = (struct ldif_info *)op->o_bd->be_private;
599         ldap_pvt_thread_mutex_lock( &ni->li_mutex );
600         entry = (Entry *)get_entry( op, &ni->li_base_path );
601
602         /* no object is found for them */
603         if ( entry == NULL ) {
604                 struct berval   odn = op->o_req_dn;
605                 struct berval   ondn = op->o_req_ndn;
606
607                 struct berval   pndn = op->o_req_ndn;
608
609                 for ( ; entry == NULL; ) {
610                         dnParent( &pndn, &pndn );
611                         
612                         if ( !dnIsSuffix( &pndn, &op->o_bd->be_nsuffix[0] ) ) {
613                                 break;
614                         }
615
616                         op->o_req_dn = pndn;
617                         op->o_req_ndn = pndn;
618
619                         entry = (Entry *)get_entry( op, &ni->li_base_path );
620                 }
621
622                 ldap_pvt_thread_mutex_unlock( &ni->li_mutex );
623
624                 op->o_req_dn = odn;
625                 op->o_req_ndn = ondn;
626
627                 rc = LDAP_SUCCESS;
628                 rs->sr_matched = NULL;
629                 if ( entry != NULL ) {
630                         Debug( LDAP_DEBUG_TRACE,
631                                 "ldif_back_referrals: op=%ld target=\"%s\" matched=\"%s\"\n",
632                                 (long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val );
633
634                         if ( is_entry_referral( entry ) ) {
635                                 rc = LDAP_OTHER;
636                                 rs->sr_ref = get_entry_referrals( op, entry );
637                                 if ( rs->sr_ref ) {
638                                         rs->sr_matched = ber_strdup_x(
639                                         entry->e_name.bv_val, op->o_tmpmemctx );
640                                 }
641                         }
642
643                         entry_free(entry);
644
645                 } else if ( default_referral != NULL ) {
646                         rc = LDAP_OTHER;
647                         rs->sr_ref = referral_rewrite( default_referral,
648                                 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
649                 }
650
651                 if ( rs->sr_ref != NULL ) {
652                         /* send referrals */
653                         rc = rs->sr_err = LDAP_REFERRAL;
654                         send_ldap_result( op, rs );
655                         ber_bvarray_free( rs->sr_ref );
656                         rs->sr_ref = NULL;
657
658                 } else if ( rc != LDAP_SUCCESS ) {
659                         rs->sr_err = rc;
660                         rs->sr_text = rs->sr_matched ? "bad referral object" : NULL;
661                         send_ldap_result( op, rs );
662                 }
663
664                 if ( rs->sr_matched ) {
665                         op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
666                         rs->sr_matched = NULL;
667                 }
668
669                 return rc;
670         }
671
672         ldap_pvt_thread_mutex_unlock( &ni->li_mutex );
673
674         if ( is_entry_referral( entry ) ) {
675                 /* entry is a referral */
676                 BerVarray refs = get_entry_referrals( op, entry );
677                 rs->sr_ref = referral_rewrite(
678                         refs, &entry->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
679
680                 Debug( LDAP_DEBUG_TRACE,
681                         "ldif_back_referrals: op=%ld target=\"%s\" matched=\"%s\"\n",
682                         (long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val );
683
684                 rs->sr_matched = entry->e_name.bv_val;
685                 if ( rs->sr_ref != NULL ) {
686                         rc = rs->sr_err = LDAP_REFERRAL;
687                         send_ldap_result( op, rs );
688                         ber_bvarray_free( rs->sr_ref );
689                         rs->sr_ref = NULL;
690
691                 } else {
692                         send_ldap_error( op, rs, LDAP_OTHER, "bad referral object" );
693                         rc = rs->sr_err;
694                 }
695
696                 rs->sr_matched = NULL;
697                 ber_bvarray_free( refs );
698         }
699
700         entry_free( entry );
701
702         return rc;
703 }
704
705 static int
706 ldif_back_bind( Operation *op, SlapReply *rs )
707 {
708         struct ldif_info *ni = NULL;
709         Attribute * a = NULL;
710         AttributeDescription *password = slap_schema.si_ad_userPassword;
711         int return_val = 0;
712         Entry * entry = NULL;
713
714         ni = (struct ldif_info *) op->o_bd->be_private;
715         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
716         entry = (Entry *) get_entry(op, &ni->li_base_path);
717
718         /* no object is found for them */
719         if(entry == NULL) {
720                 if(be_isroot_pw(op)) {
721                         rs->sr_err = return_val = LDAP_SUCCESS;
722                 } else {
723                         rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
724                 }
725                 goto return_result;
726         }
727
728         /* they don't have userpassword */
729         if((a = attr_find(entry->e_attrs, password)) == NULL) {
730                 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
731                 return_val = 1;
732                 goto return_result;
733         }
734
735         /* authentication actually failed */
736         if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
737                              &rs->sr_text) != 0) {
738                 rs->sr_err = LDAP_INVALID_CREDENTIALS;
739                 return_val = 1;
740                 goto return_result;
741         }
742
743         /* let the front-end send success */
744         return_val = 0;
745         goto return_result;
746
747  return_result:
748         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
749         if(return_val != 0)
750                 send_ldap_result( op, rs );
751         if(entry != NULL)
752                 entry_free(entry);
753         return return_val;
754 }
755
756 static int ldif_back_search(Operation *op, SlapReply *rs)
757 {
758         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
759         enumCookie ck = { NULL, NULL, NULL, 0, 0 };
760
761         ck.op = op;
762         ck.rs = rs;
763         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
764         rs->sr_err = enum_tree( &ck );
765         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
766         send_ldap_result(op, rs);
767
768         return rs->sr_err;
769 }
770
771 static int ldif_back_add(Operation *op, SlapReply *rs) {
772         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
773         Entry * e = op->ora_e;
774         struct berval dn = e->e_nname;
775         struct berval leaf_path = BER_BVNULL;
776         struct stat stats;
777         int statres;
778         char textbuf[SLAP_TEXT_BUFLEN];
779
780         Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", dn.bv_val, 0, 0);
781         slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
782
783         rs->sr_err = entry_schema_check(op, e, NULL, 0,
784                 &rs->sr_text, textbuf, sizeof( textbuf ) );
785         if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
786                                 
787         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
788
789         dn2path(&dn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &leaf_path);
790
791         if(leaf_path.bv_val != NULL) {
792                 struct berval base = BER_BVNULL;
793                 /* build path to container and ldif of container */
794                 get_parent_path(&leaf_path, &base);
795
796                 statres = stat(base.bv_val, &stats); /* check if container exists */
797                 if(statres == -1 && errno == ENOENT) { /* container missing */
798                         base.bv_val[base.bv_len] = '.';
799                         statres = stat(base.bv_val, &stats); /* check for leaf node */
800                         base.bv_val[base.bv_len] = '\0';
801                         if(statres == -1 && errno == ENOENT) {
802                                 rs->sr_err = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
803                                 rs->sr_text = "Parent does not exist";
804                         }
805                         else if(statres != -1) { /* create parent */
806                                 int mkdirres = mkdir(base.bv_val, 0750);
807                                 if(mkdirres == -1) {
808                                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
809                                         rs->sr_text = "Could not create parent folder";
810                                         Debug( LDAP_DEBUG_ANY, "could not create folder \"%s\": %s\n",
811                                                 base.bv_val, strerror( errno ), 0 );
812                                 }
813                         }
814                         else
815                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
816                 }/* container was possibly created, move on to add the entry */
817                 if(rs->sr_err == LDAP_SUCCESS) {
818                         statres = stat(leaf_path.bv_val, &stats);
819                         if(statres == -1 && errno == ENOENT) {
820                                 ldap_pvt_thread_mutex_lock(&entry2str_mutex);
821                                 rs->sr_err = (int) spew_entry(e, &leaf_path);
822                                 ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
823                         }
824                         else if ( statres == -1 ) {
825                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
826                                 Debug( LDAP_DEBUG_ANY, "could not stat file \"%s\": %s\n",
827                                         leaf_path.bv_val, strerror( errno ), 0 );
828                         }
829                         else /* it already exists */
830                                 rs->sr_err = LDAP_ALREADY_EXISTS;
831                 }
832                 SLAP_FREE(base.bv_val);
833                 SLAP_FREE(leaf_path.bv_val);
834         }
835
836         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
837
838 send_res:
839         Debug( LDAP_DEBUG_TRACE, 
840                         "ldif_back_add: err: %d text: %s\n", rs->sr_err, rs->sr_text, 0);
841         send_ldap_result(op, rs);
842         slap_graduate_commit_csn( op );
843         return 0;
844 }
845
846 static int ldif_back_modify(Operation *op, SlapReply *rs) {
847         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
848         Modifications * modlst = op->orm_modlist;
849         struct berval path = BER_BVNULL;
850         Entry * entry = NULL;
851         int spew_res;
852
853         slap_mods_opattrs( op, &op->orm_modlist, 1 );
854
855         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
856         dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path,
857                 &path);
858         entry = (Entry *) get_entry(op, &ni->li_base_path);
859
860         if(entry != NULL) {
861                 rs->sr_err = apply_modify_to_entry(entry, modlst, op, rs);
862                 if(rs->sr_err == LDAP_SUCCESS) {
863                         int save_errno;
864                         ldap_pvt_thread_mutex_lock(&entry2str_mutex);
865                         spew_res = spew_entry(entry, &path);
866                         save_errno = errno;
867                         ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
868                         if(spew_res == -1) {
869                                 Debug( LDAP_DEBUG_ANY,
870                                         "%s ldif_back_modify: could not output entry \"%s\": %s\n",
871                                         op->o_log_prefix, entry->e_name.bv_val, strerror( save_errno ) );
872                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
873                         }
874                 }
875         }
876         else {
877                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
878         }
879         
880         if(entry != NULL)
881                 entry_free(entry);
882         if(path.bv_val != NULL)
883                 SLAP_FREE(path.bv_val);
884         rs->sr_text = NULL;
885         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
886         send_ldap_result(op, rs);
887         slap_graduate_commit_csn( op );
888         return 0;
889 }
890
891 static int ldif_back_delete(Operation *op, SlapReply *rs) {
892         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
893         struct berval path = BER_BVNULL;
894         int res = 0;
895
896         if ( BER_BVISEMPTY( &op->o_csn )) {
897                 struct berval csn;
898                 char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
899
900                 csn.bv_val = csnbuf;
901                 csn.bv_len = sizeof( csnbuf );
902                 slap_get_csn( op, &csn, 1 );
903         }
904
905         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
906         dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &path);
907
908         path.bv_val[path.bv_len - STRLENOF(LDIF)] = '\0';
909         res = rmdir(path.bv_val);
910         path.bv_val[path.bv_len - STRLENOF(LDIF)] = '.';
911         if ( res && errno != ENOENT ) {
912                 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
913         } else {
914                 res = unlink(path.bv_val);
915         }
916
917         if(res == -1) {
918                 if(errno == ENOENT)
919                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
920                 else
921                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
922         }
923         else
924                 rs->sr_err = LDAP_SUCCESS;
925
926         SLAP_FREE(path.bv_val);
927         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
928         send_ldap_result(op, rs);
929         slap_graduate_commit_csn( op );
930         return 0;
931 }
932
933
934 static int move_entry(Entry * entry, struct berval * ndn,
935                            struct berval * newndn, struct berval * suffixdn,
936                            struct berval * base_path) {
937         int res;
938         int exists_res;
939         struct berval path;
940         struct berval newpath;
941
942         dn2path(ndn, suffixdn, base_path, &path);
943         dn2path(newndn, suffixdn, base_path, &newpath);
944
945         if((entry == NULL || path.bv_val == NULL) || newpath.bv_val == NULL) {
946                 /* some object doesn't exist */
947                 res = LDAP_NO_SUCH_OBJECT;
948         }
949         else { /* do the modrdn */
950                 exists_res = open(newpath.bv_val, O_RDONLY);
951                 if(exists_res == -1 && errno == ENOENT) {
952                         res = spew_entry(entry, &newpath);
953                         if(res != -1) {
954                                 /* if this fails we should log something bad */
955                                 res = unlink(path.bv_val);
956                                 res = LDAP_SUCCESS;
957                         }
958                         else {
959                                 if(errno == ENOENT)
960                                         res = LDAP_NO_SUCH_OBJECT;
961                                 else
962                                         res = LDAP_UNWILLING_TO_PERFORM;
963                                 unlink(newpath.bv_val); /* in case file was created */
964                         }
965                 }
966                 else if(exists_res) {
967                         int close_res = close(exists_res);
968                         res = LDAP_ALREADY_EXISTS;
969                         if(close_res == -1) {
970                         /* log heinous error */
971                         }
972                 }
973                 else {
974                         res = LDAP_UNWILLING_TO_PERFORM;
975                 }
976         }
977
978         if(newpath.bv_val != NULL)
979                 SLAP_FREE(newpath.bv_val);
980         if(path.bv_val != NULL)
981                 SLAP_FREE(path.bv_val);
982         return res;
983 }
984
985 static int
986 ldif_back_modrdn(Operation *op, SlapReply *rs)
987 {
988         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
989         struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
990         struct berval p_dn;
991         Entry * entry = NULL;
992         int res;
993
994         slap_mods_opattrs( op, &op->orr_modlist, 1 );
995
996         ldap_pvt_thread_mutex_lock( &ni->li_mutex );
997         ldap_pvt_thread_mutex_lock( &entry2str_mutex );
998         entry = (Entry *) get_entry( op, &ni->li_base_path );
999
1000         /* build the mods to the entry */
1001         if ( entry != NULL ) {
1002                 /* build new dn, and new ndn for the entry */
1003                 if ( op->oq_modrdn.rs_newSup != NULL ) {
1004                         /* new superior */
1005                         p_dn = *op->oq_modrdn.rs_newSup;
1006                 } else {
1007                         p_dn = slap_empty_bv;
1008                 }
1009                 dnParent( &entry->e_name, &p_dn );
1010                 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL ); 
1011                 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1012                 ber_memfree_x( entry->e_name.bv_val, NULL );
1013                 ber_memfree_x( entry->e_nname.bv_val, NULL );
1014                 entry->e_name = new_dn;
1015                 entry->e_nname = new_ndn;
1016
1017                 /* perform the modifications */
1018                 res = apply_modify_to_entry( entry, op->orr_modlist, op, rs );
1019                 if ( res == LDAP_SUCCESS ) {
1020                         rs->sr_err = move_entry( entry, &op->o_req_ndn,
1021                                                 &new_ndn,
1022                                                 &op->o_bd->be_nsuffix[0],
1023                                                 &ni->li_base_path );
1024                 } else {
1025                         rs->sr_err = res;
1026                 }
1027         } else {
1028                 /* entry was null */
1029                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1030         }
1031
1032         if ( entry != NULL ) {
1033                 entry_free( entry );
1034         }
1035         rs->sr_text = "";
1036         ldap_pvt_thread_mutex_unlock( &ni->li_mutex );
1037         ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
1038         send_ldap_result( op, rs );
1039         slap_graduate_commit_csn( op );
1040         return 0;
1041 }
1042
1043 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
1044  */
1045 int ldif_back_entry_get(
1046         Operation *op,
1047         struct berval *ndn,
1048         ObjectClass *oc,
1049         AttributeDescription *at,
1050         int rw,
1051         Entry **ent )
1052 {
1053         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
1054         struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1055
1056         assert( ndn != NULL );
1057         assert( !BER_BVISNULL( ndn ) );
1058
1059         ldap_pvt_thread_mutex_lock( &ni->li_mutex );
1060         op->o_req_dn = *ndn;
1061         op->o_req_ndn = *ndn;
1062         *ent = (Entry *) get_entry( op, &ni->li_base_path );
1063         op->o_req_dn = op_dn;
1064         op->o_req_ndn = op_ndn;
1065         ldap_pvt_thread_mutex_unlock( &ni->li_mutex );
1066
1067         if ( *ent && oc && !is_entry_objectclass_or_sub( *ent, oc ) ) {
1068                 entry_free( *ent );
1069                 *ent = NULL;
1070         }
1071
1072         return ( *ent == NULL ? 1 : 0 );
1073 }
1074
1075 static int ldif_tool_entry_open(BackendDB * be, int mode) {
1076         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1077         ni->li_tool_current = 0;
1078         return 0;
1079 }                                       
1080
1081 static int ldif_tool_entry_close(BackendDB * be) {
1082         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1083
1084         SLAP_FREE(ni->li_tool_cookie.entries);
1085         return 0;
1086 }
1087
1088 static ID
1089 ldif_tool_entry_first(BackendDB *be)
1090 {
1091         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1092         ID id = 1; /* first entry in the array of entries shifted by one */
1093
1094         ni->li_tool_current = 1;
1095         if(ni->li_tool_cookie.entries == NULL) {
1096                 Operation op = {0};
1097
1098                 op.o_bd = be;
1099                 op.o_req_dn = *be->be_suffix;
1100                 op.o_req_ndn = *be->be_nsuffix;
1101                 op.ors_scope = LDAP_SCOPE_SUBTREE;
1102                 ni->li_tool_cookie.op = &op;
1103                 (void)enum_tree( &ni->li_tool_cookie );
1104                 ni->li_tool_cookie.op = NULL;
1105         }
1106         return id;
1107 }
1108
1109 static ID ldif_tool_entry_next(BackendDB *be)
1110 {
1111         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1112         ni->li_tool_current += 1;
1113         if(ni->li_tool_current > ni->li_tool_cookie.eind)
1114                 return NOID;
1115         else
1116                 return ni->li_tool_current;
1117 }
1118
1119 static Entry * ldif_tool_entry_get(BackendDB * be, ID id) {
1120         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1121         Entry * e;
1122
1123         if(id > ni->li_tool_cookie.eind || id < 1)
1124                 return NULL;
1125         else {
1126                 e = ni->li_tool_cookie.entries[id - 1];
1127                 ni->li_tool_cookie.entries[id - 1] = NULL;
1128                 return e;
1129         }
1130 }
1131
1132 static ID ldif_tool_entry_put(BackendDB * be, Entry * e, struct berval *text) {
1133         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1134         struct berval dn = e->e_nname;
1135         struct berval leaf_path = BER_BVNULL;
1136         struct stat stats;
1137         int statres;
1138         int res = LDAP_SUCCESS;
1139
1140         dn2path(&dn, &be->be_nsuffix[0], &ni->li_base_path, &leaf_path);
1141
1142         if(leaf_path.bv_val != NULL) {
1143                 struct berval base = BER_BVNULL;
1144                 /* build path to container, and path to ldif of container */
1145                 get_parent_path(&leaf_path, &base);
1146
1147                 statres = stat(base.bv_val, &stats); /* check if container exists */
1148                 if(statres == -1 && errno == ENOENT) { /* container missing */
1149                         base.bv_val[base.bv_len] = '.';
1150                         statres = stat(base.bv_val, &stats); /* check for leaf node */
1151                         base.bv_val[base.bv_len] = '\0';
1152                         if(statres == -1 && errno == ENOENT) {
1153                                 res = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
1154                         }
1155                         else if(statres != -1) { /* create parent */
1156                                 int mkdirres = mkdir(base.bv_val, 0750);
1157                                 if(mkdirres == -1) {
1158                                         res = LDAP_UNWILLING_TO_PERFORM;
1159                                 }
1160                         }
1161                         else
1162                                 res = LDAP_UNWILLING_TO_PERFORM;
1163                 }/* container was possibly created, move on to add the entry */
1164                 if(res == LDAP_SUCCESS) {
1165                         statres = stat(leaf_path.bv_val, &stats);
1166                         if(statres == -1 && errno == ENOENT) {
1167                                 res = (int) spew_entry(e, &leaf_path);
1168                         }
1169                         else /* it already exists */
1170                                 res = LDAP_ALREADY_EXISTS;
1171                 }
1172                 SLAP_FREE(base.bv_val);
1173                 SLAP_FREE(leaf_path.bv_val);
1174         }
1175
1176         if(res == LDAP_SUCCESS) {
1177                 return 1;
1178         }
1179         else
1180                 return NOID;
1181 }
1182
1183 static int
1184 ldif_back_db_init( BackendDB *be )
1185 {
1186         struct ldif_info *ni;
1187
1188         ni = ch_calloc( 1, sizeof(struct ldif_info) );
1189         be->be_private = ni;
1190         be->be_cf_ocs = ldifocs;
1191         ldap_pvt_thread_mutex_init(&ni->li_mutex);
1192         return 0;
1193 }
1194
1195 static int
1196 ldif_back_db_destroy(
1197                            Backend      *be
1198                            )
1199 {
1200         struct ldif_info *ni = be->be_private;
1201
1202         ch_free(ni->li_base_path.bv_val);
1203         ldap_pvt_thread_mutex_destroy(&ni->li_mutex);
1204         free( be->be_private );
1205         return 0;
1206 }
1207
1208 static int
1209 ldif_back_db_open(
1210                         Backend *be
1211                         )
1212 {
1213         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1214         if( BER_BVISEMPTY(&ni->li_base_path)) {/* missing base path */
1215                 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1216                 return 1;
1217         }
1218         return 0;
1219 }
1220
1221 int
1222 ldif_back_initialize(
1223                            BackendInfo  *bi
1224                            )
1225 {
1226         static char *controls[] = {
1227                 LDAP_CONTROL_MANAGEDSAIT,
1228                 NULL
1229         };
1230         int rc;
1231
1232         bi->bi_flags |=
1233                 SLAP_BFLAG_INCREMENT |
1234                 SLAP_BFLAG_REFERRALS;
1235
1236         bi->bi_controls = controls;
1237
1238         bi->bi_open = 0;
1239         bi->bi_close = 0;
1240         bi->bi_config = 0;
1241         bi->bi_destroy = 0;
1242
1243         bi->bi_db_init = ldif_back_db_init;
1244         bi->bi_db_config = config_generic_wrapper;
1245         bi->bi_db_open = ldif_back_db_open;
1246         bi->bi_db_close = 0;
1247         bi->bi_db_destroy = ldif_back_db_destroy;
1248
1249         bi->bi_op_bind = ldif_back_bind;
1250         bi->bi_op_unbind = 0;
1251         bi->bi_op_search = ldif_back_search;
1252         bi->bi_op_compare = 0;
1253         bi->bi_op_modify = ldif_back_modify;
1254         bi->bi_op_modrdn = ldif_back_modrdn;
1255         bi->bi_op_add = ldif_back_add;
1256         bi->bi_op_delete = ldif_back_delete;
1257         bi->bi_op_abandon = 0;
1258
1259         bi->bi_extended = 0;
1260
1261         bi->bi_chk_referrals = ldif_back_referrals;
1262
1263         bi->bi_connection_init = 0;
1264         bi->bi_connection_destroy = 0;
1265
1266         bi->bi_entry_get_rw = ldif_back_entry_get;
1267
1268 #if 0   /* NOTE: uncomment to completely disable access control */
1269         bi->bi_access_allowed = slap_access_always_allowed;
1270 #endif
1271
1272         bi->bi_tool_entry_open = ldif_tool_entry_open;
1273         bi->bi_tool_entry_close = ldif_tool_entry_close;
1274         bi->bi_tool_entry_first = ldif_tool_entry_first;
1275         bi->bi_tool_entry_next = ldif_tool_entry_next;
1276         bi->bi_tool_entry_get = ldif_tool_entry_get;
1277         bi->bi_tool_entry_put = ldif_tool_entry_put;
1278         bi->bi_tool_entry_reindex = 0;
1279         bi->bi_tool_sync = 0;
1280         
1281         bi->bi_tool_dn2id_get = 0;
1282         bi->bi_tool_id2entry_get = 0;
1283         bi->bi_tool_entry_modify = 0;
1284
1285         bi->bi_cf_ocs = ldifocs;
1286
1287         rc = config_register_schema( ldifcfg, ldifocs );
1288         if ( rc ) return rc;
1289         return 0;
1290 }