]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldif/ldif.c
Merge remote-tracking branch 'origin/mdb.RE/0.9'
[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-2014 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 struct ldif_tool {
35         Entry   **entries;                      /* collected by bi_tool_entry_first() */
36         ID              elen;                           /* length of entries[] array */
37         ID              ecount;                         /* number of entries */
38         ID              ecurrent;                       /* bi_tool_entry_next() position */
39 #       define  ENTRY_BUFF_INCREMENT 500 /* initial entries[] length */
40         struct berval   *tl_base;
41         int             tl_scope;
42         Filter          *tl_filter;
43 };
44
45 /* Per-database data */
46 struct ldif_info {
47         struct berval li_base_path;                     /* database directory */
48         struct ldif_tool li_tool;                       /* for slap tools */
49         /*
50          * Read-only LDAP requests readlock li_rdwr for filesystem input.
51          * Update requests first lock li_modop_mutex for filesystem I/O,
52          * and then writelock li_rdwr as well for filesystem output.
53          * This allows update requests to do callbacks that acquire
54          * read locks, e.g. access controls that inspect entries.
55          * (An alternative would be recursive read/write locks.)
56          */
57         ldap_pvt_thread_mutex_t li_modop_mutex; /* serialize update requests */
58         ldap_pvt_thread_rdwr_t  li_rdwr;        /* no other I/O when writing */
59 };
60
61 static int write_data( int fd, const char *spew, int len, int *save_errno );
62
63 #ifdef _WIN32
64 #define mkdir(a,b)      mkdir(a)
65 #define move_file(from, to) (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
66 #else
67 #define move_file(from, to) rename(from, to)
68 #endif
69 #define move_dir(from, to) rename(from, to)
70
71
72 #define LDIF    ".ldif"
73 #define LDIF_FILETYPE_SEP       '.'                     /* LDIF[0] */
74
75 /*
76  * Unsafe/translated characters in the filesystem.
77  *
78  * LDIF_UNSAFE_CHAR(c) returns true if the character c is not to be used
79  * in relative filenames, except it should accept '\\', '{' and '}' even
80  * if unsafe.  The value should be a constant expression.
81  *
82  * If '\\' is unsafe, #define LDIF_ESCAPE_CHAR as a safe character.
83  * If '{' and '}' are unsafe, #define IX_FSL/IX_FSR as safe characters.
84  * (Not digits, '-' or '+'.  IX_FSL == IX_FSR is allowed.)
85  *
86  * Characters are escaped as LDIF_ESCAPE_CHAR followed by two hex digits,
87  * except '\\' is replaced with LDIF_ESCAPE_CHAR and {} with IX_FS[LR].
88  * Also some LDIF special chars are hex-escaped.
89  *
90  * Thus an LDIF filename is a valid normalized RDN (or suffix DN)
91  * followed by ".ldif", except with '\\' replaced with LDIF_ESCAPE_CHAR.
92  */
93
94 #ifndef _WIN32
95
96 /*
97  * Unix/MacOSX version.  ':' vs '/' can cause confusion on MacOSX so we
98  * escape both.  We escape them on Unix so both OS variants get the same
99  * filenames.
100  */
101 #define LDIF_ESCAPE_CHAR        '\\'
102 #define LDIF_UNSAFE_CHAR(c)     ((c) == '/' || (c) == ':')
103
104 #else /* _WIN32 */
105
106 /* Windows version - Microsoft's list of unsafe characters, except '\\' */
107 #define LDIF_ESCAPE_CHAR        '^'                     /* Not '\\' (unsafe on Windows) */
108 #define LDIF_UNSAFE_CHAR(c)     \
109         ((c) == '/' || (c) == ':' || \
110          (c) == '<' || (c) == '>' || (c) == '"' || \
111          (c) == '|' || (c) == '?' || (c) == '*')
112
113 #endif /* !_WIN32 */
114
115 /*
116  * Left and Right "{num}" prefix to ordered RDNs ("olcDatabase={1}bdb").
117  * IX_DN* are for LDAP RDNs, IX_FS* for their .ldif filenames.
118  */
119 #define IX_DNL  '{'
120 #define IX_DNR  '}'
121 #ifndef IX_FSL
122 #define IX_FSL  IX_DNL
123 #define IX_FSR  IX_DNR
124 #endif
125
126 /*
127  * Test for unsafe chars, as well as chars handled specially by back-ldif:
128  * - If the escape char is not '\\', it must itself be escaped.  Otherwise
129  *   '\\' and the escape char would map to the same character.
130  * - Escape the '.' in ".ldif", so the directory for an RDN that actually
131  *   ends with ".ldif" can not conflict with a file of the same name.  And
132  *   since some OSes/programs choke on multiple '.'s, escape all of them.
133  * - If '{' and '}' are translated to some other characters, those
134  *   characters must in turn be escaped when they occur in an RDN.
135  */
136 #ifndef LDIF_NEED_ESCAPE
137 #define LDIF_NEED_ESCAPE(c) \
138         ((LDIF_UNSAFE_CHAR(c)) || \
139          LDIF_MAYBE_UNSAFE(c, LDIF_ESCAPE_CHAR) || \
140          LDIF_MAYBE_UNSAFE(c, LDIF_FILETYPE_SEP) || \
141          LDIF_MAYBE_UNSAFE(c, IX_FSL) || \
142          (IX_FSR != IX_FSL && LDIF_MAYBE_UNSAFE(c, IX_FSR)))
143 #endif
144 /*
145  * Helper macro for LDIF_NEED_ESCAPE(): Treat character x as unsafe if
146  * back-ldif does not already treat is specially.
147  */
148 #define LDIF_MAYBE_UNSAFE(c, x) \
149         (!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \
150          && (c) == (x))
151
152 /* Collect other "safe char" tests here, until someone needs a fix. */
153 enum {
154         eq_unsafe = LDIF_UNSAFE_CHAR('='),
155         safe_filenames = STRLENOF("" LDAP_DIRSEP "") == 1 && !(
156                 LDIF_UNSAFE_CHAR('-') || /* for "{-1}frontend" in bconfig.c */
157                 LDIF_UNSAFE_CHAR(LDIF_ESCAPE_CHAR) ||
158                 LDIF_UNSAFE_CHAR(IX_FSL) || LDIF_UNSAFE_CHAR(IX_FSR))
159 };
160 /* Sanity check: Try to force a compilation error if !safe_filenames */
161 typedef struct {
162         int assert_safe_filenames : safe_filenames ? 2 : -2;
163 } assert_safe_filenames[safe_filenames ? 2 : -2];
164
165
166 static ConfigTable ldifcfg[] = {
167         { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
168                 (void *)offsetof(struct ldif_info, li_base_path),
169                 "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
170                         "DESC 'Directory for database content' "
171                         "EQUALITY caseIgnoreMatch "
172                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
173         { NULL, NULL, 0, 0, 0, ARG_IGNORED,
174                 NULL, NULL, NULL, NULL }
175 };
176
177 static ConfigOCs ldifocs[] = {
178         { "( OLcfgDbOc:2.1 "
179                 "NAME 'olcLdifConfig' "
180                 "DESC 'LDIF backend configuration' "
181                 "SUP olcDatabaseConfig "
182                 "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg },
183         { NULL, 0, NULL }
184 };
185
186
187 /*
188  * Handle file/directory names.
189  */
190
191 /* Set *res = LDIF filename path for the normalized DN */
192 static int
193 ndn2path( Operation *op, struct berval *dn, struct berval *res, int empty_ok )
194 {
195         BackendDB *be = op->o_bd;
196         struct ldif_info *li = (struct ldif_info *) be->be_private;
197         struct berval *suffixdn = &be->be_nsuffix[0];
198         const char *start, *end, *next, *p;
199         char ch, *ptr;
200         ber_len_t len;
201         static const char hex[] = "0123456789ABCDEF";
202
203         assert( dn != NULL );
204         assert( !BER_BVISNULL( dn ) );
205         assert( suffixdn != NULL );
206         assert( !BER_BVISNULL( suffixdn ) );
207         assert( dnIsSuffix( dn, suffixdn ) );
208
209         if ( dn->bv_len == 0 && !empty_ok ) {
210                 return LDAP_UNWILLING_TO_PERFORM;
211         }
212
213         start = dn->bv_val;
214         end = start + dn->bv_len;
215
216         /* Room for dir, dirsep, dn, LDIF, "\hexpair"-escaping of unsafe chars */
217         len = li->li_base_path.bv_len + dn->bv_len + (1 + STRLENOF( LDIF ));
218         for ( p = start; p < end; ) {
219                 ch = *p++;
220                 if ( LDIF_NEED_ESCAPE( ch ) )
221                         len += 2;
222         }
223         res->bv_val = ch_malloc( len + 1 );
224
225         ptr = lutil_strcopy( res->bv_val, li->li_base_path.bv_val );
226         for ( next = end - suffixdn->bv_len; end > start; end = next ) {
227                 /* Set p = start of DN component, next = &',' or start of DN */
228                 while ( (p = next) > start ) {
229                         --next;
230                         if ( DN_SEPARATOR( *next ) )
231                                 break;
232                 }
233                 /* Append <dirsep> <p..end-1: RDN or database-suffix> */
234                 for ( *ptr++ = LDAP_DIRSEP[0]; p < end; *ptr++ = ch ) {
235                         ch = *p++;
236                         if ( LDIF_ESCAPE_CHAR != '\\' && ch == '\\' ) {
237                                 ch = LDIF_ESCAPE_CHAR;
238                         } else if ( IX_FSL != IX_DNL && ch == IX_DNL ) {
239                                 ch = IX_FSL;
240                         } else if ( IX_FSR != IX_DNR && ch == IX_DNR ) {
241                                 ch = IX_FSR;
242                         } else if ( LDIF_NEED_ESCAPE( ch ) ) {
243                                 *ptr++ = LDIF_ESCAPE_CHAR;
244                                 *ptr++ = hex[(ch & 0xFFU) >> 4];
245                                 ch = hex[ch & 0x0FU];
246                         }
247                 }
248         }
249         ptr = lutil_strcopy( ptr, LDIF );
250         res->bv_len = ptr - res->bv_val;
251
252         assert( res->bv_len <= len );
253
254         return LDAP_SUCCESS;
255 }
256
257 /*
258  * *dest = dupbv(<dir + LDAP_DIRSEP>), plus room for <more>-sized filename.
259  * Return pointer past the dirname.
260  */
261 static char *
262 fullpath_alloc( struct berval *dest, const struct berval *dir, ber_len_t more )
263 {
264         char *s = SLAP_MALLOC( dir->bv_len + more + 2 );
265
266         dest->bv_val = s;
267         if ( s == NULL ) {
268                 dest->bv_len = 0;
269                 Debug( LDAP_DEBUG_ANY, "back-ldif: out of memory\n", 0, 0, 0 );
270         } else {
271                 s = lutil_strcopy( dest->bv_val, dir->bv_val );
272                 *s++ = LDAP_DIRSEP[0];
273                 *s = '\0';
274                 dest->bv_len = s - dest->bv_val;
275         }
276         return s;
277 }
278
279 /*
280  * Append filename to fullpath_alloc() dirname or replace previous filename.
281  * dir_end = fullpath_alloc() return value.
282  */
283 #define FILL_PATH(fpath, dir_end, filename) \
284         ((fpath)->bv_len = lutil_strcopy(dir_end, filename) - (fpath)->bv_val)
285
286
287 /* .ldif entry filename length <-> subtree dirname length. */
288 #define ldif2dir_len(bv)  ((bv).bv_len -= STRLENOF(LDIF))
289 #define dir2ldif_len(bv)  ((bv).bv_len += STRLENOF(LDIF))
290 /* .ldif entry filename <-> subtree dirname, both with dirname length. */
291 #define ldif2dir_name(bv) ((bv).bv_val[(bv).bv_len] = '\0')
292 #define dir2ldif_name(bv) ((bv).bv_val[(bv).bv_len] = LDIF_FILETYPE_SEP)
293
294 /* Get the parent directory path, plus the LDIF suffix overwritten by a \0. */
295 static int
296 get_parent_path( struct berval *dnpath, struct berval *res )
297 {
298         ber_len_t i = dnpath->bv_len;
299
300         while ( i > 0 && dnpath->bv_val[ --i ] != LDAP_DIRSEP[0] ) ;
301         if ( res == NULL ) {
302                 res = dnpath;
303         } else {
304                 res->bv_val = SLAP_MALLOC( i + 1 + STRLENOF(LDIF) );
305                 if ( res->bv_val == NULL )
306                         return LDAP_OTHER;
307                 AC_MEMCPY( res->bv_val, dnpath->bv_val, i );
308         }
309         res->bv_len = i;
310         strcpy( res->bv_val + i, LDIF );
311         res->bv_val[i] = '\0';
312         return LDAP_SUCCESS;
313 }
314
315 /* Make temporary filename pattern for mkstemp() based on dnpath. */
316 static char *
317 ldif_tempname( const struct berval *dnpath )
318 {
319         static const char suffix[] = ".XXXXXX";
320         ber_len_t len = dnpath->bv_len - STRLENOF( LDIF );
321         char *name = SLAP_MALLOC( len + sizeof( suffix ) );
322
323         if ( name != NULL ) {
324                 AC_MEMCPY( name, dnpath->bv_val, len );
325                 strcpy( name + len, suffix );
326         }
327         return name;
328 }
329
330 /* CRC-32 table for the polynomial:
331  * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
332  *
333  * As used by zlib
334  */
335
336 static const ber_uint_t crctab[256] = {
337         0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
338         0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
339         0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
340         0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
341         0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
342         0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
343         0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
344         0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
345         0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
346         0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
347         0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
348         0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
349         0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
350         0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
351         0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
352         0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
353         0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
354         0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
355         0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
356         0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
357         0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
358         0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
359         0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
360         0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
361         0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
362         0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
363         0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
364         0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
365         0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
366         0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
367         0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
368         0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
369         0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
370         0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
371         0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
372         0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
373         0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
374         0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
375         0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
376         0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
377         0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
378         0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
379         0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
380         0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
381         0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
382         0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
383         0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
384         0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
385         0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
386         0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
387         0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
388         0x2d02ef8dL
389 };
390
391 #define CRC1    crc = crctab[(crc ^ *buf++) & 0xff] ^ (crc >> 8)
392 #define CRC8    CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1
393 unsigned int
394 crc32(const void *vbuf, int len)
395 {
396         const unsigned char     *buf = vbuf;
397         ber_uint_t              crc = 0xffffffff;
398         int                             i;
399
400         while (len > 7) {
401                 CRC8;
402                 len -= 8;
403         }
404         while (len) {
405                 CRC1;
406                 len--;
407         }
408
409         return crc ^ 0xffffffff;
410 }
411
412 /*
413  * Read a file, or stat() it if datap == NULL.  Allocate and fill *datap.
414  * Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error.
415  */
416 static int
417 ldif_read_file( const char *path, char **datap )
418 {
419         int rc = LDAP_SUCCESS, fd, len;
420         int res = -1;   /* 0:success, <0:error, >0:file too big/growing. */
421         struct stat st;
422         char *data = NULL, *ptr = NULL;
423         const char *msg;
424
425         if ( datap == NULL ) {
426                 res = stat( path, &st );
427                 goto done;
428         }
429         fd = open( path, O_RDONLY );
430         if ( fd >= 0 ) {
431                 if ( fstat( fd, &st ) == 0 ) {
432                         if ( st.st_size > INT_MAX - 2 ) {
433                                 res = 1;
434                         } else {
435                                 len = st.st_size + 1; /* +1 detects file size > st.st_size */
436                                 *datap = data = ptr = SLAP_MALLOC( len + 1 );
437                                 if ( ptr != NULL ) {
438                                         while ( len && (res = read( fd, ptr, len )) ) {
439                                                 if ( res > 0 ) {
440                                                         len -= res;
441                                                         ptr += res;
442                                                 } else if ( errno != EINTR ) {
443                                                         break;
444                                                 }
445                                         }
446                                         *ptr = '\0';
447                                 }
448                         }
449                 }
450                 if ( close( fd ) < 0 )
451                         res = -1;
452         }
453
454  done:
455         if ( res == 0 ) {
456 #ifdef LDAP_DEBUG
457                 msg = "entry file exists";
458                 if ( datap ) {
459                         msg = "read entry file";
460                         len = ptr - data;
461                         ptr = strstr( data, "\n# CRC32" );
462                         if (!ptr) {
463                                 msg = "read entry file without checksum";
464                         } else {
465                                 unsigned int crc1 = 0, crc2 = 1;
466                                 if ( sscanf( ptr + 9, "%08x", &crc1) == 1) {
467                                         ptr = strchr(ptr+1, '\n');
468                                         if ( ptr ) {
469                                                 ptr++;
470                                                 len -= (ptr - data);
471                                                 crc2 = crc32( ptr, len );
472                                         }
473                                 }
474                                 if ( crc1 != crc2 ) {
475                                         Debug( LDAP_DEBUG_ANY, "ldif_read_file: checksum error on \"%s\"\n",
476                                                 path, 0, 0 );
477                                         return rc;
478                                 }
479                         }
480                 }
481                 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n", msg, path, 0 );
482 #endif /* LDAP_DEBUG */
483         } else {
484                 if ( res < 0 && errno == ENOENT ) {
485                         Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
486                                 "no entry file \"%s\"\n", path, 0, 0 );
487                         rc = LDAP_NO_SUCH_OBJECT;
488                 } else {
489                         msg = res < 0 ? STRERROR( errno ) : "bad stat() size";
490                         Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
491                                 msg, path, 0 );
492                         rc = LDAP_OTHER;
493                 }
494                 if ( data != NULL )
495                         SLAP_FREE( data );
496         }
497         return rc;
498 }
499
500 /*
501  * return nonnegative for success or -1 for error
502  * do not return numbers less than -1
503  */
504 static int
505 spew_file( int fd, const char *spew, int len, int *save_errno )
506 {
507         int writeres;
508 #define HEADER  "# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n"
509         char header[sizeof(HEADER "# CRC32 12345678\n")];
510
511         sprintf(header, HEADER "# CRC32 %08x\n", crc32(spew, len));
512         writeres = write_data(fd, header, sizeof(header)-1, save_errno);
513         return writeres < 0 ? writeres : write_data(fd, spew, len, save_errno);
514 }
515
516 static int
517 write_data( int fd, const char *spew, int len, int *save_errno )
518 {
519         int writeres = 0;
520         while(len > 0) {
521                 writeres = write(fd, spew, len);
522                 if(writeres == -1) {
523                         *save_errno = errno;
524                         if (*save_errno != EINTR)
525                                 break;
526                 }
527                 else {
528                         spew += writeres;
529                         len -= writeres;
530                 }
531         }
532         return writeres;
533 }
534
535 /* Write an entry LDIF file.  Create parentdir first if non-NULL. */
536 static int
537 ldif_write_entry(
538         Operation *op,
539         Entry *e,
540         const struct berval *path,
541         const char *parentdir,
542         const char **text )
543 {
544         int rc = LDAP_OTHER, res, save_errno = 0;
545         int fd, entry_length;
546         char *entry_as_string, *tmpfname;
547
548         if ( op->o_abandon )
549                 return SLAPD_ABANDON;
550
551         if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
552                 save_errno = errno;
553                 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
554                         "cannot create parent directory",
555                         parentdir, STRERROR( save_errno ) );
556                 *text = "internal error (cannot create parent directory)";
557                 return rc;
558         }
559
560         tmpfname = ldif_tempname( path );
561         fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
562         if ( fd < 0 ) {
563                 save_errno = errno;
564                 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
565                         "cannot create file", e->e_dn, STRERROR( save_errno ) );
566                 *text = "internal error (cannot create file)";
567
568         } else {
569                 ber_len_t dn_len = e->e_name.bv_len;
570                 struct berval rdn;
571
572                 /* Only save the RDN onto disk */
573                 dnRdn( &e->e_name, &rdn );
574                 if ( rdn.bv_len != dn_len ) {
575                         e->e_name.bv_val[rdn.bv_len] = '\0';
576                         e->e_name.bv_len = rdn.bv_len;
577                 }
578
579                 res = -2;
580                 ldap_pvt_thread_mutex_lock( &entry2str_mutex );
581                 entry_as_string = entry2str( e, &entry_length );
582                 if ( entry_as_string != NULL )
583                         res = spew_file( fd, entry_as_string, entry_length, &save_errno );
584                 ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
585
586                 /* Restore full DN */
587                 if ( rdn.bv_len != dn_len ) {
588                         e->e_name.bv_val[rdn.bv_len] = ',';
589                         e->e_name.bv_len = dn_len;
590                 }
591
592                 if ( close( fd ) < 0 && res >= 0 ) {
593                         res = -1;
594                         save_errno = errno;
595                 }
596
597                 if ( res >= 0 ) {
598                         if ( move_file( tmpfname, path->bv_val ) == 0 ) {
599                                 Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
600                                         "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 );
601                                 rc = LDAP_SUCCESS;
602                         } else {
603                                 save_errno = errno;
604                                 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
605                                         "could not put entry file for \"%s\" in place: %s\n",
606                                         e->e_name.bv_val, STRERROR( save_errno ), 0 );
607                                 *text = "internal error (could not put entry file in place)";
608                         }
609                 } else if ( res == -1 ) {
610                         Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
611                                 "write error to", tmpfname, STRERROR( save_errno ) );
612                         *text = "internal error (write error to entry file)";
613                 }
614
615                 if ( rc != LDAP_SUCCESS ) {
616                         unlink( tmpfname );
617                 }
618         }
619
620         if ( tmpfname )
621                 SLAP_FREE( tmpfname );
622         return rc;
623 }
624
625 /*
626  * Read the entry at path, or if entryp==NULL just see if it exists.
627  * pdn and pndn are the parent's DN and normalized DN, or both NULL.
628  * Return an LDAP result code.
629  */
630 static int
631 ldif_read_entry(
632         Operation *op,
633         const char *path,
634         struct berval *pdn,
635         struct berval *pndn,
636         Entry **entryp,
637         const char **text )
638 {
639         int rc;
640         Entry *entry;
641         char *entry_as_string;
642         struct berval rdn;
643
644         /* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
645          * If so we need not check for LDAP_REQ_BIND here.
646          */
647         if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND )
648                 return SLAPD_ABANDON;
649
650         rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
651
652         switch ( rc ) {
653         case LDAP_SUCCESS:
654                 if ( entryp == NULL )
655                         break;
656                 *entryp = entry = str2entry( entry_as_string );
657                 SLAP_FREE( entry_as_string );
658                 if ( entry == NULL ) {
659                         rc = LDAP_OTHER;
660                         if ( text != NULL )
661                                 *text = "internal error (cannot parse some entry file)";
662                         break;
663                 }
664                 if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
665                         break;
666                 /* Append parent DN to DN from LDIF file */
667                 rdn = entry->e_name;
668                 build_new_dn( &entry->e_name, pdn, &rdn, NULL );
669                 SLAP_FREE( rdn.bv_val );
670                 rdn = entry->e_nname;
671                 build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
672                 SLAP_FREE( rdn.bv_val );
673                 break;
674
675         case LDAP_OTHER:
676                 if ( text != NULL )
677                         *text = entryp
678                                 ? "internal error (cannot read some entry file)"
679                                 : "internal error (cannot stat some entry file)";
680                 break;
681         }
682
683         return rc;
684 }
685
686 /*
687  * Read the operation's entry, or if entryp==NULL just see if it exists.
688  * Return an LDAP result code.  May set *text to a message on failure.
689  * If pathp is non-NULL, set it to the entry filename on success.
690  */
691 static int
692 get_entry(
693         Operation *op,
694         Entry **entryp,
695         struct berval *pathp,
696         const char **text )
697 {
698         int rc;
699         struct berval path, pdn, pndn;
700
701         dnParent( &op->o_req_dn, &pdn );
702         dnParent( &op->o_req_ndn, &pndn );
703         rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
704         if ( rc != LDAP_SUCCESS ) {
705                 goto done;
706         }
707
708         rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
709
710         if ( rc == LDAP_SUCCESS && pathp != NULL ) {
711                 *pathp = path;
712         } else {
713                 SLAP_FREE( path.bv_val );
714         }
715  done:
716         return rc;
717 }
718
719
720 /*
721  * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
722  * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
723  * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
724  * Does not sort escaped chars correctly, would need to un-escape them.
725  */
726 typedef struct bvlist {
727         struct bvlist *next;
728         char *trunc;    /* filename was truncated here */
729         int  inum;              /* num from "attr={num}" in filename, or INT_MIN */
730         char savech;    /* original char at *trunc */
731         /* BVL_NAME(&bvlist) is the filename, allocated after the struct: */
732 #       define BVL_NAME(bvl)     ((char *) ((bvl) + 1))
733 #       define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1)
734 } bvlist;
735
736 static int
737 ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
738 {
739         int rc = LDAP_SUCCESS;
740
741         if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
742                 if ( rs == NULL ) {
743                         /* Save the entry for tool mode */
744                         struct ldif_tool *tl =
745                                 &((struct ldif_info *) op->o_bd->be_private)->li_tool;
746
747                         if ( tl->ecount >= tl->elen ) {
748                                 /* Allocate/grow entries */
749                                 ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
750                                 Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
751                                         sizeof(Entry *) * elen );
752                                 if ( entries == NULL ) {
753                                         Debug( LDAP_DEBUG_ANY,
754                                                 "ldif_send_entry: out of memory\n", 0, 0, 0 );
755                                         rc = LDAP_OTHER;
756                                         goto done;
757                                 }
758                                 tl->elen = elen;
759                                 tl->entries = entries;
760                         }
761                         tl->entries[tl->ecount++] = e;
762                         e->e_id = tl->ecount;
763                         return rc;
764                 }
765
766                 else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
767                         /* Send a continuation reference.
768                          * (ldif_back_referrals() handles baseobject referrals.)
769                          * Don't check the filter since it's only a candidate.
770                          */
771                         BerVarray refs = get_entry_referrals( op, e );
772                         rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
773                         rs->sr_entry = e;
774                         rc = send_search_reference( op, rs );
775                         ber_bvarray_free( rs->sr_ref );
776                         ber_bvarray_free( refs );
777                         rs->sr_ref = NULL;
778                         rs->sr_entry = NULL;
779                 }
780
781                 else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
782                         rs->sr_entry = e;
783                         rs->sr_attrs = op->ors_attrs;
784                         /* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
785                          * but refraining lets us test unFREEable MODIFIABLE
786                          * entries.  Like entries built on the stack.
787                          */
788                         rs->sr_flags = REP_ENTRY_MODIFIABLE;
789                         rc = send_search_entry( op, rs );
790                         rs->sr_entry = NULL;
791                         rs->sr_attrs = NULL;
792                 }
793         }
794
795  done:
796         entry_free( e );
797         return rc;
798 }
799
800 /* Read LDIF directory <path> into <listp>.  Set *fname_maxlenp. */
801 static int
802 ldif_readdir(
803         Operation *op,
804         SlapReply *rs,
805         const struct berval *path,
806         bvlist **listp,
807         ber_len_t *fname_maxlenp )
808 {
809         int rc = LDAP_SUCCESS;
810         DIR *dir_of_path;
811
812         *listp = NULL;
813         *fname_maxlenp = 0;
814
815         dir_of_path = opendir( path->bv_val );
816         if ( dir_of_path == NULL ) {
817                 int save_errno = errno;
818                 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
819                 int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
820
821                 /* Absent directory is OK (leaf entry), except the database dir */
822                 if ( is_rootDSE || save_errno != ENOENT ) {
823                         Debug( LDAP_DEBUG_ANY,
824                                 "=> ldif_search_entry: failed to opendir \"%s\": %s\n",
825                                 path->bv_val, STRERROR( save_errno ), 0 );
826                         rc = LDAP_OTHER;
827                         if ( rs != NULL )
828                                 rs->sr_text =
829                                         save_errno != ENOENT ? "internal error (bad directory)"
830                                         : !is_rootDSE ? "internal error (missing directory)"
831                                         : "internal error (database directory does not exist)";
832                 }
833
834         } else {
835                 bvlist *ptr;
836                 struct dirent *dir;
837                 int save_errno = 0;
838
839                 while ( (dir = readdir( dir_of_path )) != NULL ) {
840                         size_t fname_len;
841                         bvlist *bvl, **prev;
842                         char *trunc, *idxp, *endp, *endp2;
843
844                         fname_len = strlen( dir->d_name );
845                         if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
846                                 continue;
847                         if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
848                                 continue;
849
850                         if ( *fname_maxlenp < fname_len )
851                                 *fname_maxlenp = fname_len;
852
853                         bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
854                         if ( bvl == NULL ) {
855                                 rc = LDAP_OTHER;
856                                 save_errno = errno;
857                                 break;
858                         }
859                         strcpy( BVL_NAME( bvl ), dir->d_name );
860
861                         /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
862                         trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
863                         if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
864                                  (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
865                                  (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
866                         {
867                                 /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
868                                 bvl->inum = strtol( idxp, &endp2, 10 );
869                                 if ( endp2 == endp ) {
870                                         trunc = idxp;
871                                         goto truncate;
872                                 }
873                         }
874                         bvl->inum = INT_MIN;
875                 truncate:
876                         bvl->trunc = trunc;
877                         bvl->savech = *trunc;
878                         *trunc = '\0';
879
880                         /* Insertion sort */
881                         for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
882                                 int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
883                                 if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
884                                         break;
885                         }
886                         *prev = bvl;
887                         bvl->next = ptr;
888                 }
889
890                 if ( closedir( dir_of_path ) < 0 ) {
891                         save_errno = errno;
892                         rc = LDAP_OTHER;
893                         if ( rs != NULL )
894                                 rs->sr_text = "internal error (bad directory)";
895                 }
896                 if ( rc != LDAP_SUCCESS ) {
897                         Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
898                                 "error reading directory", path->bv_val,
899                                 STRERROR( save_errno ) );
900                 }
901         }
902
903         return rc;
904 }
905
906 /*
907  * Send an entry, recursively search its children, and free or save it.
908  * Return an LDAP result code.  Parameters:
909  *  op, rs  operation and reply.  rs == NULL for slap tools.
910  *  e       entry to search, or NULL for rootDSE.
911  *  scope   scope for the part of the search from this entry.
912  *  path    LDIF filename -- bv_len and non-directory part are overwritten.
913  */
914 static int
915 ldif_search_entry(
916         Operation *op,
917         SlapReply *rs,
918         Entry *e,
919         int scope,
920         struct berval *path )
921 {
922         int rc = LDAP_SUCCESS;
923         struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
924
925         if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
926                 /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
927                  * which bconfig.c seems to need.  (TODO: see config_rename_one.)
928                  */
929                 if ( ber_dupbv( &dn,  &e->e_name  ) == NULL ||
930                          ber_dupbv( &ndn, &e->e_nname ) == NULL )
931                 {
932                         Debug( LDAP_DEBUG_ANY,
933                                 "ldif_search_entry: out of memory\n", 0, 0, 0 );
934                         rc = LDAP_OTHER;
935                         goto done;
936                 }
937         }
938
939         /* Send the entry if appropriate, and free or save it */
940         if ( e != NULL )
941                 rc = ldif_send_entry( op, rs, e, scope );
942
943         /* Search the children */
944         if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
945                 bvlist *list, *ptr;
946                 struct berval fpath;    /* becomes child pathname */
947                 char *dir_end;  /* will point past dirname in fpath */
948
949                 ldif2dir_len( *path );
950                 ldif2dir_name( *path );
951                 rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
952
953                 if ( list != NULL ) {
954                         const char **text = rs == NULL ? NULL : &rs->sr_text;
955
956                         if ( scope == LDAP_SCOPE_ONELEVEL )
957                                 scope = LDAP_SCOPE_BASE;
958                         else if ( scope == LDAP_SCOPE_SUBORDINATE )
959                                 scope = LDAP_SCOPE_SUBTREE;
960
961                         /* Allocate fpath and fill in directory part */
962                         dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
963                         if ( dir_end == NULL )
964                                 rc = LDAP_OTHER;
965
966                         do {
967                                 ptr = list;
968
969                                 if ( rc == LDAP_SUCCESS ) {
970                                         *ptr->trunc = ptr->savech;
971                                         FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
972
973                                         rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
974                                                 &e, text );
975                                         switch ( rc ) {
976                                         case LDAP_SUCCESS:
977                                                 rc = ldif_search_entry( op, rs, e, scope, &fpath );
978                                                 break;
979                                         case LDAP_NO_SUCH_OBJECT:
980                                                 /* Only the search baseDN may produce noSuchObject. */
981                                                 rc = LDAP_OTHER;
982                                                 if ( rs != NULL )
983                                                         rs->sr_text = "internal error "
984                                                                 "(did someone just remove an entry file?)";
985                                                 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
986                                                         "file listed in parent directory does not exist: "
987                                                         "\"%s\"\n", fpath.bv_val, 0, 0 );
988                                                 break;
989                                         }
990                                 }
991
992                                 list = ptr->next;
993                                 SLAP_FREE( ptr );
994                         } while ( list != NULL );
995
996                         if ( !BER_BVISNULL( &fpath ) )
997                                 SLAP_FREE( fpath.bv_val );
998                 }
999         }
1000
1001  done:
1002         if ( !BER_BVISEMPTY( &dn ) )
1003                 ber_memfree( dn.bv_val );
1004         if ( !BER_BVISEMPTY( &ndn ) )
1005                 ber_memfree( ndn.bv_val );
1006         return rc;
1007 }
1008
1009 static int
1010 search_tree( Operation *op, SlapReply *rs )
1011 {
1012         int rc = LDAP_SUCCESS;
1013         Entry *e = NULL;
1014         struct berval path;
1015         struct berval pdn, pndn;
1016
1017         (void) ndn2path( op, &op->o_req_ndn, &path, 1 );
1018         if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
1019                 /* Read baseObject */
1020                 dnParent( &op->o_req_dn, &pdn );
1021                 dnParent( &op->o_req_ndn, &pndn );
1022                 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
1023                         rs == NULL ? NULL : &rs->sr_text );
1024         }
1025         if ( rc == LDAP_SUCCESS )
1026                 rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
1027
1028         ch_free( path.bv_val );
1029         return rc;
1030 }
1031
1032
1033 /*
1034  * Prepare to create or rename an entry:
1035  * Check that the entry does not already exist.
1036  * Check that the parent entry exists and can have subordinates,
1037  * unless need_dir is NULL or adding the suffix entry.
1038  *
1039  * Return an LDAP result code.  May set *text to a message on failure.
1040  * If success, set *dnpath to LDIF entry path and *need_dir to
1041  * (directory must be created ? dirname : NULL).
1042  */
1043 static int
1044 ldif_prepare_create(
1045         Operation *op,
1046         Entry *e,
1047         struct berval *dnpath,
1048         char **need_dir,
1049         const char **text )
1050 {
1051         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1052         struct berval *ndn = &e->e_nname;
1053         struct berval ppath = BER_BVNULL;
1054         struct stat st;
1055         Entry *parent = NULL;
1056         int rc;
1057
1058         if ( op->o_abandon )
1059                 return SLAPD_ABANDON;
1060
1061         rc = ndn2path( op, ndn, dnpath, 0 );
1062         if ( rc != LDAP_SUCCESS ) {
1063                 return rc;
1064         }
1065
1066         if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
1067                 rc = LDAP_ALREADY_EXISTS;
1068
1069         } else if ( errno != ENOENT ) {
1070                 Debug( LDAP_DEBUG_ANY,
1071                         "ldif_prepare_create: cannot stat \"%s\": %s\n",
1072                         dnpath->bv_val, STRERROR( errno ), 0 );
1073                 rc = LDAP_OTHER;
1074                 *text = "internal error (cannot check entry file)";
1075
1076         } else if ( need_dir != NULL ) {
1077                 *need_dir = NULL;
1078                 rc = get_parent_path( dnpath, &ppath );
1079                 /* If parent dir exists, so does parent .ldif:
1080                  * The directory gets created after and removed before the .ldif.
1081                  * Except with the database directory, which has no matching entry.
1082                  */
1083                 if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
1084                         rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
1085                                 ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
1086                 }
1087                 switch ( rc ) {
1088                 case LDAP_NO_SUCH_OBJECT:
1089                         /* No parent dir, check parent .ldif */
1090                         dir2ldif_name( ppath );
1091                         rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
1092                                 (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
1093                                  ? &parent : NULL),
1094                                 text );
1095                         switch ( rc ) {
1096                         case LDAP_SUCCESS:
1097                                 /* Check that parent is not a referral, unless
1098                                  * ldif_back_referrals() already checked.
1099                                  */
1100                                 if ( parent != NULL ) {
1101                                         int is_ref = is_entry_referral( parent );
1102                                         entry_free( parent );
1103                                         if ( is_ref ) {
1104                                                 rc = LDAP_AFFECTS_MULTIPLE_DSAS;
1105                                                 *text = op->o_tag == LDAP_REQ_MODDN
1106                                                         ? "newSuperior is a referral object"
1107                                                         : "parent is a referral object";
1108                                                 break;
1109                                         }
1110                                 }
1111                                 /* Must create parent directory. */
1112                                 ldif2dir_name( ppath );
1113                                 *need_dir = ppath.bv_val;
1114                                 break;
1115                         case LDAP_NO_SUCH_OBJECT:
1116                                 *text = op->o_tag == LDAP_REQ_MODDN
1117                                         ? "newSuperior object does not exist"
1118                                         : "parent does not exist";
1119                                 break;
1120                         }
1121                         break;
1122                 case LDAP_OTHER:
1123                         Debug( LDAP_DEBUG_ANY,
1124                                 "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
1125                                 ndn->bv_val, STRERROR( errno ), 0 );
1126                         *text = "internal error (cannot stat parent dir)";
1127                         break;
1128                 }
1129                 if ( *need_dir == NULL && ppath.bv_val != NULL )
1130                         SLAP_FREE( ppath.bv_val );
1131         }
1132
1133         if ( rc != LDAP_SUCCESS ) {
1134                 SLAP_FREE( dnpath->bv_val );
1135                 BER_BVZERO( dnpath );
1136         }
1137         return rc;
1138 }
1139
1140 static int
1141 apply_modify_to_entry(
1142         Entry *entry,
1143         Modifications *modlist,
1144         Operation *op,
1145         SlapReply *rs,
1146         char *textbuf )
1147 {
1148         int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
1149         int is_oc = 0;
1150         Modification *mods;
1151
1152         if (!acl_check_modlist(op, entry, modlist)) {
1153                 return LDAP_INSUFFICIENT_ACCESS;
1154         }
1155
1156         for (; modlist != NULL; modlist = modlist->sml_next) {
1157                 mods = &modlist->sml_mod;
1158
1159                 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
1160                         is_oc = 1;
1161                 }
1162                 switch (mods->sm_op) {
1163                 case LDAP_MOD_ADD:
1164                         rc = modify_add_values(entry, mods,
1165                                    get_permissiveModify(op),
1166                                    &rs->sr_text, textbuf,
1167                                    SLAP_TEXT_BUFLEN );
1168                         break;
1169
1170                 case LDAP_MOD_DELETE:
1171                         rc = modify_delete_values(entry, mods,
1172                                 get_permissiveModify(op),
1173                                 &rs->sr_text, textbuf,
1174                                 SLAP_TEXT_BUFLEN );
1175                         break;
1176
1177                 case LDAP_MOD_REPLACE:
1178                         rc = modify_replace_values(entry, mods,
1179                                  get_permissiveModify(op),
1180                                  &rs->sr_text, textbuf,
1181                                  SLAP_TEXT_BUFLEN );
1182                         break;
1183
1184                 case LDAP_MOD_INCREMENT:
1185                         rc = modify_increment_values( entry,
1186                                 mods, get_permissiveModify(op),
1187                                 &rs->sr_text, textbuf,
1188                                 SLAP_TEXT_BUFLEN );
1189                         break;
1190
1191                 case SLAP_MOD_SOFTADD:
1192                         mods->sm_op = LDAP_MOD_ADD;
1193                         rc = modify_add_values(entry, mods,
1194                                    get_permissiveModify(op),
1195                                    &rs->sr_text, textbuf,
1196                                    SLAP_TEXT_BUFLEN );
1197                         mods->sm_op = SLAP_MOD_SOFTADD;
1198                         if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
1199                                 rc = LDAP_SUCCESS;
1200                         }
1201                         break;
1202
1203                 case SLAP_MOD_SOFTDEL:
1204                         mods->sm_op = LDAP_MOD_DELETE;
1205                         rc = modify_delete_values(entry, mods,
1206                                    get_permissiveModify(op),
1207                                    &rs->sr_text, textbuf,
1208                                    SLAP_TEXT_BUFLEN );
1209                         mods->sm_op = SLAP_MOD_SOFTDEL;
1210                         if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
1211                                 rc = LDAP_SUCCESS;
1212                         }
1213                         break;
1214
1215                 case SLAP_MOD_ADD_IF_NOT_PRESENT:
1216                         if ( attr_find( entry->e_attrs, mods->sm_desc ) ) {
1217                                 rc = LDAP_SUCCESS;
1218                                 break;
1219                         }
1220                         mods->sm_op = LDAP_MOD_ADD;
1221                         rc = modify_add_values(entry, mods,
1222                                    get_permissiveModify(op),
1223                                    &rs->sr_text, textbuf,
1224                                    SLAP_TEXT_BUFLEN );
1225                         mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
1226                         break;
1227                 }
1228                 if(rc != LDAP_SUCCESS) break;
1229         }
1230
1231         if ( rc == LDAP_SUCCESS ) {
1232                 rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
1233                 if ( is_oc ) {
1234                         entry->e_ocflags = 0;
1235                 }
1236                 /* check that the entry still obeys the schema */
1237                 rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
1238                           &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN );
1239         }
1240
1241         return rc;
1242 }
1243
1244
1245 static int
1246 ldif_back_referrals( Operation *op, SlapReply *rs )
1247 {
1248         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1249         struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn;
1250         ber_len_t min_dnlen;
1251         Entry *entry = NULL, **entryp;
1252         BerVarray ref;
1253         int rc;
1254
1255         min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
1256         if ( min_dnlen == 0 ) {
1257                 /* Catch root DSE (empty DN), it is not a referral */
1258                 min_dnlen = 1;
1259         }
1260         if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) {
1261                 return LDAP_SUCCESS;    /* Root DSE again */
1262         }
1263
1264         entryp = get_manageDSAit( op ) ? NULL : &entry;
1265         ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1266
1267         for (;;) {
1268                 dnParent( &dn, &dn );
1269                 dnParent( &ndn, &ndn );
1270                 rc = ldif_read_entry( op, path.bv_val, &dn, &ndn,
1271                         entryp, &rs->sr_text );
1272                 if ( rc != LDAP_NO_SUCH_OBJECT )
1273                         break;
1274
1275                 rc = LDAP_SUCCESS;
1276                 if ( ndn.bv_len < min_dnlen )
1277                         break;
1278                 (void) get_parent_path( &path, NULL );
1279                 dir2ldif_name( path );
1280                 entryp = &entry;
1281         }
1282
1283         ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1284         SLAP_FREE( path.bv_val );
1285
1286         if ( entry != NULL ) {
1287                 if ( is_entry_referral( entry ) ) {
1288                         Debug( LDAP_DEBUG_TRACE,
1289                                 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
1290                                 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn );
1291
1292                         ref = get_entry_referrals( op, entry );
1293                         rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn,
1294                                 op->o_tag == LDAP_REQ_SEARCH ?
1295                                 op->ors_scope : LDAP_SCOPE_DEFAULT );
1296                         ber_bvarray_free( ref );
1297
1298                         if ( rs->sr_ref != NULL ) {
1299                                 /* send referral */
1300                                 rc = rs->sr_err = LDAP_REFERRAL;
1301                                 rs->sr_matched = entry->e_dn;
1302                                 send_ldap_result( op, rs );
1303                                 ber_bvarray_free( rs->sr_ref );
1304                                 rs->sr_ref = NULL;
1305                         } else {
1306                                 rc = LDAP_OTHER;
1307                                 rs->sr_text = "bad referral object";
1308                         }
1309                         rs->sr_matched = NULL;
1310                 }
1311
1312                 entry_free( entry );
1313         }
1314
1315         return rc;
1316 }
1317
1318
1319 /* LDAP operations */
1320
1321 static int
1322 ldif_back_bind( Operation *op, SlapReply *rs )
1323 {
1324         struct ldif_info *li;
1325         Attribute *a;
1326         AttributeDescription *password = slap_schema.si_ad_userPassword;
1327         int return_val;
1328         Entry *entry = NULL;
1329
1330         switch ( be_rootdn_bind( op, rs ) ) {
1331         case SLAP_CB_CONTINUE:
1332                 break;
1333
1334         default:
1335                 /* in case of success, front end will send result;
1336                  * otherwise, be_rootdn_bind() did */
1337                 return rs->sr_err;
1338         }
1339
1340         li = (struct ldif_info *) op->o_bd->be_private;
1341         ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1342         return_val = get_entry(op, &entry, NULL, NULL);
1343
1344         /* no object is found for them */
1345         if(return_val != LDAP_SUCCESS) {
1346                 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
1347                 goto return_result;
1348         }
1349
1350         /* they don't have userpassword */
1351         if((a = attr_find(entry->e_attrs, password)) == NULL) {
1352                 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1353                 return_val = 1;
1354                 goto return_result;
1355         }
1356
1357         /* authentication actually failed */
1358         if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
1359                              &rs->sr_text) != 0) {
1360                 rs->sr_err = LDAP_INVALID_CREDENTIALS;
1361                 return_val = 1;
1362                 goto return_result;
1363         }
1364
1365         /* let the front-end send success */
1366         return_val = LDAP_SUCCESS;
1367
1368  return_result:
1369         ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1370         if(return_val != LDAP_SUCCESS)
1371                 send_ldap_result( op, rs );
1372         if(entry != NULL)
1373                 entry_free(entry);
1374         return return_val;
1375 }
1376
1377 static int
1378 ldif_back_search( Operation *op, SlapReply *rs )
1379 {
1380         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1381
1382         ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1383         rs->sr_err = search_tree( op, rs );
1384         ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1385         send_ldap_result(op, rs);
1386
1387         return rs->sr_err;
1388 }
1389
1390 static int
1391 ldif_back_add( Operation *op, SlapReply *rs )
1392 {
1393         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1394         Entry * e = op->ora_e;
1395         struct berval path;
1396         char *parentdir;
1397         char textbuf[SLAP_TEXT_BUFLEN];
1398         int rc;
1399
1400         Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
1401
1402         rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
1403                 &rs->sr_text, textbuf, sizeof( textbuf ) );
1404         if ( rc != LDAP_SUCCESS )
1405                 goto send_res;
1406
1407         rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
1408         if ( rc != LDAP_SUCCESS )
1409                 goto send_res;
1410
1411         ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1412
1413         rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
1414         if ( rc == LDAP_SUCCESS ) {
1415                 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1416                 rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
1417                 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1418
1419                 SLAP_FREE( path.bv_val );
1420                 if ( parentdir != NULL )
1421                         SLAP_FREE( parentdir );
1422         }
1423
1424         ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1425
1426  send_res:
1427         rs->sr_err = rc;
1428         Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
1429                 rc, rs->sr_text ? rs->sr_text : "", 0 );
1430         send_ldap_result( op, rs );
1431         slap_graduate_commit_csn( op );
1432         rs->sr_text = NULL;     /* remove possible pointer to textbuf */
1433         return rs->sr_err;
1434 }
1435
1436 static int
1437 ldif_back_modify( Operation *op, SlapReply *rs )
1438 {
1439         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1440         Modifications * modlst = op->orm_modlist;
1441         struct berval path;
1442         Entry *entry;
1443         char textbuf[SLAP_TEXT_BUFLEN];
1444         int rc;
1445
1446         slap_mods_opattrs( op, &op->orm_modlist, 1 );
1447
1448         ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1449
1450         rc = get_entry( op, &entry, &path, &rs->sr_text );
1451         if ( rc == LDAP_SUCCESS ) {
1452                 rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
1453                 if ( rc == LDAP_SUCCESS ) {
1454                         ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1455                         rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
1456                         ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1457                 }
1458
1459                 entry_free( entry );
1460                 SLAP_FREE( path.bv_val );
1461         }
1462
1463         ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1464
1465         rs->sr_err = rc;
1466         send_ldap_result( op, rs );
1467         slap_graduate_commit_csn( op );
1468         rs->sr_text = NULL;     /* remove possible pointer to textbuf */
1469         return rs->sr_err;
1470 }
1471
1472 static int
1473 ldif_back_delete( Operation *op, SlapReply *rs )
1474 {
1475         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1476         struct berval path;
1477         int rc = LDAP_SUCCESS;
1478
1479         if ( BER_BVISEMPTY( &op->o_csn )) {
1480                 struct berval csn;
1481                 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
1482
1483                 csn.bv_val = csnbuf;
1484                 csn.bv_len = sizeof( csnbuf );
1485                 slap_get_csn( op, &csn, 1 );
1486         }
1487
1488         ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1489         ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1490         if ( op->o_abandon ) {
1491                 rc = SLAPD_ABANDON;
1492                 goto done;
1493         }
1494
1495         rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
1496         if ( rc != LDAP_SUCCESS ) {
1497                 goto done;
1498         }
1499
1500         ldif2dir_len( path );
1501         ldif2dir_name( path );
1502         if ( rmdir( path.bv_val ) < 0 ) {
1503                 switch ( errno ) {
1504                 case ENOTEMPTY:
1505                         rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1506                         break;
1507                 case ENOENT:
1508                         /* is leaf, go on */
1509                         break;
1510                 default:
1511                         rc = LDAP_OTHER;
1512                         rs->sr_text = "internal error (cannot delete subtree directory)";
1513                         break;
1514                 }
1515         }
1516
1517         if ( rc == LDAP_SUCCESS ) {
1518                 dir2ldif_name( path );
1519                 if ( unlink( path.bv_val ) < 0 ) {
1520                         rc = LDAP_NO_SUCH_OBJECT;
1521                         if ( errno != ENOENT ) {
1522                                 rc = LDAP_OTHER;
1523                                 rs->sr_text = "internal error (cannot delete entry file)";
1524                         }
1525                 }
1526         }
1527
1528         if ( rc == LDAP_OTHER ) {
1529                 Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
1530                         "cannot delete", path.bv_val, STRERROR( errno ) );
1531         }
1532
1533         SLAP_FREE( path.bv_val );
1534  done:
1535         ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1536         ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1537         rs->sr_err = rc;
1538         send_ldap_result( op, rs );
1539         slap_graduate_commit_csn( op );
1540         return rs->sr_err;
1541 }
1542
1543
1544 static int
1545 ldif_move_entry(
1546         Operation *op,
1547         Entry *entry,
1548         int same_ndn,
1549         struct berval *oldpath,
1550         const char **text )
1551 {
1552         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1553         struct berval newpath;
1554         char *parentdir = NULL, *trash;
1555         int rc, rename_res;
1556
1557         if ( same_ndn ) {
1558                 rc = LDAP_SUCCESS;
1559                 newpath = *oldpath;
1560         } else {
1561                 rc = ldif_prepare_create( op, entry, &newpath,
1562                         op->orr_newSup ? &parentdir : NULL, text );
1563         }
1564
1565         if ( rc == LDAP_SUCCESS ) {
1566                 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1567
1568                 rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
1569                 if ( rc == LDAP_SUCCESS && !same_ndn ) {
1570                         trash = oldpath->bv_val; /* will be .ldif file to delete */
1571                         ldif2dir_len( newpath );
1572                         ldif2dir_len( *oldpath );
1573                         /* Move subdir before deleting old entry,
1574                          * so .ldif always exists if subdir does.
1575                          */
1576                         ldif2dir_name( newpath );
1577                         ldif2dir_name( *oldpath );
1578                         rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
1579                         if ( rename_res != 0 && errno != ENOENT ) {
1580                                 rc = LDAP_OTHER;
1581                                 *text = "internal error (cannot move this subtree)";
1582                                 trash = newpath.bv_val;
1583                         }
1584
1585                         /* Delete old entry, or if error undo change */
1586                         for (;;) {
1587                                 dir2ldif_name( newpath );
1588                                 dir2ldif_name( *oldpath );
1589                                 if ( unlink( trash ) == 0 )
1590                                         break;
1591                                 if ( rc == LDAP_SUCCESS ) {
1592                                         /* Prepare to undo change and return failure */
1593                                         rc = LDAP_OTHER;
1594                                         *text = "internal error (cannot move this entry)";
1595                                         trash = newpath.bv_val;
1596                                         if ( rename_res != 0 )
1597                                                 continue;
1598                                         /* First move subdirectory back */
1599                                         ldif2dir_name( newpath );
1600                                         ldif2dir_name( *oldpath );
1601                                         if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
1602                                                 continue;
1603                                 }
1604                                 *text = "added new but couldn't delete old entry!";
1605                                 break;
1606                         }
1607
1608                         if ( rc != LDAP_SUCCESS ) {
1609                                 char s[128];
1610                                 snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
1611                                 Debug( LDAP_DEBUG_ANY,
1612                                         "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
1613                                         s, op->o_req_dn.bv_val, entry->e_dn );
1614                         }
1615                 }
1616
1617                 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1618                 if ( !same_ndn )
1619                         SLAP_FREE( newpath.bv_val );
1620                 if ( parentdir != NULL )
1621                         SLAP_FREE( parentdir );
1622         }
1623
1624         return rc;
1625 }
1626
1627 static int
1628 ldif_back_modrdn( Operation *op, SlapReply *rs )
1629 {
1630         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1631         struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1632         struct berval p_dn, old_path;
1633         Entry *entry;
1634         char textbuf[SLAP_TEXT_BUFLEN];
1635         int rc, same_ndn;
1636
1637         slap_mods_opattrs( op, &op->orr_modlist, 1 );
1638
1639         ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1640
1641         rc = get_entry( op, &entry, &old_path, &rs->sr_text );
1642         if ( rc == LDAP_SUCCESS ) {
1643                 /* build new dn, and new ndn for the entry */
1644                 if ( op->oq_modrdn.rs_newSup != NULL ) {
1645                         p_dn = *op->oq_modrdn.rs_newSup;
1646                 } else {
1647                         dnParent( &entry->e_name, &p_dn );
1648                 }
1649                 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
1650                 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1651                 same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
1652                 ber_memfree_x( entry->e_name.bv_val, NULL );
1653                 ber_memfree_x( entry->e_nname.bv_val, NULL );
1654                 entry->e_name = new_dn;
1655                 entry->e_nname = new_ndn;
1656
1657                 /* perform the modifications */
1658                 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
1659                 if ( rc == LDAP_SUCCESS )
1660                         rc = ldif_move_entry( op, entry, same_ndn, &old_path,
1661                                 &rs->sr_text );
1662
1663                 entry_free( entry );
1664                 SLAP_FREE( old_path.bv_val );
1665         }
1666
1667         ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1668         rs->sr_err = rc;
1669         send_ldap_result( op, rs );
1670         slap_graduate_commit_csn( op );
1671         rs->sr_text = NULL;     /* remove possible pointer to textbuf */
1672         return rs->sr_err;
1673 }
1674
1675
1676 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1677 static int
1678 ldif_back_entry_get(
1679         Operation *op,
1680         struct berval *ndn,
1681         ObjectClass *oc,
1682         AttributeDescription *at,
1683         int rw,
1684         Entry **e )
1685 {
1686         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1687         struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1688         int rc;
1689
1690         assert( ndn != NULL );
1691         assert( !BER_BVISNULL( ndn ) );
1692
1693         ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1694         op->o_req_dn = *ndn;
1695         op->o_req_ndn = *ndn;
1696         rc = get_entry( op, e, NULL, NULL );
1697         op->o_req_dn = op_dn;
1698         op->o_req_ndn = op_ndn;
1699         ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1700
1701         if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1702                 rc = LDAP_NO_SUCH_ATTRIBUTE;
1703                 entry_free( *e );
1704                 *e = NULL;
1705         }
1706
1707         return rc;
1708 }
1709
1710 static int
1711 ldif_back_entry_release_rw (
1712         Operation *op,
1713         Entry *e,
1714         int rw )
1715 {
1716         ID id = e->e_id;
1717
1718         /* only tool mode assigns valid IDs */
1719         if ( id != 0 && id != NOID )
1720         {
1721                 struct ldif_tool *tl = &((struct ldif_info *) op->o_bd->be_private)->li_tool;
1722
1723                 id--;
1724
1725                 assert( id < tl->ecount );
1726                 assert( e == tl->entries[id] );
1727                 tl->entries[id] = NULL;
1728         }
1729
1730         entry_free( e );
1731         return 0;
1732 }
1733
1734
1735 /* Slap tools */
1736
1737 static int
1738 ldif_tool_entry_open( BackendDB *be, int mode )
1739 {
1740         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1741
1742         tl->ecurrent = 0;
1743         return 0;
1744 }
1745
1746 static int
1747 ldif_tool_entry_close( BackendDB *be )
1748 {
1749         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1750         Entry **entries = tl->entries;
1751         ID i;
1752
1753         for ( i = tl->ecount; i--; )
1754                 if ( entries[i] )
1755                         entry_free( entries[i] );
1756         SLAP_FREE( entries );
1757         tl->entries = NULL;
1758         tl->ecount = tl->elen = 0;
1759         return 0;
1760 }
1761
1762 static ID
1763 ldif_tool_entry_next( BackendDB *be )
1764 {
1765         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1766
1767         do {
1768                 Entry *e = tl->entries[ tl->ecurrent ];
1769
1770                 if ( tl->ecurrent >= tl->ecount ) {
1771                         return NOID;
1772                 }
1773
1774                 ++tl->ecurrent;
1775
1776                 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1777                         continue;
1778                 }
1779
1780                 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter  ) != LDAP_COMPARE_TRUE ) {
1781                         continue;
1782                 }
1783
1784                 break;
1785         } while ( 1 );
1786
1787         return tl->ecurrent;
1788 }
1789
1790 static ID
1791 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1792 {
1793         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1794
1795         tl->tl_base = base;
1796         tl->tl_scope = scope;
1797         tl->tl_filter = f;
1798
1799         if ( tl->entries == NULL ) {
1800                 Operation op = {0};
1801
1802                 op.o_bd = be;
1803                 op.o_req_dn = *be->be_suffix;
1804                 op.o_req_ndn = *be->be_nsuffix;
1805                 op.ors_scope = LDAP_SCOPE_SUBTREE;
1806                 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1807                         tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1808                         return NOID; /* fail ldif_tool_entry_get() */
1809                 }
1810         }
1811         return ldif_tool_entry_next( be );
1812 }
1813
1814 static ID
1815 ldif_tool_dn2id_get( BackendDB *be, struct berval *dn )
1816 {
1817         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1818
1819         Operation op = {0};
1820
1821         op.o_bd = be;
1822         op.o_req_dn = *dn;
1823         op.o_req_ndn = *dn;
1824         op.ors_scope = LDAP_SCOPE_BASE;
1825         if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1826                 return NOID;
1827         }
1828         return tl->ecount;
1829 }
1830
1831 static Entry *
1832 ldif_tool_entry_get( BackendDB *be, ID id )
1833 {
1834         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1835         Entry *e = NULL;
1836
1837         --id;
1838         if ( id < tl->ecount ) {
1839                 e = tl->entries[id];
1840         }
1841         return e;
1842 }
1843
1844 static ID
1845 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1846 {
1847         int rc;
1848         const char *errmsg = NULL;
1849         struct berval path;
1850         char *parentdir;
1851         Operation op = {0};
1852
1853         op.o_bd = be;
1854         rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1855         if ( rc == LDAP_SUCCESS ) {
1856                 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1857
1858                 SLAP_FREE( path.bv_val );
1859                 if ( parentdir != NULL )
1860                         SLAP_FREE( parentdir );
1861                 if ( rc == LDAP_SUCCESS )
1862                         return 1;
1863         }
1864
1865         if ( errmsg == NULL && rc != LDAP_OTHER )
1866                 errmsg = ldap_err2string( rc );
1867         if ( errmsg != NULL )
1868                 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1869         return NOID;
1870 }
1871
1872 static ID
1873 ldif_tool_entry_modify( BackendDB *be, Entry *e, struct berval *text )
1874 {
1875         int rc;
1876         const char *errmsg = NULL;
1877         struct berval path;
1878         Operation op = {0};
1879
1880         op.o_bd = be;
1881         ndn2path( &op, &e->e_nname, &path, 0 );
1882         rc = ldif_write_entry( &op, e, &path, NULL, &errmsg );
1883         SLAP_FREE( path.bv_val );
1884         if ( rc == LDAP_SUCCESS )
1885                 return 1;
1886
1887         if ( errmsg == NULL && rc != LDAP_OTHER )
1888                 errmsg = ldap_err2string( rc );
1889         if ( errmsg != NULL )
1890                 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1891         return NOID;
1892 }
1893
1894 static int
1895 ldif_tool_entry_delete( BackendDB *be, ID id, struct berval *text )
1896 {
1897         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1898         int rc = LDAP_SUCCESS;
1899         const char *errmsg = NULL;
1900         struct berval path;
1901         Entry *e;
1902         Operation op = {0};
1903
1904         id--;
1905         if ( id >= tl->ecount || tl->entries[id] == NULL )
1906                 return LDAP_OTHER;
1907         e = tl->entries[id];
1908
1909         op.o_bd = be;
1910         ndn2path( &op, &e->e_nname, &path, 0 );
1911
1912         ldif2dir_len( path );
1913         ldif2dir_name( path );
1914         if ( rmdir( path.bv_val ) < 0 ) {
1915                 switch ( errno ) {
1916                 case ENOTEMPTY:
1917                         rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1918                         break;
1919                 case ENOENT:
1920                         /* is leaf, go on */
1921                         break;
1922                 default:
1923                         rc = LDAP_OTHER;
1924                         errmsg = "internal error (cannot delete subtree directory)";
1925                         break;
1926                 }
1927         }
1928
1929         if ( rc == LDAP_SUCCESS ) {
1930                 dir2ldif_name( path );
1931                 if ( unlink( path.bv_val ) < 0 ) {
1932                         rc = LDAP_NO_SUCH_OBJECT;
1933                         if ( errno != ENOENT ) {
1934                                 rc = LDAP_OTHER;
1935                                 errmsg = "internal error (cannot delete entry file)";
1936                         }
1937                 }
1938         }
1939
1940         SLAP_FREE( path.bv_val );
1941         entry_free( e );
1942         tl->entries[id] = NULL;
1943
1944         if ( errmsg == NULL && rc != LDAP_OTHER )
1945                 errmsg = ldap_err2string( rc );
1946         if ( errmsg != NULL )
1947                 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1948         return rc;
1949 }
1950
1951
1952 /* Setup */
1953
1954 static int
1955 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1956 {
1957         struct ldif_info *li;
1958
1959         li = ch_calloc( 1, sizeof(struct ldif_info) );
1960         be->be_private = li;
1961         be->be_cf_ocs = ldifocs;
1962         ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1963         ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1964         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1965         return 0;
1966 }
1967
1968 static int
1969 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1970 {
1971         struct ldif_info *li = be->be_private;
1972
1973         ch_free( li->li_base_path.bv_val );
1974         ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1975         ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1976         free( be->be_private );
1977         return 0;
1978 }
1979
1980 static int
1981 ldif_back_db_open( Backend *be, ConfigReply *cr )
1982 {
1983         struct ldif_info *li = (struct ldif_info *) be->be_private;
1984         if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1985                 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1986                 return 1;
1987         }
1988         return 0;
1989 }
1990
1991 int
1992 ldif_back_initialize( BackendInfo *bi )
1993 {
1994         static char *controls[] = {
1995                 LDAP_CONTROL_MANAGEDSAIT,
1996                 NULL
1997         };
1998         int rc;
1999
2000         bi->bi_flags |=
2001                 SLAP_BFLAG_INCREMENT |
2002                 SLAP_BFLAG_REFERRALS;
2003
2004         bi->bi_controls = controls;
2005
2006         bi->bi_open = 0;
2007         bi->bi_close = 0;
2008         bi->bi_config = 0;
2009         bi->bi_destroy = 0;
2010
2011         bi->bi_db_init = ldif_back_db_init;
2012         bi->bi_db_config = config_generic_wrapper;
2013         bi->bi_db_open = ldif_back_db_open;
2014         bi->bi_db_close = 0;
2015         bi->bi_db_destroy = ldif_back_db_destroy;
2016
2017         bi->bi_op_bind = ldif_back_bind;
2018         bi->bi_op_unbind = 0;
2019         bi->bi_op_search = ldif_back_search;
2020         bi->bi_op_compare = 0;
2021         bi->bi_op_modify = ldif_back_modify;
2022         bi->bi_op_modrdn = ldif_back_modrdn;
2023         bi->bi_op_add = ldif_back_add;
2024         bi->bi_op_delete = ldif_back_delete;
2025         bi->bi_op_abandon = 0;
2026
2027         bi->bi_extended = 0;
2028
2029         bi->bi_chk_referrals = ldif_back_referrals;
2030
2031         bi->bi_connection_init = 0;
2032         bi->bi_connection_destroy = 0;
2033
2034         bi->bi_entry_get_rw = ldif_back_entry_get;
2035         bi->bi_entry_release_rw = ldif_back_entry_release_rw;
2036
2037 #if 0   /* NOTE: uncomment to completely disable access control */
2038         bi->bi_access_allowed = slap_access_always_allowed;
2039 #endif
2040
2041         bi->bi_tool_entry_open = ldif_tool_entry_open;
2042         bi->bi_tool_entry_close = ldif_tool_entry_close;
2043         bi->bi_tool_entry_first = backend_tool_entry_first;
2044         bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
2045         bi->bi_tool_entry_next = ldif_tool_entry_next;
2046         bi->bi_tool_dn2id_get = ldif_tool_dn2id_get;
2047         bi->bi_tool_entry_get = ldif_tool_entry_get;
2048         bi->bi_tool_entry_put = ldif_tool_entry_put;
2049         bi->bi_tool_entry_modify = ldif_tool_entry_modify;
2050         bi->bi_tool_entry_delete = ldif_tool_entry_delete;
2051         bi->bi_tool_entry_reindex = 0;
2052         bi->bi_tool_sync = 0;
2053
2054         bi->bi_cf_ocs = ldifocs;
2055
2056         rc = config_register_schema( ldifcfg, ldifocs );
2057         if ( rc ) return rc;
2058         return 0;
2059 }