]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldif/ldif.c
80e573dc6c86af67eeb18e0caf59f680dd919457
[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-2007 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 ?
846                                 rs->sr_text : "", 0);
847         send_ldap_result(op, rs);
848         slap_graduate_commit_csn( op );
849         return 0;
850 }
851
852 static int ldif_back_modify(Operation *op, SlapReply *rs) {
853         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
854         Modifications * modlst = op->orm_modlist;
855         struct berval path = BER_BVNULL;
856         Entry * entry = NULL;
857         int spew_res;
858
859         slap_mods_opattrs( op, &op->orm_modlist, 1 );
860
861         ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr);
862         dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path,
863                 &path);
864         entry = (Entry *) get_entry(op, &ni->li_base_path);
865
866         if(entry != NULL) {
867                 rs->sr_err = apply_modify_to_entry(entry, modlst, op, rs);
868                 if(rs->sr_err == LDAP_SUCCESS) {
869                         int save_errno;
870                         ldap_pvt_thread_mutex_lock(&entry2str_mutex);
871                         spew_res = spew_entry(entry, &path);
872                         save_errno = errno;
873                         ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
874                         if(spew_res == -1) {
875                                 Debug( LDAP_DEBUG_ANY,
876                                         "%s ldif_back_modify: could not output entry \"%s\": %s\n",
877                                         op->o_log_prefix, entry->e_name.bv_val, STRERROR( save_errno ) );
878                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
879                         }
880                 }
881         }
882         else {
883                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
884         }
885         
886         if(entry != NULL)
887                 entry_free(entry);
888         if(path.bv_val != NULL)
889                 SLAP_FREE(path.bv_val);
890         rs->sr_text = NULL;
891         ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr);
892         send_ldap_result(op, rs);
893         slap_graduate_commit_csn( op );
894         return 0;
895 }
896
897 static int ldif_back_delete(Operation *op, SlapReply *rs) {
898         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
899         struct berval path = BER_BVNULL;
900         int res = 0;
901
902         if ( BER_BVISEMPTY( &op->o_csn )) {
903                 struct berval csn;
904                 char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
905
906                 csn.bv_val = csnbuf;
907                 csn.bv_len = sizeof( csnbuf );
908                 slap_get_csn( op, &csn, 1 );
909         }
910
911         ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr);
912         dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &path);
913
914         path.bv_val[path.bv_len - STRLENOF(LDIF)] = '\0';
915         res = rmdir(path.bv_val);
916         path.bv_val[path.bv_len - STRLENOF(LDIF)] = '.';
917         if ( res && errno != ENOENT ) {
918                 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
919         } else {
920                 res = unlink(path.bv_val);
921         }
922
923         if(res == -1) {
924                 if(errno == ENOENT)
925                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
926                 else
927                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
928         }
929         else
930                 rs->sr_err = LDAP_SUCCESS;
931
932         SLAP_FREE(path.bv_val);
933         ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr);
934         send_ldap_result(op, rs);
935         slap_graduate_commit_csn( op );
936         return 0;
937 }
938
939
940 static int move_entry(Entry * entry, struct berval * ndn,
941                            struct berval * newndn, struct berval * suffixdn,
942                            struct berval * base_path) {
943         int res;
944         int exists_res;
945         struct berval path;
946         struct berval newpath;
947
948         dn2path(ndn, suffixdn, base_path, &path);
949         dn2path(newndn, suffixdn, base_path, &newpath);
950
951         if((entry == NULL || path.bv_val == NULL) || newpath.bv_val == NULL) {
952                 /* some object doesn't exist */
953                 res = LDAP_NO_SUCH_OBJECT;
954         }
955         else { /* do the modrdn */
956                 exists_res = open(newpath.bv_val, O_RDONLY);
957                 if(exists_res == -1 && errno == ENOENT) {
958                         ldap_pvt_thread_mutex_lock( &entry2str_mutex );
959                         res = spew_entry(entry, &newpath);
960                         if(res != -1) {
961                                 /* if this fails we should log something bad */
962                                 res = unlink(path.bv_val);
963                                 res = LDAP_SUCCESS;
964                         }
965                         else {
966                                 if(errno == ENOENT)
967                                         res = LDAP_NO_SUCH_OBJECT;
968                                 else
969                                         res = LDAP_UNWILLING_TO_PERFORM;
970                                 unlink(newpath.bv_val); /* in case file was created */
971                         }
972                         ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
973                 }
974                 else if(exists_res) {
975                         int close_res = close(exists_res);
976                         res = LDAP_ALREADY_EXISTS;
977                         if(close_res == -1) {
978                         /* log heinous error */
979                         }
980                 }
981                 else {
982                         res = LDAP_UNWILLING_TO_PERFORM;
983                 }
984         }
985
986         if(newpath.bv_val != NULL)
987                 SLAP_FREE(newpath.bv_val);
988         if(path.bv_val != NULL)
989                 SLAP_FREE(path.bv_val);
990         return res;
991 }
992
993 static int ldif_back_modrdn(Operation *op, SlapReply *rs) {
994         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
995         struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
996         struct berval p_dn, bv = BER_BVNULL;
997         Entry * entry = NULL;
998         LDAPRDN new_rdn = NULL;
999         LDAPRDN old_rdn = NULL;
1000         Modifications * mods = NULL;
1001         int res;
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                 if(ldap_bv2rdn(&op->oq_modrdn.rs_newrdn, &new_rdn,
1009                         (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP)) {
1010                         rs->sr_err = LDAP_INVALID_DN_SYNTAX;
1011                 }
1012                 else if(op->oq_modrdn.rs_deleteoldrdn &&
1013                         ldap_bv2rdn(&op->o_req_dn, &old_rdn, (char **)&rs->sr_text,
1014                         LDAP_DN_FORMAT_LDAP)) {
1015                         rs->sr_err = LDAP_OTHER;
1016                 }
1017                 else { /* got both rdns successfully, ready to build mods */
1018                         if(slap_modrdn2mods(op, rs, entry, old_rdn, new_rdn, &mods)
1019                                 != LDAP_SUCCESS) {
1020                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1021                         }
1022                         else { /* built mods successfully */
1023
1024                                 /* build new dn, and new ndn for the entry */
1025                                 if(op->oq_modrdn.rs_newSup != NULL) {
1026                                         struct berval   op_dn = op->o_req_dn,
1027                                                         op_ndn = op->o_req_ndn;
1028                                         Entry           *np;
1029
1030                                         /* new superior */
1031                                         p_dn = *op->oq_modrdn.rs_newSup;
1032                                         op->o_req_dn = *op->oq_modrdn.rs_newSup;
1033                                         op->o_req_ndn = *op->oq_modrdn.rs_nnewSup;
1034                                         np = (Entry *)get_entry( op, &ni->li_base_path );
1035                                         op->o_req_dn = op_dn;
1036                                         op->o_req_ndn = op_ndn;
1037                                         if ( np == NULL ) {
1038                                                 goto no_such_object;
1039                                         }
1040                                         entry_free( np );
1041                                 } else {
1042                                         dnParent(&entry->e_name, &p_dn);
1043                                 }
1044                                 build_new_dn(&new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL); 
1045                                 dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx );
1046                                 ber_dupbv( &new_ndn, &bv );
1047                                 entry->e_name = new_dn;
1048                                 entry->e_nname = new_ndn;
1049
1050                                 /* perform the modifications */
1051                                 res = apply_modify_to_entry(entry, mods, op, rs);
1052                                 if(res == LDAP_SUCCESS) {
1053                                         rs->sr_err = move_entry(entry, &op->o_req_ndn,
1054                                                                 &new_ndn,
1055                                                                 &op->o_bd->be_nsuffix[0],
1056                                                                 &ni->li_base_path);
1057                                 } else {
1058                                         rs->sr_err = res;
1059                                 }
1060                         }
1061                 }
1062         } else {
1063 no_such_object:;
1064         /* entry was null */
1065                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1066         }
1067
1068         if ( entry != NULL ) {
1069                 entry_free(entry);
1070         }
1071         rs->sr_text = "";
1072         ldap_pvt_thread_rdwr_wunlock( &ni->li_rdwr );
1073         send_ldap_result(op, rs);
1074         slap_graduate_commit_csn( op );
1075         return 0;
1076 }
1077
1078 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
1079  */
1080 int ldif_back_entry_get(
1081         Operation *op,
1082         struct berval *ndn,
1083         ObjectClass *oc,
1084         AttributeDescription *at,
1085         int rw,
1086         Entry **ent )
1087 {
1088         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
1089         struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1090
1091         assert( ndn != NULL );
1092         assert( !BER_BVISNULL( ndn ) );
1093
1094         ldap_pvt_thread_rdwr_rlock( &ni->li_rdwr );
1095         op->o_req_dn = *ndn;
1096         op->o_req_ndn = *ndn;
1097         *ent = (Entry *) get_entry( op, &ni->li_base_path );
1098         op->o_req_dn = op_dn;
1099         op->o_req_ndn = op_ndn;
1100         ldap_pvt_thread_rdwr_runlock( &ni->li_rdwr );
1101
1102         if ( *ent && oc && !is_entry_objectclass_or_sub( *ent, oc ) ) {
1103                 entry_free( *ent );
1104                 *ent = NULL;
1105         }
1106
1107         return ( *ent == NULL ? 1 : 0 );
1108 }
1109
1110 static int ldif_tool_entry_open(BackendDB * be, int mode) {
1111         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1112         ni->li_tool_current = 0;
1113         return 0;
1114 }                                       
1115
1116 static int ldif_tool_entry_close(BackendDB * be) {
1117         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1118
1119         SLAP_FREE(ni->li_tool_cookie.entries);
1120         return 0;
1121 }
1122
1123 static ID
1124 ldif_tool_entry_first(BackendDB *be)
1125 {
1126         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1127         ID id = 1; /* first entry in the array of entries shifted by one */
1128
1129         ni->li_tool_current = 1;
1130         if(ni->li_tool_cookie.entries == NULL) {
1131                 Operation op = {0};
1132
1133                 op.o_bd = be;
1134                 op.o_req_dn = *be->be_suffix;
1135                 op.o_req_ndn = *be->be_nsuffix;
1136                 op.ors_scope = LDAP_SCOPE_SUBTREE;
1137                 ni->li_tool_cookie.op = &op;
1138                 (void)enum_tree( &ni->li_tool_cookie );
1139                 ni->li_tool_cookie.op = NULL;
1140         }
1141         return id;
1142 }
1143
1144 static ID ldif_tool_entry_next(BackendDB *be)
1145 {
1146         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1147         ni->li_tool_current += 1;
1148         if(ni->li_tool_current > ni->li_tool_cookie.eind)
1149                 return NOID;
1150         else
1151                 return ni->li_tool_current;
1152 }
1153
1154 static Entry * ldif_tool_entry_get(BackendDB * be, ID id) {
1155         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1156         Entry * e;
1157
1158         if(id > ni->li_tool_cookie.eind || id < 1)
1159                 return NULL;
1160         else {
1161                 e = ni->li_tool_cookie.entries[id - 1];
1162                 ni->li_tool_cookie.entries[id - 1] = NULL;
1163                 return e;
1164         }
1165 }
1166
1167 static ID ldif_tool_entry_put(BackendDB * be, Entry * e, struct berval *text) {
1168         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1169         struct berval dn = e->e_nname;
1170         struct berval leaf_path = BER_BVNULL;
1171         struct stat stats;
1172         int statres;
1173         int res = LDAP_SUCCESS;
1174
1175         dn2path(&dn, &be->be_nsuffix[0], &ni->li_base_path, &leaf_path);
1176
1177         if(leaf_path.bv_val != NULL) {
1178                 struct berval base = BER_BVNULL;
1179                 /* build path to container, and path to ldif of container */
1180                 get_parent_path(&leaf_path, &base);
1181
1182                 statres = stat(base.bv_val, &stats); /* check if container exists */
1183                 if(statres == -1 && errno == ENOENT) { /* container missing */
1184                         base.bv_val[base.bv_len] = '.';
1185                         statres = stat(base.bv_val, &stats); /* check for leaf node */
1186                         base.bv_val[base.bv_len] = '\0';
1187                         if(statres == -1 && errno == ENOENT) {
1188                                 res = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
1189                         }
1190                         else if(statres != -1) { /* create parent */
1191                                 int mkdirres = mkdir(base.bv_val, 0750);
1192                                 if(mkdirres == -1) {
1193                                         res = LDAP_UNWILLING_TO_PERFORM;
1194                                 }
1195                         }
1196                         else
1197                                 res = LDAP_UNWILLING_TO_PERFORM;
1198                 }/* container was possibly created, move on to add the entry */
1199                 if(res == LDAP_SUCCESS) {
1200                         statres = stat(leaf_path.bv_val, &stats);
1201                         if(statres == -1 && errno == ENOENT) {
1202                                 res = (int) spew_entry(e, &leaf_path);
1203                         }
1204                         else /* it already exists */
1205                                 res = LDAP_ALREADY_EXISTS;
1206                 }
1207                 SLAP_FREE(base.bv_val);
1208                 SLAP_FREE(leaf_path.bv_val);
1209         }
1210
1211         if(res == LDAP_SUCCESS) {
1212                 return 1;
1213         }
1214         else
1215                 return NOID;
1216 }
1217
1218 static int
1219 ldif_back_db_init( BackendDB *be )
1220 {
1221         struct ldif_info *ni;
1222
1223         ni = ch_calloc( 1, sizeof(struct ldif_info) );
1224         be->be_private = ni;
1225         be->be_cf_ocs = ldifocs;
1226         ldap_pvt_thread_rdwr_init(&ni->li_rdwr);
1227         return 0;
1228 }
1229
1230 static int
1231 ldif_back_db_destroy(
1232                            Backend      *be
1233                            )
1234 {
1235         struct ldif_info *ni = be->be_private;
1236
1237         ch_free(ni->li_base_path.bv_val);
1238         ldap_pvt_thread_rdwr_destroy(&ni->li_rdwr);
1239         free( be->be_private );
1240         return 0;
1241 }
1242
1243 static int
1244 ldif_back_db_open(
1245                         Backend *be
1246                         )
1247 {
1248         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1249         if( BER_BVISEMPTY(&ni->li_base_path)) {/* missing base path */
1250                 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1251                 return 1;
1252         }
1253         return 0;
1254 }
1255
1256 int
1257 ldif_back_initialize(
1258                            BackendInfo  *bi
1259                            )
1260 {
1261         static char *controls[] = {
1262                 LDAP_CONTROL_MANAGEDSAIT,
1263                 NULL
1264         };
1265         int rc;
1266
1267         bi->bi_flags |=
1268                 SLAP_BFLAG_INCREMENT |
1269                 SLAP_BFLAG_REFERRALS;
1270
1271         bi->bi_controls = controls;
1272
1273         bi->bi_open = 0;
1274         bi->bi_close = 0;
1275         bi->bi_config = 0;
1276         bi->bi_destroy = 0;
1277
1278         bi->bi_db_init = ldif_back_db_init;
1279         bi->bi_db_config = config_generic_wrapper;
1280         bi->bi_db_open = ldif_back_db_open;
1281         bi->bi_db_close = 0;
1282         bi->bi_db_destroy = ldif_back_db_destroy;
1283
1284         bi->bi_op_bind = ldif_back_bind;
1285         bi->bi_op_unbind = 0;
1286         bi->bi_op_search = ldif_back_search;
1287         bi->bi_op_compare = 0;
1288         bi->bi_op_modify = ldif_back_modify;
1289         bi->bi_op_modrdn = ldif_back_modrdn;
1290         bi->bi_op_add = ldif_back_add;
1291         bi->bi_op_delete = ldif_back_delete;
1292         bi->bi_op_abandon = 0;
1293
1294         bi->bi_extended = 0;
1295
1296         bi->bi_chk_referrals = ldif_back_referrals;
1297
1298         bi->bi_connection_init = 0;
1299         bi->bi_connection_destroy = 0;
1300
1301         bi->bi_entry_get_rw = ldif_back_entry_get;
1302
1303 #if 0   /* NOTE: uncomment to completely disable access control */
1304 #ifdef SLAP_OVERLAY_ACCESS
1305         bi->bi_access_allowed = slap_access_always_allowed;
1306 #endif /* SLAP_OVERLAY_ACCESS */
1307 #endif
1308
1309         bi->bi_tool_entry_open = ldif_tool_entry_open;
1310         bi->bi_tool_entry_close = ldif_tool_entry_close;
1311         bi->bi_tool_entry_first = ldif_tool_entry_first;
1312         bi->bi_tool_entry_next = ldif_tool_entry_next;
1313         bi->bi_tool_entry_get = ldif_tool_entry_get;
1314         bi->bi_tool_entry_put = ldif_tool_entry_put;
1315         bi->bi_tool_entry_reindex = 0;
1316         bi->bi_tool_sync = 0;
1317         
1318         bi->bi_tool_dn2id_get = 0;
1319         bi->bi_tool_id2entry_get = 0;
1320         bi->bi_tool_entry_modify = 0;
1321
1322         bi->bi_cf_ocs = ldifocs;
1323
1324         rc = config_register_schema( ldifcfg, ldifocs );
1325         if ( rc ) return rc;
1326         return 0;
1327 }