]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldif/ldif.c
ITS#5408 part 2 - filesystem I/O, file error handling:
[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-2008 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         ID elen;
39         ID 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 #define move_file(from, to) (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
52 #else
53 #define move_file(from, to) rename(from, to)
54 #endif
55
56
57 #define LDIF    ".ldif"
58 #define LDIF_FILETYPE_SEP       '.'                     /* LDIF[0] */
59
60 /*
61  * Unsafe/translated characters in the filesystem.
62  *
63  * LDIF_UNSAFE_CHAR(c) returns true if the character c is not to be used
64  * in relative filenames, except it should accept '\\' even if unsafe and
65  * need not reject '{' and '}'.  The value should be a constant expression.
66  *
67  * If '\\' is unsafe, #define LDIF_ESCAPE_CHAR as a safe character.
68  *
69  * If '{' and '}' are unsafe, #define IX_FSL/IX_FSR as safe characters.
70  * (Not digits, '-' or '+'.  IX_FSL == IX_FSR is allowed.)
71  *
72  * Characters are escaped as LDIF_ESCAPE_CHAR followed by two hex digits,
73  * except '\\' is replaced with LDIF_ESCAPE_CHAR and {} with IX_FS[LR].
74  * Also some LDIF special chars are hex-escaped.
75  *
76  * Thus an LDIF filename is a valid normalized RDN (or suffix DN)
77  * followed by ".ldif", except with '\\' replaced with LDIF_ESCAPE_CHAR.
78  */
79
80 #ifndef _WIN32
81
82 /*
83  * Unix/MacOSX version.  ':' vs '/' can cause confusion on MacOSX so we
84  * escape both.  We escape them on Unix so both OS variants get the same
85  * filenames.
86  */
87 #define LDIF_ESCAPE_CHAR        '\\'
88 #define LDIF_UNSAFE_CHAR(c)     ((c) == '/' || (c) == ':')
89
90 #else /* _WIN32 */
91
92 /* Windows version - Microsoft's list of unsafe characters, except '\\' */
93 #define LDIF_ESCAPE_CHAR        '^'
94 #define LDIF_UNSAFE_CHAR(c)     \
95         ((c) == '/' || (c) == ':' || \
96          (c) == '<' || (c) == '>' || (c) == '"' || \
97          (c) == '|' || (c) == '?' || (c) == '*')
98
99 #endif /* !_WIN32 */
100
101 /*
102  * Left and Right "{num}" prefix to ordered RDNs ("olcDatabase={1}bdb").
103  * IX_DN* are for LDAP RDNs, IX_FS* for their .ldif filenames.
104  */
105 #define IX_DNL  '{'
106 #define IX_DNR  '}'
107 #ifndef IX_FSL
108 #define IX_FSL  IX_DNL
109 #define IX_FSR  IX_DNR
110 #endif
111
112 /*
113  * Test for unsafe chars, as well as chars handled specially by back-ldif:
114  * - If the escape char is not '\\', it must itself be escaped.  Otherwise
115  *   '\\' and the escape char would map to the same character.
116  * - Escape the '.' in ".ldif", so the directory for an RDN that actually
117  *   ends with ".ldif" can not conflict with a file of the same name.  And
118  *   since some OSes/programs choke on multiple '.'s, escape all of them.
119  * - If '{' and '}' are translated to some other characters, those
120  *   characters must in turn be escaped when they occur in an RDN.
121  */
122 #ifndef LDIF_NEED_ESCAPE
123 #define LDIF_NEED_ESCAPE(c) \
124         ((LDIF_UNSAFE_CHAR(c)) || \
125          LDIF_MAYBE_UNSAFE(c, LDIF_ESCAPE_CHAR) || \
126          LDIF_MAYBE_UNSAFE(c, LDIF_FILETYPE_SEP) || \
127          LDIF_MAYBE_UNSAFE(c, IX_FSL) || \
128          (IX_FSR != IX_FSL && LDIF_MAYBE_UNSAFE(c, IX_FSR)))
129 #endif
130 /*
131  * Helper macro for LDIF_NEED_ESCAPE(): Treat character x as unsafe if
132  * back-ldif does not already treat is specially.
133  */
134 #define LDIF_MAYBE_UNSAFE(c, x) \
135         (!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \
136          && (c) == (x))
137
138
139 #define ENTRY_BUFF_INCREMENT 500
140
141 static ConfigTable ldifcfg[] = {
142         { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
143                 (void *)offsetof(struct ldif_info, li_base_path),
144                 "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
145                         "DESC 'Directory for database content' "
146                         "EQUALITY caseIgnoreMatch "
147                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
148         { NULL, NULL, 0, 0, 0, ARG_IGNORED,
149                 NULL, NULL, NULL, NULL }
150 };
151
152 static ConfigOCs ldifocs[] = {
153         { "( OLcfgDbOc:2.1 "
154                 "NAME 'olcLdifConfig' "
155                 "DESC 'LDIF backend configuration' "
156                 "SUP olcDatabaseConfig "
157                 "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg },
158         { NULL, 0, NULL }
159 };
160
161
162 /* Set *res = LDIF filename path for the normalized DN */
163 static void
164 dn2path( BackendDB *be, struct berval *dn, struct berval *res )
165 {
166         struct ldif_info *li = (struct ldif_info *) be->be_private;
167         struct berval *suffixdn = &be->be_nsuffix[0];
168         const char *start, *end, *next, *p;
169         char ch, *ptr;
170         ber_len_t len;
171         static const char hex[] = "0123456789ABCDEF";
172
173         assert( dn != NULL );
174         assert( !BER_BVISNULL( dn ) );
175         assert( suffixdn != NULL );
176         assert( !BER_BVISNULL( suffixdn ) );
177         assert( dnIsSuffix( dn, suffixdn ) );
178
179         start = dn->bv_val;
180         end = start + dn->bv_len;
181
182         /* Room for dir, dirsep, dn, LDIF, "\hexpair"-escaping of unsafe chars */
183         len = li->li_base_path.bv_len + dn->bv_len + (1 + STRLENOF( LDIF ));
184         for ( p = start; p < end; ) {
185                 ch = *p++;
186                 if ( LDIF_NEED_ESCAPE( ch ) )
187                         len += 2;
188         }
189         res->bv_val = ch_malloc( len + 1 );
190
191         ptr = lutil_strcopy( res->bv_val, li->li_base_path.bv_val );
192         for ( next = end - suffixdn->bv_len; end > start; end = next ) {
193                 /* Set p = start of DN component, next = &',' or start of DN */
194                 while ( (p = next) > start ) {
195                         --next;
196                         if ( DN_SEPARATOR( *next ) )
197                                 break;
198                 }
199                 /* Append <dirsep> <p..end-1: RDN or database-suffix> */
200                 for ( *ptr++ = LDAP_DIRSEP[0]; p < end; *ptr++ = ch ) {
201                         ch = *p++;
202                         if ( LDIF_ESCAPE_CHAR != '\\' && ch == '\\' ) {
203                                 ch = LDIF_ESCAPE_CHAR;
204                         } else if ( IX_FSL != IX_DNL && ch == IX_DNL ) {
205                                 ch = IX_FSL;
206                         } else if ( IX_FSR != IX_DNR && ch == IX_DNR ) {
207                                 ch = IX_FSR;
208                         } else if ( LDIF_NEED_ESCAPE( ch ) ) {
209                                 *ptr++ = LDIF_ESCAPE_CHAR;
210                                 *ptr++ = hex[(ch & 0xFFU) >> 4];
211                                 ch = hex[ch & 0x0FU];
212                         }
213                 }
214         }
215         ptr = lutil_strcopy( ptr, LDIF );
216         res->bv_len = ptr - res->bv_val;
217
218         assert( res->bv_len <= len );
219 }
220
221 /* Make temporary filename pattern for mkstemp() based on dnpath. */
222 static char *
223 ldif_tempname( const struct berval *dnpath )
224 {
225         static const char suffix[] = "XXXXXX";
226         ber_len_t len = dnpath->bv_len;
227         char *name = SLAP_MALLOC( len + sizeof( suffix ) );
228
229         if ( name != NULL ) {
230                 AC_MEMCPY( name, dnpath->bv_val, len );
231                 strcpy( name + len, suffix );
232         }
233         return name;
234 }
235
236 /*
237  * Read a file, or stat() it if datap == NULL.  Allocate and fill *datap.
238  * Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error.
239  */
240 static int
241 ldif_read_file( const char *path, char **datap )
242 {
243         int rc, fd, len;
244         int res = -1;   /* 0:success, <0:error, >0:file too big/growing. */
245         struct stat st;
246         char *data = NULL, *ptr;
247
248         if ( datap == NULL ) {
249                 res = stat( path, &st );
250                 goto done;
251         }
252         fd = open( path, O_RDONLY );
253         if ( fd >= 0 ) {
254                 if ( fstat( fd, &st ) == 0 ) {
255                         if ( st.st_size > INT_MAX - 2 ) {
256                                 res = 1;
257                         } else {
258                                 len = st.st_size + 1; /* +1 detects file size > st.st_size */
259                                 *datap = data = ptr = SLAP_MALLOC( len + 1 );
260                                 if ( ptr != NULL ) {
261                                         while ( len && (res = read( fd, ptr, len )) ) {
262                                                 if ( res > 0 ) {
263                                                         len -= res;
264                                                         ptr += res;
265                                                 } else if ( errno != EINTR ) {
266                                                         break;
267                                                 }
268                                         }
269                                         *ptr = '\0';
270                                 }
271                         }
272                 }
273                 if ( close( fd ) < 0 )
274                         res = -1;
275         }
276
277  done:
278         if ( res == 0 ) {
279                 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n",
280                         datap ? "read entry file" : "entry file exists", path, 0 );
281                 rc = LDAP_SUCCESS;
282         } else {
283                 if ( res < 0 && errno == ENOENT ) {
284                         Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
285                                 "no entry file \"%s\"\n", path, 0, 0 );
286                         rc = LDAP_NO_SUCH_OBJECT;
287                 } else {
288                         const char *msg = res < 0 ? STRERROR( errno ) : "bad stat() size";
289                         Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
290                                 msg, path, 0 );
291                         rc = LDAP_OTHER;
292                 }
293                 if ( data != NULL )
294                         SLAP_FREE( data );
295         }
296         return rc;
297 }
298
299 /*
300  * return nonnegative for success or -1 for error
301  * do not return numbers less than -1
302  */
303 static int
304 spew_file( int fd, const char *spew, int len, int *save_errno )
305 {
306         int writeres = 0;
307
308         while(len > 0) {
309                 writeres = write(fd, spew, len);
310                 if(writeres == -1) {
311                         *save_errno = errno;
312                         if (*save_errno != EINTR)
313                                 break;
314                 }
315                 else {
316                         spew += writeres;
317                         len -= writeres;
318                 }
319         }
320         return writeres;
321 }
322
323 static int
324 ldif_write_entry(
325         Operation *op,
326         Entry *e,
327         const struct berval *path,
328         const char **text )
329 {
330         int rc = LDAP_OTHER, res, save_errno = 0;
331         int fd, entry_length;
332         char *entry_as_string, *tmpfname;
333
334         tmpfname = ldif_tempname( path );
335         fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
336         if ( fd < 0 ) {
337                 save_errno = errno;
338                 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
339                         "cannot create file", e->e_dn, STRERROR( save_errno ) );
340
341         } else {
342                 ber_len_t dn_len = e->e_name.bv_len;
343                 struct berval rdn;
344
345                 /* Only save the RDN onto disk */
346                 dnRdn( &e->e_name, &rdn );
347                 if ( rdn.bv_len != dn_len ) {
348                         e->e_name.bv_val[rdn.bv_len] = '\0';
349                         e->e_name.bv_len = rdn.bv_len;
350                 }
351
352                 res = -2;
353                 ldap_pvt_thread_mutex_lock( &entry2str_mutex );
354                 entry_as_string = entry2str( e, &entry_length );
355                 if ( entry_as_string != NULL )
356                         res = spew_file( fd, entry_as_string, entry_length, &save_errno );
357                 ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
358
359                 /* Restore full DN */
360                 if ( rdn.bv_len != dn_len ) {
361                         e->e_name.bv_val[rdn.bv_len] = ',';
362                         e->e_name.bv_len = dn_len;
363                 }
364
365                 if ( close( fd ) < 0 && res >= 0 ) {
366                         res = -1;
367                         save_errno = errno;
368                 }
369
370                 if ( res >= 0 ) {
371                         if ( move_file( tmpfname, path->bv_val ) == 0 ) {
372                                 Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
373                                         "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 );
374                                 rc = LDAP_SUCCESS;
375                         } else {
376                                 save_errno = errno;
377                                 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
378                                         "could not put entry file for \"%s\" in place: %s\n",
379                                         e->e_name.bv_val, STRERROR( save_errno ), 0 );
380                         }
381                 } else if ( res == -1 ) {
382                         Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
383                                 "write error to", tmpfname, STRERROR( save_errno ) );
384                         *text = "internal error (write error to entry file)";
385                 }
386
387                 if ( rc != LDAP_SUCCESS ) {
388                         unlink( tmpfname );
389                 }
390         }
391
392         if ( rc == LDAP_OTHER && save_errno == ENOENT )
393                 rc = LDAP_NO_SUCH_OBJECT;
394
395         if ( tmpfname )
396                 SLAP_FREE( tmpfname );
397         return rc;
398 }
399
400 /*
401  * Read the entry at path, or if entryp==NULL just see if it exists.
402  * pdn and pndn are the parent's DN and normalized DN, or both NULL.
403  * Return an LDAP result code.
404  */
405 static int
406 ldif_read_entry(
407         Operation *op,
408         const char *path,
409         struct berval *pdn,
410         struct berval *pndn,
411         Entry **entryp,
412         const char **text )
413 {
414         int rc;
415         Entry *entry;
416         char *entry_as_string;
417         struct berval rdn;
418
419         rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
420
421         switch ( rc ) {
422         case LDAP_SUCCESS:
423                 if ( entryp == NULL )
424                         break;
425                 *entryp = entry = str2entry( entry_as_string );
426                 SLAP_FREE( entry_as_string );
427                 if ( entry == NULL ) {
428                         rc = LDAP_OTHER;
429                         if ( text != NULL )
430                                 *text = "internal error (cannot parse some entry file)";
431                         break;
432                 }
433                 if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
434                         break;
435                 /* Append parent DN to DN from LDIF file */
436                 rdn = entry->e_name;
437                 build_new_dn( &entry->e_name, pdn, &rdn, NULL );
438                 SLAP_FREE( rdn.bv_val );
439                 rdn = entry->e_nname;
440                 build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
441                 SLAP_FREE( rdn.bv_val );
442                 break;
443
444         case LDAP_OTHER:
445                 if ( text != NULL )
446                         *text = entryp
447                                 ? "internal error (cannot read some entry file)"
448                                 : "internal error (cannot stat some entry file)";
449                 break;
450         }
451
452         return rc;
453 }
454
455 /*
456  * Read the operation's entry, or if entryp==NULL just see if it exists.
457  * Return an LDAP result code.  May set *text to a message on failure.
458  * If pathp is non-NULL, set it to the entry filename on success.
459  */
460 static int
461 get_entry(
462         Operation *op,
463         Entry **entryp,
464         struct berval *pathp,
465         const char **text )
466 {
467         int rc;
468         struct berval path, pdn, pndn;
469
470         dnParent(&op->o_req_dn, &pdn);
471         dnParent(&op->o_req_ndn, &pndn);
472         dn2path( op->o_bd, &op->o_req_ndn, &path );
473         rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
474
475         if ( rc == LDAP_SUCCESS && pathp != NULL ) {
476                 *pathp = path;
477         } else {
478                 SLAP_FREE(path.bv_val);
479         }
480         return rc;
481 }
482
483 static void fullpath(struct berval *base, struct berval *name, struct berval *res) {
484         char *ptr;
485         res->bv_len = name->bv_len + base->bv_len + 1;
486         res->bv_val = ch_malloc( res->bv_len + 1 );
487         strcpy(res->bv_val, base->bv_val);
488         ptr = res->bv_val + base->bv_len;
489         *ptr++ = LDAP_DIRSEP[0];
490         strcpy(ptr, name->bv_val);
491 }
492
493 typedef struct bvlist {
494         struct bvlist *next;
495         struct berval bv;
496         struct berval num;
497         int inum;
498         int off;
499 } bvlist;
500
501
502 static int r_enum_tree(enumCookie *ck, struct berval *path, int base,
503         struct berval *pdn, struct berval *pndn)
504 {
505         Entry *e = NULL;
506         int fd = 0, rc = LDAP_SUCCESS;
507
508         if ( !base ) {
509                 rc = ldif_read_entry( ck->op, path->bv_val, pdn, pndn, &e,
510                         ck->rs == NULL ? NULL : &ck->rs->sr_text );
511                 if ( rc != LDAP_SUCCESS ) {
512                         return LDAP_NO_SUCH_OBJECT;
513                 }
514
515                 if ( ck->op->ors_scope == LDAP_SCOPE_BASE ||
516                         ck->op->ors_scope == LDAP_SCOPE_SUBTREE ) {
517                         /* Send right away? */
518                         if ( ck->rs ) {
519                                 /*
520                                  * if it's a referral, add it to the list of referrals. only do
521                                  * this for non-base searches, and don't check the filter
522                                  * explicitly here since it's only a candidate anyway.
523                                  */
524                                 if ( !get_manageDSAit( ck->op )
525                                                 && ck->op->ors_scope != LDAP_SCOPE_BASE
526                                                 && is_entry_referral( e ) )
527                                 {
528                                         BerVarray erefs = get_entry_referrals( ck->op, e );
529                                         ck->rs->sr_ref = referral_rewrite( erefs,
530                                                         &e->e_name, NULL,
531                                                         ck->op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL
532                                                                 ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );
533         
534                                         ck->rs->sr_entry = e;
535                                         rc = send_search_reference( ck->op, ck->rs );
536                                         ber_bvarray_free( ck->rs->sr_ref );
537                                         ber_bvarray_free( erefs );
538                                         ck->rs->sr_ref = NULL;
539                                         ck->rs->sr_entry = NULL;
540         
541                                 } else if ( test_filter( ck->op, e, ck->op->ors_filter ) == LDAP_COMPARE_TRUE )
542                                 {
543                                         ck->rs->sr_entry = e;
544                                         ck->rs->sr_attrs = ck->op->ors_attrs;
545                                         ck->rs->sr_flags = REP_ENTRY_MODIFIABLE;
546                                         rc = send_search_entry(ck->op, ck->rs);
547                                         ck->rs->sr_entry = NULL;
548                                 }
549                                 fd = 1;
550                                 if ( rc )
551                                         goto done;
552                         } else {
553                         /* Queueing up for tool mode */
554                                 if(ck->entries == NULL) {
555                                         ck->entries = (Entry **) ch_malloc(sizeof(Entry *) * ENTRY_BUFF_INCREMENT);
556                                         ck->elen = ENTRY_BUFF_INCREMENT;
557                                 }
558                                 if(ck->eind >= ck->elen) { /* grow entries if necessary */      
559                                         ck->entries = (Entry **) ch_realloc(ck->entries, sizeof(Entry *) * (ck->elen) * 2);
560                                         ck->elen *= 2;
561                                 }
562         
563                                 ck->entries[ck->eind++] = e;
564                                 fd = 0;
565                         }
566                 } else {
567                         fd = 1;
568                 }
569         }
570
571         if ( ck->op->ors_scope != LDAP_SCOPE_BASE ) {
572                 DIR * dir_of_path;
573                 bvlist *list = NULL, *ptr;
574
575                 path->bv_len -= STRLENOF( LDIF );
576                 path->bv_val[path->bv_len] = '\0';
577
578                 dir_of_path = opendir(path->bv_val);
579                 if(dir_of_path == NULL) { /* can't open directory */
580                         if ( errno != ENOENT ) {
581                                 /* it shouldn't be treated as an error
582                                  * only if the directory doesn't exist */
583                                 rc = LDAP_BUSY;
584                                 Debug( LDAP_DEBUG_ANY,
585                                         "=> ldif_enum_tree: failed to opendir %s (%d)\n",
586                                         path->bv_val, errno, 0 );
587                         }
588                         goto done;
589                 }
590         
591                 while(1) {
592                         struct berval fname, itmp;
593                         struct dirent * dir;
594                         bvlist *bvl, **prev;
595
596                         dir = readdir(dir_of_path);
597                         if(dir == NULL) break; /* end of the directory */
598                         fname.bv_len = strlen( dir->d_name );
599                         if ( fname.bv_len <= STRLENOF( LDIF ))
600                                 continue;
601                         if ( strcmp( dir->d_name + (fname.bv_len - STRLENOF(LDIF)), LDIF))
602                                 continue;
603                         fname.bv_val = dir->d_name;
604
605                         bvl = ch_malloc( sizeof(bvlist) );
606                         ber_dupbv( &bvl->bv, &fname );
607                         BER_BVZERO( &bvl->num );
608                         itmp.bv_val = ber_bvchr( &bvl->bv, IX_FSL );
609                         if ( itmp.bv_val ) {
610                                 char *ptr;
611                                 itmp.bv_val++;
612                                 itmp.bv_len = bvl->bv.bv_len
613                                         - ( itmp.bv_val - bvl->bv.bv_val );
614                                 ptr = ber_bvchr( &itmp, IX_FSR );
615                                 if ( ptr ) {
616                                         itmp.bv_len = ptr - itmp.bv_val;
617                                         ber_dupbv( &bvl->num, &itmp );
618                                         bvl->inum = strtol( itmp.bv_val, NULL, 0 );
619                                         itmp.bv_val[0] = '\0';
620                                         bvl->off = itmp.bv_val - bvl->bv.bv_val;
621                                 }
622                         }
623
624                         for (prev = &list; (ptr = *prev) != NULL; prev = &ptr->next) {
625                                 int cmp = strcmp( bvl->bv.bv_val, ptr->bv.bv_val );
626                                 if ( !cmp && bvl->num.bv_val )
627                                         cmp = bvl->inum - ptr->inum;
628                                 if ( cmp < 0 )
629                                         break;
630                         }
631                         *prev = bvl;
632                         bvl->next = ptr;
633                                 
634                 }
635                 closedir(dir_of_path);
636
637                 if (ck->op->ors_scope == LDAP_SCOPE_ONELEVEL)
638                         ck->op->ors_scope = LDAP_SCOPE_BASE;
639                 else if ( ck->op->ors_scope == LDAP_SCOPE_SUBORDINATE)
640                         ck->op->ors_scope = LDAP_SCOPE_SUBTREE;
641
642                 while ( ( ptr = list ) ) {
643                         struct berval fpath;
644
645                         list = ptr->next;
646
647                         if ( rc == LDAP_SUCCESS ) {
648                                 if ( ptr->num.bv_val )
649                                         AC_MEMCPY( ptr->bv.bv_val + ptr->off, ptr->num.bv_val,
650                                                 ptr->num.bv_len );
651                                 fullpath( path, &ptr->bv, &fpath );
652                                 rc = r_enum_tree(ck, &fpath, 0,
653                                         e != NULL ? &e->e_name : pdn,
654                                         e != NULL ? &e->e_nname : pndn );
655                                 free(fpath.bv_val);
656                         }
657                         if ( ptr->num.bv_val )
658                                 free( ptr->num.bv_val );
659                         free(ptr->bv.bv_val);
660                         free(ptr);
661                 }
662         }
663 done:
664         if ( fd ) entry_free( e );
665         return rc;
666 }
667
668 static int
669 enum_tree(
670         enumCookie *ck
671 )
672 {
673         struct berval path;
674         struct berval pdn, pndn;
675         int rc;
676
677         dnParent( &ck->op->o_req_dn, &pdn );
678         dnParent( &ck->op->o_req_ndn, &pndn );
679         dn2path( ck->op->o_bd, &ck->op->o_req_ndn, &path );
680         rc = r_enum_tree(ck, &path, BER_BVISEMPTY( &ck->op->o_req_ndn ) ? 1 : 0, &pdn, &pndn);
681         ch_free( path.bv_val );
682         return rc;
683 }
684
685
686 /* Get the parent directory path, plus the LDIF suffix overwritten by a \0 */
687 static void
688 get_parent_path( struct berval *dnpath, struct berval *res )
689 {
690         int dnpathlen = dnpath->bv_len;
691         int i;
692         
693         for(i = dnpathlen;i>0;i--) /* find the first path seperator */
694                 if(dnpath->bv_val[i] == LDAP_DIRSEP[0])
695                         break;
696         res->bv_len = i;
697         res->bv_val = ch_malloc( res->bv_len + 1 + STRLENOF(LDIF) );
698         strncpy(res->bv_val, dnpath->bv_val, i);
699         strcpy(res->bv_val+i, LDIF);
700         res->bv_val[i] = '\0';
701 }
702
703 static int apply_modify_to_entry(Entry * entry,
704                                 Modifications * modlist,
705                                 Operation * op,
706                                 SlapReply * rs)
707 {
708         char textbuf[SLAP_TEXT_BUFLEN];
709         int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
710         int is_oc = 0;
711         Modification *mods;
712
713         if (!acl_check_modlist(op, entry, modlist)) {
714                 return LDAP_INSUFFICIENT_ACCESS;
715         }
716
717         for (; modlist != NULL; modlist = modlist->sml_next) {
718                 mods = &modlist->sml_mod;
719
720                 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
721                         is_oc = 1;
722                 }
723                 switch (mods->sm_op) {
724                 case LDAP_MOD_ADD:
725                         rc = modify_add_values(entry, mods,
726                                    get_permissiveModify(op),
727                                    &rs->sr_text, textbuf,
728                                    sizeof( textbuf ) );
729                         break;
730                                 
731                 case LDAP_MOD_DELETE:
732                         rc = modify_delete_values(entry, mods,
733                                 get_permissiveModify(op),
734                                 &rs->sr_text, textbuf,
735                                 sizeof( textbuf ) );
736                         break;
737                                 
738                 case LDAP_MOD_REPLACE:
739                         rc = modify_replace_values(entry, mods,
740                                  get_permissiveModify(op),
741                                  &rs->sr_text, textbuf,
742                                  sizeof( textbuf ) );
743                         break;
744
745                 case LDAP_MOD_INCREMENT:
746                         rc = modify_increment_values( entry,
747                                 mods, get_permissiveModify(op),
748                                 &rs->sr_text, textbuf,
749                                 sizeof( textbuf ) );
750                         break;
751
752                 case SLAP_MOD_SOFTADD:
753                         mods->sm_op = LDAP_MOD_ADD;
754                         rc = modify_add_values(entry, mods,
755                                    get_permissiveModify(op),
756                                    &rs->sr_text, textbuf,
757                                    sizeof( textbuf ) );
758                         mods->sm_op = SLAP_MOD_SOFTADD;
759                         if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
760                                 rc = LDAP_SUCCESS;
761                         }
762                         break;
763                 }
764                 if(rc != LDAP_SUCCESS) break;
765         }
766
767         if ( rc == LDAP_SUCCESS ) {
768                 rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
769                 if ( is_oc ) {
770                         entry->e_ocflags = 0;
771                 }
772                 /* check that the entry still obeys the schema */
773                 rc = entry_schema_check( op, entry, NULL, 0, 0,
774                           &rs->sr_text, textbuf, sizeof( textbuf ) );
775         }
776
777         return rc;
778 }
779
780 int
781 ldif_back_referrals( Operation *op, SlapReply *rs )
782 {
783         struct ldif_info        *li = NULL;
784         Entry                   *entry = NULL;
785         int                     rc = LDAP_SUCCESS;
786
787 #if 0
788         if ( op->o_tag == LDAP_REQ_SEARCH ) {
789                 /* let search take care of itself */
790                 return rc;
791         }
792 #endif
793
794         if ( get_manageDSAit( op ) ) {
795                 /* let op take care of DSA management */
796                 return rc;
797         }
798
799         if ( BER_BVISEMPTY( &op->o_req_ndn ) ) {
800                 /* the empty DN cannot be a referral */
801                 return rc;
802         }
803
804         li = (struct ldif_info *)op->o_bd->be_private;
805         ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
806         get_entry( op, &entry, NULL, &rs->sr_text );
807
808         /* no object is found for them */
809         if ( entry == NULL ) {
810                 struct berval   odn = op->o_req_dn;
811                 struct berval   ondn = op->o_req_ndn;
812                 struct berval   pndn = ondn;
813                 ber_len_t               min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
814
815                 if ( min_dnlen == 0 )
816                         min_dnlen = 1;     /* catch empty DN */
817
818                 for ( ; entry == NULL; ) {
819                         dnParent( &pndn, &pndn );
820                         if ( pndn.bv_len < min_dnlen ) {
821                                 break;
822                         }
823
824                         op->o_req_dn = pndn;
825                         op->o_req_ndn = pndn;
826
827                         get_entry( op, &entry, NULL, &rs->sr_text );
828                 }
829
830                 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
831
832                 op->o_req_dn = odn;
833                 op->o_req_ndn = ondn;
834
835                 rc = LDAP_SUCCESS;
836                 rs->sr_matched = NULL;
837                 if ( entry != NULL ) {
838                         Debug( LDAP_DEBUG_TRACE,
839                                 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
840                                 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val );
841
842                         if ( is_entry_referral( entry ) ) {
843                                 rc = LDAP_OTHER;
844                                 rs->sr_ref = get_entry_referrals( op, entry );
845                                 if ( rs->sr_ref ) {
846                                         rs->sr_matched = ber_strdup_x(
847                                         entry->e_name.bv_val, op->o_tmpmemctx );
848                                 }
849                         }
850
851                         entry_free(entry);
852
853                 } else if ( default_referral != NULL ) {
854                         rc = LDAP_OTHER;
855                         rs->sr_ref = referral_rewrite( default_referral,
856                                 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
857                 }
858
859                 if ( rs->sr_ref != NULL ) {
860                         /* send referrals */
861                         rc = rs->sr_err = LDAP_REFERRAL;
862                         send_ldap_result( op, rs );
863                         ber_bvarray_free( rs->sr_ref );
864                         rs->sr_ref = NULL;
865
866                 } else if ( rc != LDAP_SUCCESS ) {
867                         rs->sr_text = rs->sr_matched ? "bad referral object" : NULL;
868                 }
869
870                 if ( rs->sr_matched ) {
871                         op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
872                         rs->sr_matched = NULL;
873                 }
874
875                 return rc;
876         }
877
878         ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
879
880         if ( is_entry_referral( entry ) ) {
881                 /* entry is a referral */
882                 BerVarray refs = get_entry_referrals( op, entry );
883                 rs->sr_ref = referral_rewrite(
884                         refs, &entry->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
885
886                 Debug( LDAP_DEBUG_TRACE,
887                         "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
888                         (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val );
889
890                 rs->sr_matched = entry->e_name.bv_val;
891                 if ( rs->sr_ref != NULL ) {
892                         rc = rs->sr_err = LDAP_REFERRAL;
893                         send_ldap_result( op, rs );
894                         ber_bvarray_free( rs->sr_ref );
895                         rs->sr_ref = NULL;
896
897                 } else {
898                         rc = LDAP_OTHER;
899                         rs->sr_text = "bad referral object";
900                 }
901
902                 rs->sr_matched = NULL;
903                 ber_bvarray_free( refs );
904         }
905
906         entry_free( entry );
907
908         return rc;
909 }
910
911
912 /* LDAP operations */
913
914 static int
915 ldif_back_bind( Operation *op, SlapReply *rs )
916 {
917         struct ldif_info *li;
918         Attribute *a;
919         AttributeDescription *password = slap_schema.si_ad_userPassword;
920         int return_val;
921         Entry *entry = NULL;
922
923         switch ( be_rootdn_bind( op, rs ) ) {
924         case SLAP_CB_CONTINUE:
925                 break;
926
927         default:
928                 /* in case of success, front end will send result;
929                  * otherwise, be_rootdn_bind() did */
930                 return rs->sr_err;
931         }
932
933         li = (struct ldif_info *) op->o_bd->be_private;
934         ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
935         return_val = get_entry(op, &entry, NULL, NULL);
936
937         /* no object is found for them */
938         if(return_val != LDAP_SUCCESS) {
939                 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
940                 goto return_result;
941         }
942
943         /* they don't have userpassword */
944         if((a = attr_find(entry->e_attrs, password)) == NULL) {
945                 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
946                 return_val = 1;
947                 goto return_result;
948         }
949
950         /* authentication actually failed */
951         if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
952                              &rs->sr_text) != 0) {
953                 rs->sr_err = LDAP_INVALID_CREDENTIALS;
954                 return_val = 1;
955                 goto return_result;
956         }
957
958         /* let the front-end send success */
959         return_val = 0;
960         goto return_result;
961
962  return_result:
963         ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
964         if(return_val != 0)
965                 send_ldap_result( op, rs );
966         if(entry != NULL)
967                 entry_free(entry);
968         return return_val;
969 }
970
971 static int ldif_back_search(Operation *op, SlapReply *rs)
972 {
973         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
974         enumCookie ck = { NULL, NULL, NULL, 0, 0 };
975
976         ck.op = op;
977         ck.rs = rs;
978         ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
979         rs->sr_err = enum_tree( &ck );
980         ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
981         send_ldap_result(op, rs);
982
983         return rs->sr_err;
984 }
985
986 static int ldif_back_add(Operation *op, SlapReply *rs) {
987         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
988         Entry * e = op->ora_e;
989         struct berval dn = e->e_nname;
990         struct berval leaf_path = BER_BVNULL;
991         struct stat stats;
992         int statres;
993         char textbuf[SLAP_TEXT_BUFLEN];
994
995         Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", dn.bv_val, 0, 0);
996
997         rs->sr_err = entry_schema_check(op, e, NULL, 0, 1,
998                 &rs->sr_text, textbuf, sizeof( textbuf ) );
999         if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
1000
1001         rs->sr_err = slap_add_opattrs( op,
1002                 &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
1003         if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
1004
1005         ldap_pvt_thread_rdwr_wlock(&li->li_rdwr);
1006
1007         dn2path( op->o_bd, &dn, &leaf_path );
1008
1009         if(leaf_path.bv_val != NULL) {
1010                 struct berval base = BER_BVNULL;
1011                 /* build path to container and ldif of container */
1012                 get_parent_path(&leaf_path, &base);
1013
1014                 statres = stat(base.bv_val, &stats); /* check if container exists */
1015                 if(statres == -1 && errno == ENOENT) { /* container missing */
1016                         base.bv_val[base.bv_len] = LDIF_FILETYPE_SEP;
1017                         statres = stat(base.bv_val, &stats); /* check for leaf node */
1018                         base.bv_val[base.bv_len] = '\0';
1019                         if(statres == -1 && errno == ENOENT) {
1020                                 rs->sr_err = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
1021                                 rs->sr_text = "Parent does not exist";
1022                         }
1023                         else if(statres != -1) { /* create parent */
1024                                 int mkdirres = mkdir(base.bv_val, 0750);
1025                                 if(mkdirres == -1) {
1026                                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1027                                         rs->sr_text = "Could not create parent folder";
1028                                         Debug( LDAP_DEBUG_ANY, "could not create folder \"%s\": %s\n",
1029                                                 base.bv_val, STRERROR( errno ), 0 );
1030                                 }
1031                         }
1032                         else
1033                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1034                 }/* container was possibly created, move on to add the entry */
1035                 if(rs->sr_err == LDAP_SUCCESS) {
1036                         statres = stat(leaf_path.bv_val, &stats);
1037                         if(statres == -1 && errno == ENOENT) {
1038                                 rs->sr_err = ldif_write_entry( op, e, &leaf_path, &rs->sr_text );
1039                         }
1040                         else if ( statres == -1 ) {
1041                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1042                                 Debug( LDAP_DEBUG_ANY, "could not stat file \"%s\": %s\n",
1043                                         leaf_path.bv_val, STRERROR( errno ), 0 );
1044                         }
1045                         else /* it already exists */
1046                                 rs->sr_err = LDAP_ALREADY_EXISTS;
1047                 }
1048                 SLAP_FREE(base.bv_val);
1049                 SLAP_FREE(leaf_path.bv_val);
1050         }
1051
1052         ldap_pvt_thread_rdwr_wunlock(&li->li_rdwr);
1053
1054 send_res:
1055         Debug( LDAP_DEBUG_TRACE, 
1056                         "ldif_back_add: err: %d text: %s\n", rs->sr_err, rs->sr_text ?
1057                                 rs->sr_text : "", 0);
1058         send_ldap_result(op, rs);
1059         slap_graduate_commit_csn( op );
1060         return rs->sr_err;
1061 }
1062
1063 static int ldif_back_modify(Operation *op, SlapReply *rs) {
1064         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1065         Modifications * modlst = op->orm_modlist;
1066         struct berval path;
1067         Entry *entry;
1068         int rc;
1069
1070         slap_mods_opattrs( op, &op->orm_modlist, 1 );
1071
1072         ldap_pvt_thread_rdwr_wlock(&li->li_rdwr);
1073
1074         rc = get_entry( op, &entry, &path, &rs->sr_text );
1075         if ( rc == LDAP_SUCCESS ) {
1076                 rc = apply_modify_to_entry( entry, modlst, op, rs );
1077                 if ( rc == LDAP_SUCCESS ) {
1078                         rc = ldif_write_entry( op, entry, &path, &rs->sr_text );
1079                 }
1080
1081                 entry_free( entry );
1082                 SLAP_FREE( path.bv_val );
1083         }
1084
1085         ldap_pvt_thread_rdwr_wunlock(&li->li_rdwr);
1086
1087         rs->sr_err = rc;
1088         send_ldap_result( op, rs );
1089         slap_graduate_commit_csn( op );
1090         return rs->sr_err;
1091 }
1092
1093 static int
1094 ldif_back_delete( Operation *op, SlapReply *rs )
1095 {
1096         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1097         struct berval path;
1098         int rc = LDAP_SUCCESS;
1099         int res = 0;
1100
1101         if ( BER_BVISEMPTY( &op->o_csn )) {
1102                 struct berval csn;
1103                 char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
1104
1105                 csn.bv_val = csnbuf;
1106                 csn.bv_len = sizeof( csnbuf );
1107                 slap_get_csn( op, &csn, 1 );
1108         }
1109
1110         ldap_pvt_thread_rdwr_wlock(&li->li_rdwr);
1111
1112         dn2path( op->o_bd, &op->o_req_ndn, &path );
1113         path.bv_val[path.bv_len - STRLENOF(LDIF)] = '\0';
1114         res = rmdir(path.bv_val);
1115         path.bv_val[path.bv_len - STRLENOF(LDIF)] = LDIF_FILETYPE_SEP;
1116         if ( res ) {
1117                 switch ( errno ) {
1118                 case ENOTEMPTY:
1119                         rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1120                         break;
1121                 case ENOENT:
1122                         /* is leaf, go on */
1123                         break;
1124                 default:
1125                         rc = LDAP_OTHER;
1126                         rs->sr_text = "internal error (cannot delete subtree directory)";
1127                         break;
1128                 }
1129         }
1130
1131         if ( rc == LDAP_SUCCESS ) {
1132                 res = unlink(path.bv_val);
1133                 if ( res == -1 ) {
1134                         rc = LDAP_NO_SUCH_OBJECT;
1135                         if ( errno != ENOENT ) {
1136                                 rc = LDAP_OTHER;
1137                                 rs->sr_text = "internal error (cannot delete entry file)";
1138                         }
1139                 }
1140         }
1141
1142         SLAP_FREE(path.bv_val);
1143         ldap_pvt_thread_rdwr_wunlock(&li->li_rdwr);
1144         rs->sr_err = rc;
1145         send_ldap_result( op, rs );
1146         slap_graduate_commit_csn( op );
1147         return rs->sr_err;
1148 }
1149
1150
1151 static int
1152 ldif_move_entry(
1153         Operation *op,
1154         Entry *entry,
1155         struct berval *oldpath,
1156         const char **text )
1157 {
1158         int res;
1159         int exists_res;
1160         struct berval newpath;
1161
1162         dn2path( op->o_bd, &entry->e_nname, &newpath );
1163
1164         if((entry == NULL || oldpath->bv_val == NULL) || newpath.bv_val == NULL) {
1165                 /* some object doesn't exist */
1166                 res = LDAP_NO_SUCH_OBJECT;
1167         }
1168         else { /* do the modrdn */
1169                 exists_res = open(newpath.bv_val, O_RDONLY);
1170                 if(exists_res == -1 && errno == ENOENT) {
1171                         res = ldif_write_entry( op, entry, &newpath, text );
1172                         if ( res == LDAP_SUCCESS ) {
1173                                 /* if this fails we should log something bad */
1174                                 res = unlink( oldpath->bv_val );
1175                                 oldpath->bv_val[oldpath->bv_len - STRLENOF(".ldif")] = '\0';
1176                                 newpath.bv_val[newpath.bv_len - STRLENOF(".ldif")] = '\0';
1177                                 res = rename( oldpath->bv_val, newpath.bv_val );
1178                                 res = LDAP_SUCCESS;
1179                         }
1180                 }
1181                 else if(exists_res) {
1182                         int close_res = close(exists_res);
1183                         res = LDAP_ALREADY_EXISTS;
1184                         if(close_res == -1) {
1185                         /* log heinous error */
1186                         }
1187                 }
1188                 else {
1189                         res = LDAP_UNWILLING_TO_PERFORM;
1190                 }
1191         }
1192
1193         if(newpath.bv_val != NULL)
1194                 SLAP_FREE(newpath.bv_val);
1195         return res;
1196 }
1197
1198 static int
1199 ldif_back_modrdn(Operation *op, SlapReply *rs)
1200 {
1201         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1202         struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1203         struct berval p_dn, old_path;
1204         Entry *entry;
1205         int rc;
1206
1207         slap_mods_opattrs( op, &op->orr_modlist, 1 );
1208
1209         ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1210
1211         rc = get_entry( op, &entry, &old_path, &rs->sr_text );
1212         if ( rc == LDAP_SUCCESS ) {
1213                 /* build new dn, and new ndn for the entry */
1214                 if ( op->oq_modrdn.rs_newSup != NULL ) {
1215                         struct berval   op_dn = op->o_req_dn,
1216                                         op_ndn = op->o_req_ndn;
1217                         Entry           *np;
1218
1219                         /* new superior */
1220                         p_dn = *op->oq_modrdn.rs_newSup;
1221                         op->o_req_dn = *op->oq_modrdn.rs_newSup;
1222                         op->o_req_ndn = *op->oq_modrdn.rs_nnewSup;
1223                         rc = get_entry( op, &np, NULL, &rs->sr_text );
1224                         op->o_req_dn = op_dn;
1225                         op->o_req_ndn = op_ndn;
1226                         if ( rc != LDAP_SUCCESS ) {
1227                                 goto no_such_object;
1228                         }
1229                         entry_free( np );
1230                 } else {
1231                         dnParent( &entry->e_name, &p_dn );
1232                 }
1233                 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL ); 
1234                 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1235                 ber_memfree_x( entry->e_name.bv_val, NULL );
1236                 ber_memfree_x( entry->e_nname.bv_val, NULL );
1237                 entry->e_name = new_dn;
1238                 entry->e_nname = new_ndn;
1239
1240                 /* perform the modifications */
1241                 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs );
1242                 if ( rc == LDAP_SUCCESS )
1243                         rc = ldif_move_entry( op, entry, &old_path, &rs->sr_text );
1244
1245 no_such_object:;
1246                 entry_free( entry );
1247                 SLAP_FREE( old_path.bv_val );
1248         }
1249
1250         ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1251         rs->sr_err = rc;
1252         send_ldap_result( op, rs );
1253         slap_graduate_commit_csn( op );
1254         return rs->sr_err;
1255 }
1256
1257
1258 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1259 static int
1260 ldif_back_entry_get(
1261         Operation *op,
1262         struct berval *ndn,
1263         ObjectClass *oc,
1264         AttributeDescription *at,
1265         int rw,
1266         Entry **e )
1267 {
1268         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1269         struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1270         int rc;
1271
1272         assert( ndn != NULL );
1273         assert( !BER_BVISNULL( ndn ) );
1274
1275         ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1276         op->o_req_dn = *ndn;
1277         op->o_req_ndn = *ndn;
1278         rc = get_entry( op, e, NULL, NULL );
1279         op->o_req_dn = op_dn;
1280         op->o_req_ndn = op_ndn;
1281         ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1282
1283         if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1284                 rc = LDAP_NO_SUCH_ATTRIBUTE;
1285                 entry_free( *e );
1286                 *e = NULL;
1287         }
1288
1289         return rc;
1290 }
1291
1292
1293 /* Slap tools */
1294
1295 static int ldif_tool_entry_open(BackendDB *be, int mode) {
1296         struct ldif_info *li = (struct ldif_info *) be->be_private;
1297         li->li_tool_current = 0;
1298         return 0;
1299 }                                       
1300
1301 static int ldif_tool_entry_close(BackendDB * be) {
1302         struct ldif_info *li = (struct ldif_info *) be->be_private;
1303
1304         SLAP_FREE(li->li_tool_cookie.entries);
1305         return 0;
1306 }
1307
1308 static ID ldif_tool_entry_next(BackendDB *be)
1309 {
1310         struct ldif_info *li = (struct ldif_info *) be->be_private;
1311         if(li->li_tool_current >= li->li_tool_cookie.eind)
1312                 return NOID;
1313         else
1314                 return ++li->li_tool_current;
1315 }
1316
1317 static ID
1318 ldif_tool_entry_first(BackendDB *be)
1319 {
1320         struct ldif_info *li = (struct ldif_info *) be->be_private;
1321
1322         if(li->li_tool_cookie.entries == NULL) {
1323                 Operation op = {0};
1324
1325                 op.o_bd = be;
1326                 op.o_req_dn = *be->be_suffix;
1327                 op.o_req_ndn = *be->be_nsuffix;
1328                 op.ors_scope = LDAP_SCOPE_SUBTREE;
1329                 li->li_tool_cookie.op = &op;
1330                 (void)enum_tree( &li->li_tool_cookie );
1331                 li->li_tool_cookie.op = NULL;
1332         }
1333         return ldif_tool_entry_next( be );
1334 }
1335
1336 static Entry * ldif_tool_entry_get(BackendDB * be, ID id) {
1337         struct ldif_info *li = (struct ldif_info *) be->be_private;
1338         Entry * e;
1339
1340         if(id > li->li_tool_cookie.eind || id < 1)
1341                 return NULL;
1342         else {
1343                 e = li->li_tool_cookie.entries[id - 1];
1344                 li->li_tool_cookie.entries[id - 1] = NULL;
1345                 return e;
1346         }
1347 }
1348
1349 static ID
1350 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1351 {
1352         int rc;
1353         const char *errmsg = NULL;
1354         struct berval leaf_path = BER_BVNULL;
1355         struct stat stats;
1356         int statres;
1357         int res = LDAP_SUCCESS;
1358         Operation op = {0};
1359
1360         dn2path( be, &e->e_nname, &leaf_path );
1361
1362         if(leaf_path.bv_val != NULL) {
1363                 struct berval base = BER_BVNULL;
1364                 /* build path to container, and path to ldif of container */
1365                 get_parent_path(&leaf_path, &base);
1366
1367                 statres = stat(base.bv_val, &stats); /* check if container exists */
1368                 if(statres == -1 && errno == ENOENT) { /* container missing */
1369                         base.bv_val[base.bv_len] = LDIF_FILETYPE_SEP;
1370                         statres = stat(base.bv_val, &stats); /* check for leaf node */
1371                         base.bv_val[base.bv_len] = '\0';
1372                         if(statres == -1 && errno == ENOENT) {
1373                                 res = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
1374                         }
1375                         else if(statres != -1) { /* create parent */
1376                                 int mkdirres = mkdir(base.bv_val, 0750);
1377                                 if(mkdirres == -1) {
1378                                         res = LDAP_UNWILLING_TO_PERFORM;
1379                                 }
1380                         }
1381                         else
1382                                 res = LDAP_UNWILLING_TO_PERFORM;
1383                 }/* container was possibly created, move on to add the entry */
1384                 if(res == LDAP_SUCCESS) {
1385                         statres = stat(leaf_path.bv_val, &stats);
1386                         if(statres == -1 && errno == ENOENT) {
1387                                 res = ldif_write_entry( &op, e, &leaf_path, &errmsg );
1388                         }
1389                         else /* it already exists */
1390                                 res = LDAP_ALREADY_EXISTS;
1391                 }
1392                 SLAP_FREE(base.bv_val);
1393                 SLAP_FREE(leaf_path.bv_val);
1394         }
1395
1396         if(res == LDAP_SUCCESS) {
1397                 return 1;
1398         }
1399         rc = res;
1400         if ( errmsg == NULL && rc != LDAP_OTHER )
1401                 errmsg = ldap_err2string( rc );
1402         if ( errmsg != NULL )
1403                 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1404         return NOID;
1405 }
1406
1407
1408 /* Setup */
1409
1410 static int
1411 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1412 {
1413         struct ldif_info *li;
1414
1415         li = ch_calloc( 1, sizeof(struct ldif_info) );
1416         be->be_private = li;
1417         be->be_cf_ocs = ldifocs;
1418         ldap_pvt_thread_rdwr_init(&li->li_rdwr);
1419         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1420         return 0;
1421 }
1422
1423 static int
1424 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1425 {
1426         struct ldif_info *li = be->be_private;
1427
1428         ch_free(li->li_base_path.bv_val);
1429         ldap_pvt_thread_rdwr_destroy(&li->li_rdwr);
1430         free( be->be_private );
1431         return 0;
1432 }
1433
1434 static int
1435 ldif_back_db_open( Backend *be, ConfigReply *cr)
1436 {
1437         struct ldif_info *li = (struct ldif_info *) be->be_private;
1438         if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1439                 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1440                 return 1;
1441         }
1442         return 0;
1443 }
1444
1445 int
1446 ldif_back_initialize(
1447                            BackendInfo  *bi
1448                            )
1449 {
1450         static char *controls[] = {
1451                 LDAP_CONTROL_MANAGEDSAIT,
1452                 NULL
1453         };
1454         int rc;
1455
1456         bi->bi_flags |=
1457                 SLAP_BFLAG_INCREMENT |
1458                 SLAP_BFLAG_REFERRALS;
1459
1460         bi->bi_controls = controls;
1461
1462         bi->bi_open = 0;
1463         bi->bi_close = 0;
1464         bi->bi_config = 0;
1465         bi->bi_destroy = 0;
1466
1467         bi->bi_db_init = ldif_back_db_init;
1468         bi->bi_db_config = config_generic_wrapper;
1469         bi->bi_db_open = ldif_back_db_open;
1470         bi->bi_db_close = 0;
1471         bi->bi_db_destroy = ldif_back_db_destroy;
1472
1473         bi->bi_op_bind = ldif_back_bind;
1474         bi->bi_op_unbind = 0;
1475         bi->bi_op_search = ldif_back_search;
1476         bi->bi_op_compare = 0;
1477         bi->bi_op_modify = ldif_back_modify;
1478         bi->bi_op_modrdn = ldif_back_modrdn;
1479         bi->bi_op_add = ldif_back_add;
1480         bi->bi_op_delete = ldif_back_delete;
1481         bi->bi_op_abandon = 0;
1482
1483         bi->bi_extended = 0;
1484
1485         bi->bi_chk_referrals = ldif_back_referrals;
1486
1487         bi->bi_connection_init = 0;
1488         bi->bi_connection_destroy = 0;
1489
1490         bi->bi_entry_get_rw = ldif_back_entry_get;
1491
1492 #if 0   /* NOTE: uncomment to completely disable access control */
1493         bi->bi_access_allowed = slap_access_always_allowed;
1494 #endif
1495
1496         bi->bi_tool_entry_open = ldif_tool_entry_open;
1497         bi->bi_tool_entry_close = ldif_tool_entry_close;
1498         bi->bi_tool_entry_first = ldif_tool_entry_first;
1499         bi->bi_tool_entry_next = ldif_tool_entry_next;
1500         bi->bi_tool_entry_get = ldif_tool_entry_get;
1501         bi->bi_tool_entry_put = ldif_tool_entry_put;
1502         bi->bi_tool_entry_reindex = 0;
1503         bi->bi_tool_sync = 0;
1504         
1505         bi->bi_tool_dn2id_get = 0;
1506         bi->bi_tool_entry_modify = 0;
1507
1508         bi->bi_cf_ocs = ldifocs;
1509
1510         rc = config_register_schema( ldifcfg, ldifocs );
1511         if ( rc ) return rc;
1512         return 0;
1513 }