]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldif/ldif.c
Fix rev 1.52, frontendDB uses index {-1}.
[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_rdwr_t  li_rdwr;
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 && ( errno != ENOENT || op->o_tag != LDAP_REQ_ADD ) ) {
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 = strtol( 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 = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
511         int is_oc = 0;
512         Modification *mods = NULL;
513
514         if (!acl_check_modlist(op, entry, modlist)) {
515                 return LDAP_INSUFFICIENT_ACCESS;
516         }
517
518         for (; modlist != NULL; modlist = modlist->sml_next) {
519                 mods = &modlist->sml_mod;
520
521                 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
522                         is_oc = 1;
523                 }
524                 switch (mods->sm_op) {
525                 case LDAP_MOD_ADD:
526                         rc = modify_add_values(entry, mods,
527                                    get_permissiveModify(op),
528                                    &rs->sr_text, textbuf,
529                                    sizeof( textbuf ) );
530                         break;
531                                 
532                 case LDAP_MOD_DELETE:
533                         rc = modify_delete_values(entry, mods,
534                                 get_permissiveModify(op),
535                                 &rs->sr_text, textbuf,
536                                 sizeof( textbuf ) );
537                         break;
538                                 
539                 case LDAP_MOD_REPLACE:
540                         rc = modify_replace_values(entry, mods,
541                                  get_permissiveModify(op),
542                                  &rs->sr_text, textbuf,
543                                  sizeof( textbuf ) );
544                         break;
545
546                 case LDAP_MOD_INCREMENT:
547                         rc = modify_increment_values( entry,
548                                 mods, get_permissiveModify(op),
549                                 &rs->sr_text, textbuf,
550                                 sizeof( textbuf ) );
551                         break;
552
553                         break;
554
555                 case SLAP_MOD_SOFTADD:
556                         mods->sm_op = LDAP_MOD_ADD;
557                         rc = modify_add_values(entry, mods,
558                                    get_permissiveModify(op),
559                                    &rs->sr_text, textbuf,
560                                    sizeof( textbuf ) );
561                         mods->sm_op = SLAP_MOD_SOFTADD;
562                         if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
563                                 rc = LDAP_SUCCESS;
564                         }
565                         break;
566                 default:
567                         break;
568                 }
569                 if(rc != LDAP_SUCCESS) break;
570         }
571         
572         if(rc == LDAP_SUCCESS) {
573                 if ( is_oc ) {
574                         entry->e_ocflags = 0;
575                 }
576                 /* check that the entry still obeys the schema */
577                 rc = entry_schema_check( op, entry, NULL, 0,
578                           &rs->sr_text, textbuf, sizeof( textbuf ) );
579         }
580
581         return rc;
582 }
583
584 int
585 ldif_back_referrals( Operation *op, SlapReply *rs )
586 {
587         struct ldif_info        *ni = NULL;
588         Entry                   *entry;
589         int                     rc = LDAP_SUCCESS;
590
591 #if 0
592         if ( op->o_tag == LDAP_REQ_SEARCH ) {
593                 /* let search take care of itself */
594                 return rc;
595         }
596 #endif
597
598         if ( get_manageDSAit( op ) ) {
599                 /* let op take care of DSA management */
600                 return rc;
601         }
602
603         ni = (struct ldif_info *)op->o_bd->be_private;
604         ldap_pvt_thread_rdwr_rlock( &ni->li_rdwr );
605         entry = (Entry *)get_entry( op, &ni->li_base_path );
606
607         /* no object is found for them */
608         if ( entry == NULL ) {
609                 struct berval   odn = op->o_req_dn;
610                 struct berval   ondn = op->o_req_ndn;
611
612                 struct berval   pndn = op->o_req_ndn;
613
614                 for ( ; entry == NULL; ) {
615                         dnParent( &pndn, &pndn );
616                         
617                         if ( !dnIsSuffix( &pndn, &op->o_bd->be_nsuffix[0] ) ) {
618                                 break;
619                         }
620
621                         op->o_req_dn = pndn;
622                         op->o_req_ndn = pndn;
623
624                         entry = (Entry *)get_entry( op, &ni->li_base_path );
625                 }
626
627                 ldap_pvt_thread_rdwr_runlock( &ni->li_rdwr );
628
629                 op->o_req_dn = odn;
630                 op->o_req_ndn = ondn;
631
632                 rc = LDAP_SUCCESS;
633                 rs->sr_matched = NULL;
634                 if ( entry != NULL ) {
635                         Debug( LDAP_DEBUG_TRACE,
636                                 "ldif_back_referrals: op=%ld target=\"%s\" matched=\"%s\"\n",
637                                 (long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val );
638
639                         if ( is_entry_referral( entry ) ) {
640                                 rc = LDAP_OTHER;
641                                 rs->sr_ref = get_entry_referrals( op, entry );
642                                 if ( rs->sr_ref ) {
643                                         rs->sr_matched = ber_strdup_x(
644                                         entry->e_name.bv_val, op->o_tmpmemctx );
645                                 }
646                         }
647
648                         entry_free(entry);
649
650                 } else if ( default_referral != NULL ) {
651                         rc = LDAP_OTHER;
652                         rs->sr_ref = referral_rewrite( default_referral,
653                                 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
654                 }
655
656                 if ( rs->sr_ref != NULL ) {
657                         /* send referrals */
658                         rc = rs->sr_err = LDAP_REFERRAL;
659                         send_ldap_result( op, rs );
660                         ber_bvarray_free( rs->sr_ref );
661                         rs->sr_ref = NULL;
662
663                 } else if ( rc != LDAP_SUCCESS ) {
664                         rs->sr_err = rc;
665                         rs->sr_text = rs->sr_matched ? "bad referral object" : NULL;
666                         send_ldap_result( op, rs );
667                 }
668
669                 if ( rs->sr_matched ) {
670                         op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
671                         rs->sr_matched = NULL;
672                 }
673
674                 return rc;
675         }
676
677         ldap_pvt_thread_rdwr_runlock( &ni->li_rdwr );
678
679         if ( is_entry_referral( entry ) ) {
680                 /* entry is a referral */
681                 BerVarray refs = get_entry_referrals( op, entry );
682                 rs->sr_ref = referral_rewrite(
683                         refs, &entry->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
684
685                 Debug( LDAP_DEBUG_TRACE,
686                         "ldif_back_referrals: op=%ld target=\"%s\" matched=\"%s\"\n",
687                         (long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val );
688
689                 rs->sr_matched = entry->e_name.bv_val;
690                 if ( rs->sr_ref != NULL ) {
691                         rc = rs->sr_err = LDAP_REFERRAL;
692                         send_ldap_result( op, rs );
693                         ber_bvarray_free( rs->sr_ref );
694                         rs->sr_ref = NULL;
695
696                 } else {
697                         send_ldap_error( op, rs, LDAP_OTHER, "bad referral object" );
698                         rc = rs->sr_err;
699                 }
700
701                 rs->sr_matched = NULL;
702                 ber_bvarray_free( refs );
703         }
704
705         entry_free( entry );
706
707         return rc;
708 }
709
710 static int
711 ldif_back_bind( Operation *op, SlapReply *rs )
712 {
713         struct ldif_info *ni = NULL;
714         Attribute * a = NULL;
715         AttributeDescription *password = slap_schema.si_ad_userPassword;
716         int return_val = 0;
717         Entry * entry = NULL;
718
719         ni = (struct ldif_info *) op->o_bd->be_private;
720         ldap_pvt_thread_rdwr_rlock(&ni->li_rdwr);
721         entry = (Entry *) get_entry(op, &ni->li_base_path);
722
723         /* no object is found for them */
724         if(entry == NULL) {
725                 if(be_isroot_pw(op)) {
726                         rs->sr_err = return_val = LDAP_SUCCESS;
727                 } else {
728                         rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
729                 }
730                 goto return_result;
731         }
732
733         /* they don't have userpassword */
734         if((a = attr_find(entry->e_attrs, password)) == NULL) {
735                 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
736                 return_val = 1;
737                 goto return_result;
738         }
739
740         /* authentication actually failed */
741         if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
742                              &rs->sr_text) != 0) {
743                 rs->sr_err = LDAP_INVALID_CREDENTIALS;
744                 return_val = 1;
745                 goto return_result;
746         }
747
748         /* let the front-end send success */
749         return_val = 0;
750         goto return_result;
751
752  return_result:
753         ldap_pvt_thread_rdwr_runlock(&ni->li_rdwr);
754         if(return_val != 0)
755                 send_ldap_result( op, rs );
756         if(entry != NULL)
757                 entry_free(entry);
758         return return_val;
759 }
760
761 static int ldif_back_search(Operation *op, SlapReply *rs)
762 {
763         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
764         enumCookie ck = { NULL, NULL, NULL, 0, 0 };
765
766         ck.op = op;
767         ck.rs = rs;
768         ldap_pvt_thread_rdwr_rlock(&ni->li_rdwr);
769         rs->sr_err = enum_tree( &ck );
770         ldap_pvt_thread_rdwr_runlock(&ni->li_rdwr);
771         send_ldap_result(op, rs);
772
773         return rs->sr_err;
774 }
775
776 static int ldif_back_add(Operation *op, SlapReply *rs) {
777         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
778         Entry * e = op->ora_e;
779         struct berval dn = e->e_nname;
780         struct berval leaf_path = BER_BVNULL;
781         struct stat stats;
782         int statres;
783         char textbuf[SLAP_TEXT_BUFLEN];
784
785         Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", dn.bv_val, 0, 0);
786         slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
787
788         rs->sr_err = entry_schema_check(op, e, NULL, 0,
789                 &rs->sr_text, textbuf, sizeof( textbuf ) );
790         if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
791                                 
792         ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr);
793
794         dn2path(&dn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &leaf_path);
795
796         if(leaf_path.bv_val != NULL) {
797                 struct berval base = BER_BVNULL;
798                 /* build path to container and ldif of container */
799                 get_parent_path(&leaf_path, &base);
800
801                 statres = stat(base.bv_val, &stats); /* check if container exists */
802                 if(statres == -1 && errno == ENOENT) { /* container missing */
803                         base.bv_val[base.bv_len] = '.';
804                         statres = stat(base.bv_val, &stats); /* check for leaf node */
805                         base.bv_val[base.bv_len] = '\0';
806                         if(statres == -1 && errno == ENOENT) {
807                                 rs->sr_err = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
808                                 rs->sr_text = "Parent does not exist";
809                         }
810                         else if(statres != -1) { /* create parent */
811                                 int mkdirres = mkdir(base.bv_val, 0750);
812                                 if(mkdirres == -1) {
813                                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
814                                         rs->sr_text = "Could not create parent folder";
815                                         Debug( LDAP_DEBUG_ANY, "could not create folder \"%s\": %s\n",
816                                                 base.bv_val, strerror( errno ), 0 );
817                                 }
818                         }
819                         else
820                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
821                 }/* container was possibly created, move on to add the entry */
822                 if(rs->sr_err == LDAP_SUCCESS) {
823                         statres = stat(leaf_path.bv_val, &stats);
824                         if(statres == -1 && errno == ENOENT) {
825                                 ldap_pvt_thread_mutex_lock(&entry2str_mutex);
826                                 rs->sr_err = (int) spew_entry(e, &leaf_path);
827                                 ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
828                         }
829                         else if ( statres == -1 ) {
830                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
831                                 Debug( LDAP_DEBUG_ANY, "could not stat file \"%s\": %s\n",
832                                         leaf_path.bv_val, strerror( errno ), 0 );
833                         }
834                         else /* it already exists */
835                                 rs->sr_err = LDAP_ALREADY_EXISTS;
836                 }
837                 SLAP_FREE(base.bv_val);
838                 SLAP_FREE(leaf_path.bv_val);
839         }
840
841         ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr);
842
843 send_res:
844         Debug( LDAP_DEBUG_TRACE, 
845                         "ldif_back_add: err: %d text: %s\n", rs->sr_err, rs->sr_text, 0);
846         send_ldap_result(op, rs);
847         slap_graduate_commit_csn( op );
848         return 0;
849 }
850
851 static int ldif_back_modify(Operation *op, SlapReply *rs) {
852         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
853         Modifications * modlst = op->orm_modlist;
854         struct berval path = BER_BVNULL;
855         Entry * entry = NULL;
856         int spew_res;
857
858         slap_mods_opattrs( op, &op->orm_modlist, 1 );
859
860         ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr);
861         dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path,
862                 &path);
863         entry = (Entry *) get_entry(op, &ni->li_base_path);
864
865         if(entry != NULL) {
866                 rs->sr_err = apply_modify_to_entry(entry, modlst, op, rs);
867                 if(rs->sr_err == LDAP_SUCCESS) {
868                         int save_errno;
869                         ldap_pvt_thread_mutex_lock(&entry2str_mutex);
870                         spew_res = spew_entry(entry, &path);
871                         save_errno = errno;
872                         ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
873                         if(spew_res == -1) {
874                                 Debug( LDAP_DEBUG_ANY,
875                                         "%s ldif_back_modify: could not output entry \"%s\": %s\n",
876                                         op->o_log_prefix, entry->e_name.bv_val, strerror( save_errno ) );
877                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
878                         }
879                 }
880         }
881         else {
882                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
883         }
884         
885         if(entry != NULL)
886                 entry_free(entry);
887         if(path.bv_val != NULL)
888                 SLAP_FREE(path.bv_val);
889         rs->sr_text = NULL;
890         ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr);
891         send_ldap_result(op, rs);
892         slap_graduate_commit_csn( op );
893         return 0;
894 }
895
896 static int ldif_back_delete(Operation *op, SlapReply *rs) {
897         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
898         struct berval path = BER_BVNULL;
899         int res = 0;
900
901         if ( BER_BVISEMPTY( &op->o_csn )) {
902                 struct berval csn;
903                 char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
904
905                 csn.bv_val = csnbuf;
906                 csn.bv_len = sizeof( csnbuf );
907                 slap_get_csn( op, &csn, 1 );
908         }
909
910         ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr);
911         dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &path);
912
913         path.bv_val[path.bv_len - STRLENOF(LDIF)] = '\0';
914         res = rmdir(path.bv_val);
915         path.bv_val[path.bv_len - STRLENOF(LDIF)] = '.';
916         if ( res && errno != ENOENT ) {
917                 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
918         } else {
919                 res = unlink(path.bv_val);
920         }
921
922         if(res == -1) {
923                 if(errno == ENOENT)
924                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
925                 else
926                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
927         }
928         else
929                 rs->sr_err = LDAP_SUCCESS;
930
931         SLAP_FREE(path.bv_val);
932         ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr);
933         send_ldap_result(op, rs);
934         slap_graduate_commit_csn( op );
935         return 0;
936 }
937
938
939 static int move_entry(Entry * entry, struct berval * ndn,
940                            struct berval * newndn, struct berval * suffixdn,
941                            struct berval * base_path) {
942         int res;
943         int exists_res;
944         struct berval path;
945         struct berval newpath;
946
947         dn2path(ndn, suffixdn, base_path, &path);
948         dn2path(newndn, suffixdn, base_path, &newpath);
949
950         if((entry == NULL || path.bv_val == NULL) || newpath.bv_val == NULL) {
951                 /* some object doesn't exist */
952                 res = LDAP_NO_SUCH_OBJECT;
953         }
954         else { /* do the modrdn */
955                 exists_res = open(newpath.bv_val, O_RDONLY);
956                 if(exists_res == -1 && errno == ENOENT) {
957                         ldap_pvt_thread_mutex_lock( &entry2str_mutex );
958                         res = spew_entry(entry, &newpath);
959                         if(res != -1) {
960                                 /* if this fails we should log something bad */
961                                 res = unlink(path.bv_val);
962                                 res = LDAP_SUCCESS;
963                         }
964                         else {
965                                 if(errno == ENOENT)
966                                         res = LDAP_NO_SUCH_OBJECT;
967                                 else
968                                         res = LDAP_UNWILLING_TO_PERFORM;
969                                 unlink(newpath.bv_val); /* in case file was created */
970                         }
971                         ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
972                 }
973                 else if(exists_res) {
974                         int close_res = close(exists_res);
975                         res = LDAP_ALREADY_EXISTS;
976                         if(close_res == -1) {
977                         /* log heinous error */
978                         }
979                 }
980                 else {
981                         res = LDAP_UNWILLING_TO_PERFORM;
982                 }
983         }
984
985         if(newpath.bv_val != NULL)
986                 SLAP_FREE(newpath.bv_val);
987         if(path.bv_val != NULL)
988                 SLAP_FREE(path.bv_val);
989         return res;
990 }
991
992 static int
993 ldif_back_modrdn(Operation *op, SlapReply *rs)
994 {
995         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
996         struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
997         struct berval p_dn;
998         Entry * entry = NULL;
999         int res;
1000
1001         slap_mods_opattrs( op, &op->orr_modlist, 1 );
1002
1003         ldap_pvt_thread_rdwr_wlock( &ni->li_rdwr );
1004         entry = (Entry *) get_entry( op, &ni->li_base_path );
1005
1006         /* build the mods to the entry */
1007         if ( entry != NULL ) {
1008                 /* build new dn, and new ndn for the entry */
1009                 if ( op->oq_modrdn.rs_newSup != NULL ) {
1010                         struct berval   op_dn = op->o_req_dn,
1011                                         op_ndn = op->o_req_ndn;
1012                         Entry           *np;
1013
1014                         /* new superior */
1015                         p_dn = *op->oq_modrdn.rs_newSup;
1016                         op->o_req_dn = *op->oq_modrdn.rs_newSup;
1017                         op->o_req_ndn = *op->oq_modrdn.rs_nnewSup;
1018                         np = (Entry *)get_entry( op, &ni->li_base_path );
1019                         op->o_req_dn = op_dn;
1020                         op->o_req_ndn = op_ndn;
1021                         if ( np == NULL ) {
1022                                 goto no_such_object;
1023                         }
1024                         entry_free( np );
1025                 } else {
1026                         dnParent( &entry->e_name, &p_dn );
1027                 }
1028                 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL ); 
1029                 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1030                 ber_memfree_x( entry->e_name.bv_val, NULL );
1031                 ber_memfree_x( entry->e_nname.bv_val, NULL );
1032                 entry->e_name = new_dn;
1033                 entry->e_nname = new_ndn;
1034
1035                 /* perform the modifications */
1036                 res = apply_modify_to_entry( entry, op->orr_modlist, op, rs );
1037                 if ( res == LDAP_SUCCESS ) {
1038                         rs->sr_err = move_entry( entry, &op->o_req_ndn,
1039                                                 &new_ndn,
1040                                                 &op->o_bd->be_nsuffix[0],
1041                                                 &ni->li_base_path );
1042                 } else {
1043                         rs->sr_err = res;
1044                 }
1045         } else {
1046 no_such_object:;
1047                 /* entry was null */
1048                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1049         }
1050
1051         if ( entry != NULL ) {
1052                 entry_free( entry );
1053         }
1054         rs->sr_text = "";
1055         ldap_pvt_thread_rdwr_wunlock( &ni->li_rdwr );
1056         send_ldap_result( op, rs );
1057         slap_graduate_commit_csn( op );
1058         return 0;
1059 }
1060
1061 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
1062  */
1063 int ldif_back_entry_get(
1064         Operation *op,
1065         struct berval *ndn,
1066         ObjectClass *oc,
1067         AttributeDescription *at,
1068         int rw,
1069         Entry **ent )
1070 {
1071         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
1072         struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1073
1074         assert( ndn != NULL );
1075         assert( !BER_BVISNULL( ndn ) );
1076
1077         ldap_pvt_thread_rdwr_rlock( &ni->li_rdwr );
1078         op->o_req_dn = *ndn;
1079         op->o_req_ndn = *ndn;
1080         *ent = (Entry *) get_entry( op, &ni->li_base_path );
1081         op->o_req_dn = op_dn;
1082         op->o_req_ndn = op_ndn;
1083         ldap_pvt_thread_rdwr_runlock( &ni->li_rdwr );
1084
1085         if ( *ent && oc && !is_entry_objectclass_or_sub( *ent, oc ) ) {
1086                 entry_free( *ent );
1087                 *ent = NULL;
1088         }
1089
1090         return ( *ent == NULL ? 1 : 0 );
1091 }
1092
1093 static int ldif_tool_entry_open(BackendDB * be, int mode) {
1094         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1095         ni->li_tool_current = 0;
1096         return 0;
1097 }                                       
1098
1099 static int ldif_tool_entry_close(BackendDB * be) {
1100         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1101
1102         SLAP_FREE(ni->li_tool_cookie.entries);
1103         return 0;
1104 }
1105
1106 static ID
1107 ldif_tool_entry_first(BackendDB *be)
1108 {
1109         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1110         ID id = 1; /* first entry in the array of entries shifted by one */
1111
1112         ni->li_tool_current = 1;
1113         if(ni->li_tool_cookie.entries == NULL) {
1114                 Operation op = {0};
1115
1116                 op.o_bd = be;
1117                 op.o_req_dn = *be->be_suffix;
1118                 op.o_req_ndn = *be->be_nsuffix;
1119                 op.ors_scope = LDAP_SCOPE_SUBTREE;
1120                 ni->li_tool_cookie.op = &op;
1121                 (void)enum_tree( &ni->li_tool_cookie );
1122                 ni->li_tool_cookie.op = NULL;
1123         }
1124         return id;
1125 }
1126
1127 static ID ldif_tool_entry_next(BackendDB *be)
1128 {
1129         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1130         ni->li_tool_current += 1;
1131         if(ni->li_tool_current > ni->li_tool_cookie.eind)
1132                 return NOID;
1133         else
1134                 return ni->li_tool_current;
1135 }
1136
1137 static Entry * ldif_tool_entry_get(BackendDB * be, ID id) {
1138         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1139         Entry * e;
1140
1141         if(id > ni->li_tool_cookie.eind || id < 1)
1142                 return NULL;
1143         else {
1144                 e = ni->li_tool_cookie.entries[id - 1];
1145                 ni->li_tool_cookie.entries[id - 1] = NULL;
1146                 return e;
1147         }
1148 }
1149
1150 static ID ldif_tool_entry_put(BackendDB * be, Entry * e, struct berval *text) {
1151         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1152         struct berval dn = e->e_nname;
1153         struct berval leaf_path = BER_BVNULL;
1154         struct stat stats;
1155         int statres;
1156         int res = LDAP_SUCCESS;
1157
1158         dn2path(&dn, &be->be_nsuffix[0], &ni->li_base_path, &leaf_path);
1159
1160         if(leaf_path.bv_val != NULL) {
1161                 struct berval base = BER_BVNULL;
1162                 /* build path to container, and path to ldif of container */
1163                 get_parent_path(&leaf_path, &base);
1164
1165                 statres = stat(base.bv_val, &stats); /* check if container exists */
1166                 if(statres == -1 && errno == ENOENT) { /* container missing */
1167                         base.bv_val[base.bv_len] = '.';
1168                         statres = stat(base.bv_val, &stats); /* check for leaf node */
1169                         base.bv_val[base.bv_len] = '\0';
1170                         if(statres == -1 && errno == ENOENT) {
1171                                 res = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
1172                         }
1173                         else if(statres != -1) { /* create parent */
1174                                 int mkdirres = mkdir(base.bv_val, 0750);
1175                                 if(mkdirres == -1) {
1176                                         res = LDAP_UNWILLING_TO_PERFORM;
1177                                 }
1178                         }
1179                         else
1180                                 res = LDAP_UNWILLING_TO_PERFORM;
1181                 }/* container was possibly created, move on to add the entry */
1182                 if(res == LDAP_SUCCESS) {
1183                         statres = stat(leaf_path.bv_val, &stats);
1184                         if(statres == -1 && errno == ENOENT) {
1185                                 res = (int) spew_entry(e, &leaf_path);
1186                         }
1187                         else /* it already exists */
1188                                 res = LDAP_ALREADY_EXISTS;
1189                 }
1190                 SLAP_FREE(base.bv_val);
1191                 SLAP_FREE(leaf_path.bv_val);
1192         }
1193
1194         if(res == LDAP_SUCCESS) {
1195                 return 1;
1196         }
1197         else
1198                 return NOID;
1199 }
1200
1201 static int
1202 ldif_back_db_init( BackendDB *be )
1203 {
1204         struct ldif_info *ni;
1205
1206         ni = ch_calloc( 1, sizeof(struct ldif_info) );
1207         be->be_private = ni;
1208         be->be_cf_ocs = ldifocs;
1209         ldap_pvt_thread_rdwr_init(&ni->li_rdwr);
1210         return 0;
1211 }
1212
1213 static int
1214 ldif_back_db_destroy(
1215                            Backend      *be
1216                            )
1217 {
1218         struct ldif_info *ni = be->be_private;
1219
1220         ch_free(ni->li_base_path.bv_val);
1221         ldap_pvt_thread_rdwr_destroy(&ni->li_rdwr);
1222         free( be->be_private );
1223         return 0;
1224 }
1225
1226 static int
1227 ldif_back_db_open(
1228                         Backend *be
1229                         )
1230 {
1231         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1232         if( BER_BVISEMPTY(&ni->li_base_path)) {/* missing base path */
1233                 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1234                 return 1;
1235         }
1236         return 0;
1237 }
1238
1239 int
1240 ldif_back_initialize(
1241                            BackendInfo  *bi
1242                            )
1243 {
1244         static char *controls[] = {
1245                 LDAP_CONTROL_MANAGEDSAIT,
1246                 NULL
1247         };
1248         int rc;
1249
1250         bi->bi_flags |=
1251                 SLAP_BFLAG_INCREMENT |
1252                 SLAP_BFLAG_REFERRALS;
1253
1254         bi->bi_controls = controls;
1255
1256         bi->bi_open = 0;
1257         bi->bi_close = 0;
1258         bi->bi_config = 0;
1259         bi->bi_destroy = 0;
1260
1261         bi->bi_db_init = ldif_back_db_init;
1262         bi->bi_db_config = config_generic_wrapper;
1263         bi->bi_db_open = ldif_back_db_open;
1264         bi->bi_db_close = 0;
1265         bi->bi_db_destroy = ldif_back_db_destroy;
1266
1267         bi->bi_op_bind = ldif_back_bind;
1268         bi->bi_op_unbind = 0;
1269         bi->bi_op_search = ldif_back_search;
1270         bi->bi_op_compare = 0;
1271         bi->bi_op_modify = ldif_back_modify;
1272         bi->bi_op_modrdn = ldif_back_modrdn;
1273         bi->bi_op_add = ldif_back_add;
1274         bi->bi_op_delete = ldif_back_delete;
1275         bi->bi_op_abandon = 0;
1276
1277         bi->bi_extended = 0;
1278
1279         bi->bi_chk_referrals = ldif_back_referrals;
1280
1281         bi->bi_connection_init = 0;
1282         bi->bi_connection_destroy = 0;
1283
1284         bi->bi_entry_get_rw = ldif_back_entry_get;
1285
1286 #if 0   /* NOTE: uncomment to completely disable access control */
1287         bi->bi_access_allowed = slap_access_always_allowed;
1288 #endif
1289
1290         bi->bi_tool_entry_open = ldif_tool_entry_open;
1291         bi->bi_tool_entry_close = ldif_tool_entry_close;
1292         bi->bi_tool_entry_first = ldif_tool_entry_first;
1293         bi->bi_tool_entry_next = ldif_tool_entry_next;
1294         bi->bi_tool_entry_get = ldif_tool_entry_get;
1295         bi->bi_tool_entry_put = ldif_tool_entry_put;
1296         bi->bi_tool_entry_reindex = 0;
1297         bi->bi_tool_sync = 0;
1298         
1299         bi->bi_tool_dn2id_get = 0;
1300         bi->bi_tool_id2entry_get = 0;
1301         bi->bi_tool_entry_modify = 0;
1302
1303         bi->bi_cf_ocs = ldifocs;
1304
1305         rc = config_register_schema( ldifcfg, ldifocs );
1306         if ( rc ) return rc;
1307         return 0;
1308 }