]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldif/ldif.c
Happy New Year
[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-2018 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
399         while (len > 7) {
400                 CRC8;
401                 len -= 8;
402         }
403         while (len) {
404                 CRC1;
405                 len--;
406         }
407
408         return crc ^ 0xffffffff;
409 }
410
411 /*
412  * Read a file, or stat() it if datap == NULL.  Allocate and fill *datap.
413  * Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error.
414  */
415 static int
416 ldif_read_file( const char *path, char **datap )
417 {
418         int rc = LDAP_SUCCESS, fd, len;
419         int res = -1;   /* 0:success, <0:error, >0:file too big/growing. */
420         struct stat st;
421         char *data = NULL, *ptr = NULL;
422         const char *msg;
423
424         if ( datap == NULL ) {
425                 res = stat( path, &st );
426                 goto done;
427         }
428         fd = open( path, O_RDONLY );
429         if ( fd >= 0 ) {
430                 if ( fstat( fd, &st ) == 0 ) {
431                         if ( st.st_size > INT_MAX - 2 ) {
432                                 res = 1;
433                         } else {
434                                 len = st.st_size + 1; /* +1 detects file size > st.st_size */
435                                 *datap = data = ptr = SLAP_MALLOC( len + 1 );
436                                 if ( ptr != NULL ) {
437                                         while ( len && (res = read( fd, ptr, len )) ) {
438                                                 if ( res > 0 ) {
439                                                         len -= res;
440                                                         ptr += res;
441                                                 } else if ( errno != EINTR ) {
442                                                         break;
443                                                 }
444                                         }
445                                         *ptr = '\0';
446                                 }
447                         }
448                 }
449                 if ( close( fd ) < 0 )
450                         res = -1;
451         }
452
453  done:
454         if ( res == 0 ) {
455 #ifdef LDAP_DEBUG
456                 msg = "entry file exists";
457                 if ( datap ) {
458                         msg = "read entry file";
459                         len = ptr - data;
460                         ptr = strstr( data, "\n# CRC32" );
461                         if (!ptr) {
462                                 msg = "read entry file without checksum";
463                         } else {
464                                 unsigned int crc1 = 0, crc2 = 1;
465                                 if ( sscanf( ptr + 9, "%08x", &crc1) == 1) {
466                                         ptr = strchr(ptr+1, '\n');
467                                         if ( ptr ) {
468                                                 ptr++;
469                                                 len -= (ptr - data);
470                                                 crc2 = crc32( ptr, len );
471                                         }
472                                 }
473                                 if ( crc1 != crc2 ) {
474                                         Debug( LDAP_DEBUG_ANY, "ldif_read_file: checksum error on \"%s\"\n",
475                                                 path, 0, 0 );
476                                         return rc;
477                                 }
478                         }
479                 }
480                 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n", msg, path, 0 );
481 #endif /* LDAP_DEBUG */
482         } else {
483                 if ( res < 0 && errno == ENOENT ) {
484                         Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
485                                 "no entry file \"%s\"\n", path, 0, 0 );
486                         rc = LDAP_NO_SUCH_OBJECT;
487                 } else {
488                         msg = res < 0 ? STRERROR( errno ) : "bad stat() size";
489                         Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
490                                 msg, path, 0 );
491                         rc = LDAP_OTHER;
492                 }
493                 if ( data != NULL )
494                         SLAP_FREE( data );
495         }
496         return rc;
497 }
498
499 /*
500  * return nonnegative for success or -1 for error
501  * do not return numbers less than -1
502  */
503 static int
504 spew_file( int fd, const char *spew, int len, int *save_errno )
505 {
506         int writeres;
507 #define HEADER  "# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n"
508         char header[sizeof(HEADER "# CRC32 12345678\n")];
509
510         sprintf(header, HEADER "# CRC32 %08x\n", crc32(spew, len));
511         writeres = write_data(fd, header, sizeof(header)-1, save_errno);
512         return writeres < 0 ? writeres : write_data(fd, spew, len, save_errno);
513 }
514
515 static int
516 write_data( int fd, const char *spew, int len, int *save_errno )
517 {
518         int writeres = 0;
519         while(len > 0) {
520                 writeres = write(fd, spew, len);
521                 if(writeres == -1) {
522                         *save_errno = errno;
523                         if (*save_errno != EINTR)
524                                 break;
525                 }
526                 else {
527                         spew += writeres;
528                         len -= writeres;
529                 }
530         }
531         return writeres;
532 }
533
534 /* Write an entry LDIF file.  Create parentdir first if non-NULL. */
535 static int
536 ldif_write_entry(
537         Operation *op,
538         Entry *e,
539         const struct berval *path,
540         const char *parentdir,
541         const char **text )
542 {
543         int rc = LDAP_OTHER, res, save_errno = 0;
544         int fd, entry_length;
545         char *entry_as_string, *tmpfname;
546
547         if ( op->o_abandon )
548                 return SLAPD_ABANDON;
549
550         if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
551                 save_errno = errno;
552                 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
553                         "cannot create parent directory",
554                         parentdir, STRERROR( save_errno ) );
555                 *text = "internal error (cannot create parent directory)";
556                 return rc;
557         }
558
559         tmpfname = ldif_tempname( path );
560         fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
561         if ( fd < 0 ) {
562                 save_errno = errno;
563                 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
564                         "cannot create file", e->e_dn, STRERROR( save_errno ) );
565                 *text = "internal error (cannot create file)";
566
567         } else {
568                 ber_len_t dn_len = e->e_name.bv_len;
569                 struct berval rdn;
570
571                 /* Only save the RDN onto disk */
572                 dnRdn( &e->e_name, &rdn );
573                 if ( rdn.bv_len != dn_len ) {
574                         e->e_name.bv_val[rdn.bv_len] = '\0';
575                         e->e_name.bv_len = rdn.bv_len;
576                 }
577
578                 res = -2;
579                 ldap_pvt_thread_mutex_lock( &entry2str_mutex );
580                 entry_as_string = entry2str( e, &entry_length );
581                 if ( entry_as_string != NULL )
582                         res = spew_file( fd, entry_as_string, entry_length, &save_errno );
583                 ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
584
585                 /* Restore full DN */
586                 if ( rdn.bv_len != dn_len ) {
587                         e->e_name.bv_val[rdn.bv_len] = ',';
588                         e->e_name.bv_len = dn_len;
589                 }
590
591                 if ( close( fd ) < 0 && res >= 0 ) {
592                         res = -1;
593                         save_errno = errno;
594                 }
595
596                 if ( res >= 0 ) {
597                         if ( move_file( tmpfname, path->bv_val ) == 0 ) {
598                                 Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
599                                         "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 );
600                                 rc = LDAP_SUCCESS;
601                         } else {
602                                 save_errno = errno;
603                                 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
604                                         "could not put entry file for \"%s\" in place: %s\n",
605                                         e->e_name.bv_val, STRERROR( save_errno ), 0 );
606                                 *text = "internal error (could not put entry file in place)";
607                         }
608                 } else if ( res == -1 ) {
609                         Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
610                                 "write error to", tmpfname, STRERROR( save_errno ) );
611                         *text = "internal error (write error to entry file)";
612                 }
613
614                 if ( rc != LDAP_SUCCESS ) {
615                         unlink( tmpfname );
616                 }
617         }
618
619         if ( tmpfname )
620                 SLAP_FREE( tmpfname );
621         return rc;
622 }
623
624 /*
625  * Read the entry at path, or if entryp==NULL just see if it exists.
626  * pdn and pndn are the parent's DN and normalized DN, or both NULL.
627  * Return an LDAP result code.
628  */
629 static int
630 ldif_read_entry(
631         Operation *op,
632         const char *path,
633         struct berval *pdn,
634         struct berval *pndn,
635         Entry **entryp,
636         const char **text )
637 {
638         int rc;
639         Entry *entry;
640         char *entry_as_string;
641         struct berval rdn;
642
643         /* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
644          * If so we need not check for LDAP_REQ_BIND here.
645          */
646         if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND )
647                 return SLAPD_ABANDON;
648
649         rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
650
651         switch ( rc ) {
652         case LDAP_SUCCESS:
653                 if ( entryp == NULL )
654                         break;
655                 *entryp = entry = str2entry( entry_as_string );
656                 SLAP_FREE( entry_as_string );
657                 if ( entry == NULL ) {
658                         rc = LDAP_OTHER;
659                         if ( text != NULL )
660                                 *text = "internal error (cannot parse some entry file)";
661                         break;
662                 }
663                 if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
664                         break;
665                 /* Append parent DN to DN from LDIF file */
666                 rdn = entry->e_name;
667                 build_new_dn( &entry->e_name, pdn, &rdn, NULL );
668                 SLAP_FREE( rdn.bv_val );
669                 rdn = entry->e_nname;
670                 build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
671                 SLAP_FREE( rdn.bv_val );
672                 break;
673
674         case LDAP_OTHER:
675                 if ( text != NULL )
676                         *text = entryp
677                                 ? "internal error (cannot read some entry file)"
678                                 : "internal error (cannot stat some entry file)";
679                 break;
680         }
681
682         return rc;
683 }
684
685 /*
686  * Read the operation's entry, or if entryp==NULL just see if it exists.
687  * Return an LDAP result code.  May set *text to a message on failure.
688  * If pathp is non-NULL, set it to the entry filename on success.
689  */
690 static int
691 get_entry(
692         Operation *op,
693         Entry **entryp,
694         struct berval *pathp,
695         const char **text )
696 {
697         int rc;
698         struct berval path, pdn, pndn;
699
700         dnParent( &op->o_req_dn, &pdn );
701         dnParent( &op->o_req_ndn, &pndn );
702         rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
703         if ( rc != LDAP_SUCCESS ) {
704                 goto done;
705         }
706
707         rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
708
709         if ( rc == LDAP_SUCCESS && pathp != NULL ) {
710                 *pathp = path;
711         } else {
712                 SLAP_FREE( path.bv_val );
713         }
714  done:
715         return rc;
716 }
717
718
719 /*
720  * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
721  * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
722  * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
723  * Does not sort escaped chars correctly, would need to un-escape them.
724  */
725 typedef struct bvlist {
726         struct bvlist *next;
727         char *trunc;    /* filename was truncated here */
728         int  inum;              /* num from "attr={num}" in filename, or INT_MIN */
729         char savech;    /* original char at *trunc */
730         /* BVL_NAME(&bvlist) is the filename, allocated after the struct: */
731 #       define BVL_NAME(bvl)     ((char *) ((bvl) + 1))
732 #       define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1)
733 } bvlist;
734
735 static int
736 ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
737 {
738         int rc = LDAP_SUCCESS;
739
740         if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
741                 if ( rs == NULL ) {
742                         /* Save the entry for tool mode */
743                         struct ldif_tool *tl =
744                                 &((struct ldif_info *) op->o_bd->be_private)->li_tool;
745
746                         if ( tl->ecount >= tl->elen ) {
747                                 /* Allocate/grow entries */
748                                 ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
749                                 Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
750                                         sizeof(Entry *) * elen );
751                                 if ( entries == NULL ) {
752                                         Debug( LDAP_DEBUG_ANY,
753                                                 "ldif_send_entry: out of memory\n", 0, 0, 0 );
754                                         rc = LDAP_OTHER;
755                                         goto done;
756                                 }
757                                 tl->elen = elen;
758                                 tl->entries = entries;
759                         }
760                         tl->entries[tl->ecount++] = e;
761                         e->e_id = tl->ecount;
762                         return rc;
763                 }
764
765                 else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
766                         /* Send a continuation reference.
767                          * (ldif_back_referrals() handles baseobject referrals.)
768                          * Don't check the filter since it's only a candidate.
769                          */
770                         BerVarray refs = get_entry_referrals( op, e );
771                         rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
772                         rs->sr_entry = e;
773                         rc = send_search_reference( op, rs );
774                         ber_bvarray_free( rs->sr_ref );
775                         ber_bvarray_free( refs );
776                         rs->sr_ref = NULL;
777                         rs->sr_entry = NULL;
778                 }
779
780                 else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
781                         rs->sr_entry = e;
782                         rs->sr_attrs = op->ors_attrs;
783                         /* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
784                          * but refraining lets us test unFREEable MODIFIABLE
785                          * entries.  Like entries built on the stack.
786                          */
787                         rs->sr_flags = REP_ENTRY_MODIFIABLE;
788                         rc = send_search_entry( op, rs );
789                         rs->sr_entry = NULL;
790                         rs->sr_attrs = NULL;
791                 }
792         }
793
794  done:
795         entry_free( e );
796         return rc;
797 }
798
799 /* Read LDIF directory <path> into <listp>.  Set *fname_maxlenp. */
800 static int
801 ldif_readdir(
802         Operation *op,
803         SlapReply *rs,
804         const struct berval *path,
805         bvlist **listp,
806         ber_len_t *fname_maxlenp )
807 {
808         int rc = LDAP_SUCCESS;
809         DIR *dir_of_path;
810
811         *listp = NULL;
812         *fname_maxlenp = 0;
813
814         dir_of_path = opendir( path->bv_val );
815         if ( dir_of_path == NULL ) {
816                 int save_errno = errno;
817                 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
818                 int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
819
820                 /* Absent directory is OK (leaf entry), except the database dir */
821                 if ( is_rootDSE || save_errno != ENOENT ) {
822                         Debug( LDAP_DEBUG_ANY,
823                                 "=> ldif_search_entry: failed to opendir \"%s\": %s\n",
824                                 path->bv_val, STRERROR( save_errno ), 0 );
825                         rc = LDAP_OTHER;
826                         if ( rs != NULL )
827                                 rs->sr_text =
828                                         save_errno != ENOENT ? "internal error (bad directory)"
829                                         : "internal error (database directory does not exist)";
830                 }
831
832         } else {
833                 bvlist *ptr;
834                 struct dirent *dir;
835                 int save_errno = 0;
836
837                 while ( (dir = readdir( dir_of_path )) != NULL ) {
838                         size_t fname_len;
839                         bvlist *bvl, **prev;
840                         char *trunc, *idxp, *endp, *endp2;
841
842                         fname_len = strlen( dir->d_name );
843                         if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
844                                 continue;
845                         if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
846                                 continue;
847
848                         if ( *fname_maxlenp < fname_len )
849                                 *fname_maxlenp = fname_len;
850
851                         bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
852                         if ( bvl == NULL ) {
853                                 rc = LDAP_OTHER;
854                                 save_errno = errno;
855                                 break;
856                         }
857                         strcpy( BVL_NAME( bvl ), dir->d_name );
858
859                         /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
860                         trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
861                         if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
862                                  (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
863                                  (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
864                         {
865                                 /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
866                                 bvl->inum = strtol( idxp, &endp2, 10 );
867                                 if ( endp2 == endp ) {
868                                         trunc = idxp;
869                                         goto truncate;
870                                 }
871                         }
872                         bvl->inum = INT_MIN;
873                 truncate:
874                         bvl->trunc = trunc;
875                         bvl->savech = *trunc;
876                         *trunc = '\0';
877
878                         /* Insertion sort */
879                         for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
880                                 int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
881                                 if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
882                                         break;
883                         }
884                         *prev = bvl;
885                         bvl->next = ptr;
886                 }
887
888                 if ( closedir( dir_of_path ) < 0 ) {
889                         save_errno = errno;
890                         rc = LDAP_OTHER;
891                         if ( rs != NULL )
892                                 rs->sr_text = "internal error (bad directory)";
893                 }
894                 if ( rc != LDAP_SUCCESS ) {
895                         Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
896                                 "error reading directory", path->bv_val,
897                                 STRERROR( save_errno ) );
898                 }
899         }
900
901         return rc;
902 }
903
904 /*
905  * Send an entry, recursively search its children, and free or save it.
906  * Return an LDAP result code.  Parameters:
907  *  op, rs  operation and reply.  rs == NULL for slap tools.
908  *  e       entry to search, or NULL for rootDSE.
909  *  scope   scope for the part of the search from this entry.
910  *  path    LDIF filename -- bv_len and non-directory part are overwritten.
911  */
912 static int
913 ldif_search_entry(
914         Operation *op,
915         SlapReply *rs,
916         Entry *e,
917         int scope,
918         struct berval *path )
919 {
920         int rc = LDAP_SUCCESS;
921         struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
922
923         if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
924                 /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
925                  * which bconfig.c seems to need.  (TODO: see config_rename_one.)
926                  */
927                 if ( ber_dupbv( &dn,  &e->e_name  ) == NULL ||
928                          ber_dupbv( &ndn, &e->e_nname ) == NULL )
929                 {
930                         Debug( LDAP_DEBUG_ANY,
931                                 "ldif_search_entry: out of memory\n", 0, 0, 0 );
932                         rc = LDAP_OTHER;
933                         goto done;
934                 }
935         }
936
937         /* Send the entry if appropriate, and free or save it */
938         if ( e != NULL )
939                 rc = ldif_send_entry( op, rs, e, scope );
940
941         /* Search the children */
942         if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
943                 bvlist *list, *ptr;
944                 struct berval fpath;    /* becomes child pathname */
945                 char *dir_end;  /* will point past dirname in fpath */
946
947                 ldif2dir_len( *path );
948                 ldif2dir_name( *path );
949                 rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
950
951                 if ( list != NULL ) {
952                         const char **text = rs == NULL ? NULL : &rs->sr_text;
953
954                         if ( scope == LDAP_SCOPE_ONELEVEL )
955                                 scope = LDAP_SCOPE_BASE;
956                         else if ( scope == LDAP_SCOPE_SUBORDINATE )
957                                 scope = LDAP_SCOPE_SUBTREE;
958
959                         /* Allocate fpath and fill in directory part */
960                         dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
961                         if ( dir_end == NULL )
962                                 rc = LDAP_OTHER;
963
964                         do {
965                                 ptr = list;
966
967                                 if ( rc == LDAP_SUCCESS ) {
968                                         *ptr->trunc = ptr->savech;
969                                         FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
970
971                                         rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
972                                                 &e, text );
973                                         switch ( rc ) {
974                                         case LDAP_SUCCESS:
975                                                 rc = ldif_search_entry( op, rs, e, scope, &fpath );
976                                                 break;
977                                         case LDAP_NO_SUCH_OBJECT:
978                                                 /* Only the search baseDN may produce noSuchObject. */
979                                                 rc = LDAP_OTHER;
980                                                 if ( rs != NULL )
981                                                         rs->sr_text = "internal error "
982                                                                 "(did someone just remove an entry file?)";
983                                                 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
984                                                         "file listed in parent directory does not exist: "
985                                                         "\"%s\"\n", fpath.bv_val, 0, 0 );
986                                                 break;
987                                         }
988                                 }
989
990                                 list = ptr->next;
991                                 SLAP_FREE( ptr );
992                         } while ( list != NULL );
993
994                         if ( !BER_BVISNULL( &fpath ) )
995                                 SLAP_FREE( fpath.bv_val );
996                 }
997         }
998
999  done:
1000         if ( !BER_BVISEMPTY( &dn ) )
1001                 ber_memfree( dn.bv_val );
1002         if ( !BER_BVISEMPTY( &ndn ) )
1003                 ber_memfree( ndn.bv_val );
1004         return rc;
1005 }
1006
1007 static int
1008 search_tree( Operation *op, SlapReply *rs )
1009 {
1010         int rc = LDAP_SUCCESS;
1011         Entry *e = NULL;
1012         struct berval path;
1013         struct berval pdn, pndn;
1014
1015         (void) ndn2path( op, &op->o_req_ndn, &path, 1 );
1016         if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
1017                 /* Read baseObject */
1018                 dnParent( &op->o_req_dn, &pdn );
1019                 dnParent( &op->o_req_ndn, &pndn );
1020                 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
1021                         rs == NULL ? NULL : &rs->sr_text );
1022         }
1023         if ( rc == LDAP_SUCCESS )
1024                 rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
1025
1026         ch_free( path.bv_val );
1027         return rc;
1028 }
1029
1030
1031 /*
1032  * Prepare to create or rename an entry:
1033  * Check that the entry does not already exist.
1034  * Check that the parent entry exists and can have subordinates,
1035  * unless need_dir is NULL or adding the suffix entry.
1036  *
1037  * Return an LDAP result code.  May set *text to a message on failure.
1038  * If success, set *dnpath to LDIF entry path and *need_dir to
1039  * (directory must be created ? dirname : NULL).
1040  */
1041 static int
1042 ldif_prepare_create(
1043         Operation *op,
1044         Entry *e,
1045         struct berval *dnpath,
1046         char **need_dir,
1047         const char **text )
1048 {
1049         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1050         struct berval *ndn = &e->e_nname;
1051         struct berval ppath = BER_BVNULL;
1052         struct stat st;
1053         Entry *parent = NULL;
1054         int rc;
1055
1056         if ( op->o_abandon )
1057                 return SLAPD_ABANDON;
1058
1059         rc = ndn2path( op, ndn, dnpath, 0 );
1060         if ( rc != LDAP_SUCCESS ) {
1061                 return rc;
1062         }
1063
1064         if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
1065                 rc = LDAP_ALREADY_EXISTS;
1066
1067         } else if ( errno != ENOENT ) {
1068                 Debug( LDAP_DEBUG_ANY,
1069                         "ldif_prepare_create: cannot stat \"%s\": %s\n",
1070                         dnpath->bv_val, STRERROR( errno ), 0 );
1071                 rc = LDAP_OTHER;
1072                 *text = "internal error (cannot check entry file)";
1073
1074         } else if ( need_dir != NULL ) {
1075                 *need_dir = NULL;
1076                 rc = get_parent_path( dnpath, &ppath );
1077                 /* If parent dir exists, so does parent .ldif:
1078                  * The directory gets created after and removed before the .ldif.
1079                  * Except with the database directory, which has no matching entry.
1080                  */
1081                 if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
1082                         rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
1083                                 ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
1084                 }
1085                 switch ( rc ) {
1086                 case LDAP_NO_SUCH_OBJECT:
1087                         /* No parent dir, check parent .ldif */
1088                         dir2ldif_name( ppath );
1089                         rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
1090                                 (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
1091                                  ? &parent : NULL),
1092                                 text );
1093                         switch ( rc ) {
1094                         case LDAP_SUCCESS:
1095                                 /* Check that parent is not a referral, unless
1096                                  * ldif_back_referrals() already checked.
1097                                  */
1098                                 if ( parent != NULL ) {
1099                                         int is_ref = is_entry_referral( parent );
1100                                         entry_free( parent );
1101                                         if ( is_ref ) {
1102                                                 rc = LDAP_AFFECTS_MULTIPLE_DSAS;
1103                                                 *text = op->o_tag == LDAP_REQ_MODDN
1104                                                         ? "newSuperior is a referral object"
1105                                                         : "parent is a referral object";
1106                                                 break;
1107                                         }
1108                                 }
1109                                 /* Must create parent directory. */
1110                                 ldif2dir_name( ppath );
1111                                 *need_dir = ppath.bv_val;
1112                                 break;
1113                         case LDAP_NO_SUCH_OBJECT:
1114                                 *text = op->o_tag == LDAP_REQ_MODDN
1115                                         ? "newSuperior object does not exist"
1116                                         : "parent does not exist";
1117                                 break;
1118                         }
1119                         break;
1120                 case LDAP_OTHER:
1121                         Debug( LDAP_DEBUG_ANY,
1122                                 "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
1123                                 ndn->bv_val, STRERROR( errno ), 0 );
1124                         *text = "internal error (cannot stat parent dir)";
1125                         break;
1126                 }
1127                 if ( *need_dir == NULL && ppath.bv_val != NULL )
1128                         SLAP_FREE( ppath.bv_val );
1129         }
1130
1131         if ( rc != LDAP_SUCCESS ) {
1132                 SLAP_FREE( dnpath->bv_val );
1133                 BER_BVZERO( dnpath );
1134         }
1135         return rc;
1136 }
1137
1138 static int
1139 apply_modify_to_entry(
1140         Entry *entry,
1141         Modifications *modlist,
1142         Operation *op,
1143         SlapReply *rs,
1144         char *textbuf )
1145 {
1146         int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
1147         int is_oc = 0;
1148         Modification *mods;
1149
1150         if (!acl_check_modlist(op, entry, modlist)) {
1151                 return LDAP_INSUFFICIENT_ACCESS;
1152         }
1153
1154         for (; modlist != NULL; modlist = modlist->sml_next) {
1155                 mods = &modlist->sml_mod;
1156
1157                 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
1158                         is_oc = 1;
1159                 }
1160                 switch (mods->sm_op) {
1161                 case LDAP_MOD_ADD:
1162                         rc = modify_add_values(entry, mods,
1163                                    get_permissiveModify(op),
1164                                    &rs->sr_text, textbuf,
1165                                    SLAP_TEXT_BUFLEN );
1166                         break;
1167
1168                 case LDAP_MOD_DELETE:
1169                         rc = modify_delete_values(entry, mods,
1170                                 get_permissiveModify(op),
1171                                 &rs->sr_text, textbuf,
1172                                 SLAP_TEXT_BUFLEN );
1173                         break;
1174
1175                 case LDAP_MOD_REPLACE:
1176                         rc = modify_replace_values(entry, mods,
1177                                  get_permissiveModify(op),
1178                                  &rs->sr_text, textbuf,
1179                                  SLAP_TEXT_BUFLEN );
1180                         break;
1181
1182                 case LDAP_MOD_INCREMENT:
1183                         rc = modify_increment_values( entry,
1184                                 mods, get_permissiveModify(op),
1185                                 &rs->sr_text, textbuf,
1186                                 SLAP_TEXT_BUFLEN );
1187                         break;
1188
1189                 case SLAP_MOD_SOFTADD:
1190                         mods->sm_op = LDAP_MOD_ADD;
1191                         rc = modify_add_values(entry, mods,
1192                                    get_permissiveModify(op),
1193                                    &rs->sr_text, textbuf,
1194                                    SLAP_TEXT_BUFLEN );
1195                         mods->sm_op = SLAP_MOD_SOFTADD;
1196                         if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
1197                                 rc = LDAP_SUCCESS;
1198                         }
1199                         break;
1200
1201                 case SLAP_MOD_SOFTDEL:
1202                         mods->sm_op = LDAP_MOD_DELETE;
1203                         rc = modify_delete_values(entry, mods,
1204                                    get_permissiveModify(op),
1205                                    &rs->sr_text, textbuf,
1206                                    SLAP_TEXT_BUFLEN );
1207                         mods->sm_op = SLAP_MOD_SOFTDEL;
1208                         if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
1209                                 rc = LDAP_SUCCESS;
1210                         }
1211                         break;
1212
1213                 case SLAP_MOD_ADD_IF_NOT_PRESENT:
1214                         if ( attr_find( entry->e_attrs, mods->sm_desc ) ) {
1215                                 rc = LDAP_SUCCESS;
1216                                 break;
1217                         }
1218                         mods->sm_op = LDAP_MOD_ADD;
1219                         rc = modify_add_values(entry, mods,
1220                                    get_permissiveModify(op),
1221                                    &rs->sr_text, textbuf,
1222                                    SLAP_TEXT_BUFLEN );
1223                         mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
1224                         break;
1225                 }
1226                 if(rc != LDAP_SUCCESS) break;
1227         }
1228
1229         if ( rc == LDAP_SUCCESS ) {
1230                 rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
1231                 if ( is_oc ) {
1232                         entry->e_ocflags = 0;
1233                 }
1234                 /* check that the entry still obeys the schema */
1235                 rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
1236                           &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN );
1237         }
1238
1239         return rc;
1240 }
1241
1242
1243 static int
1244 ldif_back_referrals( Operation *op, SlapReply *rs )
1245 {
1246         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1247         struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn;
1248         ber_len_t min_dnlen;
1249         Entry *entry = NULL, **entryp;
1250         BerVarray ref;
1251         int rc;
1252
1253         min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
1254         if ( min_dnlen == 0 ) {
1255                 /* Catch root DSE (empty DN), it is not a referral */
1256                 min_dnlen = 1;
1257         }
1258         if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) {
1259                 return LDAP_SUCCESS;    /* Root DSE again */
1260         }
1261
1262         entryp = get_manageDSAit( op ) ? NULL : &entry;
1263         ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1264
1265         for (;;) {
1266                 dnParent( &dn, &dn );
1267                 dnParent( &ndn, &ndn );
1268                 rc = ldif_read_entry( op, path.bv_val, &dn, &ndn,
1269                         entryp, &rs->sr_text );
1270                 if ( rc != LDAP_NO_SUCH_OBJECT )
1271                         break;
1272
1273                 rc = LDAP_SUCCESS;
1274                 if ( ndn.bv_len < min_dnlen )
1275                         break;
1276                 (void) get_parent_path( &path, NULL );
1277                 dir2ldif_name( path );
1278                 entryp = &entry;
1279         }
1280
1281         ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1282         SLAP_FREE( path.bv_val );
1283
1284         if ( entry != NULL ) {
1285                 if ( is_entry_referral( entry ) ) {
1286                         Debug( LDAP_DEBUG_TRACE,
1287                                 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
1288                                 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn );
1289
1290                         ref = get_entry_referrals( op, entry );
1291                         rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn,
1292                                 op->o_tag == LDAP_REQ_SEARCH ?
1293                                 op->ors_scope : LDAP_SCOPE_DEFAULT );
1294                         ber_bvarray_free( ref );
1295
1296                         if ( rs->sr_ref != NULL ) {
1297                                 /* send referral */
1298                                 rc = rs->sr_err = LDAP_REFERRAL;
1299                                 rs->sr_matched = entry->e_dn;
1300                                 send_ldap_result( op, rs );
1301                                 ber_bvarray_free( rs->sr_ref );
1302                                 rs->sr_ref = NULL;
1303                         } else {
1304                                 rc = LDAP_OTHER;
1305                                 rs->sr_text = "bad referral object";
1306                         }
1307                         rs->sr_matched = NULL;
1308                 }
1309
1310                 entry_free( entry );
1311         }
1312
1313         return rc;
1314 }
1315
1316
1317 /* LDAP operations */
1318
1319 static int
1320 ldif_back_bind( Operation *op, SlapReply *rs )
1321 {
1322         struct ldif_info *li;
1323         Attribute *a;
1324         AttributeDescription *password = slap_schema.si_ad_userPassword;
1325         int return_val;
1326         Entry *entry = NULL;
1327
1328         switch ( be_rootdn_bind( op, rs ) ) {
1329         case SLAP_CB_CONTINUE:
1330                 break;
1331
1332         default:
1333                 /* in case of success, front end will send result;
1334                  * otherwise, be_rootdn_bind() did */
1335                 return rs->sr_err;
1336         }
1337
1338         li = (struct ldif_info *) op->o_bd->be_private;
1339         ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1340         return_val = get_entry(op, &entry, NULL, NULL);
1341
1342         /* no object is found for them */
1343         if(return_val != LDAP_SUCCESS) {
1344                 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
1345                 goto return_result;
1346         }
1347
1348         /* they don't have userpassword */
1349         if((a = attr_find(entry->e_attrs, password)) == NULL) {
1350                 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1351                 return_val = 1;
1352                 goto return_result;
1353         }
1354
1355         /* authentication actually failed */
1356         if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
1357                              &rs->sr_text) != 0) {
1358                 rs->sr_err = LDAP_INVALID_CREDENTIALS;
1359                 return_val = 1;
1360                 goto return_result;
1361         }
1362
1363         /* let the front-end send success */
1364         return_val = LDAP_SUCCESS;
1365
1366  return_result:
1367         ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1368         if(return_val != LDAP_SUCCESS)
1369                 send_ldap_result( op, rs );
1370         if(entry != NULL)
1371                 entry_free(entry);
1372         return return_val;
1373 }
1374
1375 static int
1376 ldif_back_search( Operation *op, SlapReply *rs )
1377 {
1378         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1379
1380         ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1381         rs->sr_err = search_tree( op, rs );
1382         ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1383         send_ldap_result(op, rs);
1384
1385         return rs->sr_err;
1386 }
1387
1388 static int
1389 ldif_back_add( Operation *op, SlapReply *rs )
1390 {
1391         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1392         Entry * e = op->ora_e;
1393         struct berval path;
1394         char *parentdir;
1395         char textbuf[SLAP_TEXT_BUFLEN];
1396         int rc;
1397
1398         Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
1399
1400         rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
1401                 &rs->sr_text, textbuf, sizeof( textbuf ) );
1402         if ( rc != LDAP_SUCCESS )
1403                 goto send_res;
1404
1405         rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
1406         if ( rc != LDAP_SUCCESS )
1407                 goto send_res;
1408
1409         ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1410
1411         rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
1412         if ( rc == LDAP_SUCCESS ) {
1413                 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1414                 rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
1415                 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1416
1417                 SLAP_FREE( path.bv_val );
1418                 if ( parentdir != NULL )
1419                         SLAP_FREE( parentdir );
1420         }
1421
1422         ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1423
1424  send_res:
1425         rs->sr_err = rc;
1426         Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
1427                 rc, rs->sr_text ? rs->sr_text : "", 0 );
1428         send_ldap_result( op, rs );
1429         slap_graduate_commit_csn( op );
1430         rs->sr_text = NULL;     /* remove possible pointer to textbuf */
1431         return rs->sr_err;
1432 }
1433
1434 static int
1435 ldif_back_modify( Operation *op, SlapReply *rs )
1436 {
1437         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1438         Modifications * modlst = op->orm_modlist;
1439         struct berval path;
1440         Entry *entry;
1441         char textbuf[SLAP_TEXT_BUFLEN];
1442         int rc;
1443
1444         slap_mods_opattrs( op, &op->orm_modlist, 1 );
1445
1446         ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1447
1448         rc = get_entry( op, &entry, &path, &rs->sr_text );
1449         if ( rc == LDAP_SUCCESS ) {
1450                 rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
1451                 if ( rc == LDAP_SUCCESS ) {
1452                         ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1453                         rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
1454                         ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1455                 }
1456
1457                 entry_free( entry );
1458                 SLAP_FREE( path.bv_val );
1459         }
1460
1461         ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1462
1463         rs->sr_err = rc;
1464         send_ldap_result( op, rs );
1465         slap_graduate_commit_csn( op );
1466         rs->sr_text = NULL;     /* remove possible pointer to textbuf */
1467         return rs->sr_err;
1468 }
1469
1470 static int
1471 ldif_back_delete( Operation *op, SlapReply *rs )
1472 {
1473         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1474         struct berval path;
1475         int rc = LDAP_SUCCESS;
1476
1477         if ( BER_BVISEMPTY( &op->o_csn )) {
1478                 struct berval csn;
1479                 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
1480
1481                 csn.bv_val = csnbuf;
1482                 csn.bv_len = sizeof( csnbuf );
1483                 slap_get_csn( op, &csn, 1 );
1484         }
1485
1486         ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1487         ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1488         if ( op->o_abandon ) {
1489                 rc = SLAPD_ABANDON;
1490                 goto done;
1491         }
1492
1493         rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
1494         if ( rc != LDAP_SUCCESS ) {
1495                 goto done;
1496         }
1497
1498         ldif2dir_len( path );
1499         ldif2dir_name( path );
1500         if ( rmdir( path.bv_val ) < 0 ) {
1501                 switch ( errno ) {
1502                 case ENOTEMPTY:
1503                         rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1504                         break;
1505                 case ENOENT:
1506                         /* is leaf, go on */
1507                         break;
1508                 default:
1509                         rc = LDAP_OTHER;
1510                         rs->sr_text = "internal error (cannot delete subtree directory)";
1511                         break;
1512                 }
1513         }
1514
1515         if ( rc == LDAP_SUCCESS ) {
1516                 dir2ldif_name( path );
1517                 if ( unlink( path.bv_val ) < 0 ) {
1518                         rc = LDAP_NO_SUCH_OBJECT;
1519                         if ( errno != ENOENT ) {
1520                                 rc = LDAP_OTHER;
1521                                 rs->sr_text = "internal error (cannot delete entry file)";
1522                         }
1523                 }
1524         }
1525
1526         if ( rc == LDAP_OTHER ) {
1527                 Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
1528                         "cannot delete", path.bv_val, STRERROR( errno ) );
1529         }
1530
1531         SLAP_FREE( path.bv_val );
1532  done:
1533         ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1534         ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1535         rs->sr_err = rc;
1536         send_ldap_result( op, rs );
1537         slap_graduate_commit_csn( op );
1538         return rs->sr_err;
1539 }
1540
1541
1542 static int
1543 ldif_move_entry(
1544         Operation *op,
1545         Entry *entry,
1546         int same_ndn,
1547         struct berval *oldpath,
1548         const char **text )
1549 {
1550         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1551         struct berval newpath;
1552         char *parentdir = NULL, *trash;
1553         int rc, rename_res;
1554
1555         if ( same_ndn ) {
1556                 rc = LDAP_SUCCESS;
1557                 newpath = *oldpath;
1558         } else {
1559                 rc = ldif_prepare_create( op, entry, &newpath,
1560                         op->orr_newSup ? &parentdir : NULL, text );
1561         }
1562
1563         if ( rc == LDAP_SUCCESS ) {
1564                 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1565
1566                 rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
1567                 if ( rc == LDAP_SUCCESS && !same_ndn ) {
1568                         trash = oldpath->bv_val; /* will be .ldif file to delete */
1569                         ldif2dir_len( newpath );
1570                         ldif2dir_len( *oldpath );
1571                         /* Move subdir before deleting old entry,
1572                          * so .ldif always exists if subdir does.
1573                          */
1574                         ldif2dir_name( newpath );
1575                         ldif2dir_name( *oldpath );
1576                         rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
1577                         if ( rename_res != 0 && errno != ENOENT ) {
1578                                 rc = LDAP_OTHER;
1579                                 *text = "internal error (cannot move this subtree)";
1580                                 trash = newpath.bv_val;
1581                         }
1582
1583                         /* Delete old entry, or if error undo change */
1584                         for (;;) {
1585                                 dir2ldif_name( newpath );
1586                                 dir2ldif_name( *oldpath );
1587                                 if ( unlink( trash ) == 0 )
1588                                         break;
1589                                 if ( rc == LDAP_SUCCESS ) {
1590                                         /* Prepare to undo change and return failure */
1591                                         rc = LDAP_OTHER;
1592                                         *text = "internal error (cannot move this entry)";
1593                                         trash = newpath.bv_val;
1594                                         if ( rename_res != 0 )
1595                                                 continue;
1596                                         /* First move subdirectory back */
1597                                         ldif2dir_name( newpath );
1598                                         ldif2dir_name( *oldpath );
1599                                         if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
1600                                                 continue;
1601                                 }
1602                                 *text = "added new but couldn't delete old entry!";
1603                                 break;
1604                         }
1605
1606                         if ( rc != LDAP_SUCCESS ) {
1607                                 char s[128];
1608                                 snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
1609                                 Debug( LDAP_DEBUG_ANY,
1610                                         "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
1611                                         s, op->o_req_dn.bv_val, entry->e_dn );
1612                         }
1613                 }
1614
1615                 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1616                 if ( !same_ndn )
1617                         SLAP_FREE( newpath.bv_val );
1618                 if ( parentdir != NULL )
1619                         SLAP_FREE( parentdir );
1620         }
1621
1622         return rc;
1623 }
1624
1625 static int
1626 ldif_back_modrdn( Operation *op, SlapReply *rs )
1627 {
1628         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1629         struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1630         struct berval p_dn, old_path;
1631         Entry *entry;
1632         char textbuf[SLAP_TEXT_BUFLEN];
1633         int rc, same_ndn;
1634
1635         slap_mods_opattrs( op, &op->orr_modlist, 1 );
1636
1637         ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1638
1639         rc = get_entry( op, &entry, &old_path, &rs->sr_text );
1640         if ( rc == LDAP_SUCCESS ) {
1641                 /* build new dn, and new ndn for the entry */
1642                 if ( op->oq_modrdn.rs_newSup != NULL ) {
1643                         p_dn = *op->oq_modrdn.rs_newSup;
1644                 } else {
1645                         dnParent( &entry->e_name, &p_dn );
1646                 }
1647                 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
1648                 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1649                 same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
1650                 ber_memfree_x( entry->e_name.bv_val, NULL );
1651                 ber_memfree_x( entry->e_nname.bv_val, NULL );
1652                 entry->e_name = new_dn;
1653                 entry->e_nname = new_ndn;
1654
1655                 /* perform the modifications */
1656                 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
1657                 if ( rc == LDAP_SUCCESS )
1658                         rc = ldif_move_entry( op, entry, same_ndn, &old_path,
1659                                 &rs->sr_text );
1660
1661                 entry_free( entry );
1662                 SLAP_FREE( old_path.bv_val );
1663         }
1664
1665         ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1666         rs->sr_err = rc;
1667         send_ldap_result( op, rs );
1668         slap_graduate_commit_csn( op );
1669         rs->sr_text = NULL;     /* remove possible pointer to textbuf */
1670         return rs->sr_err;
1671 }
1672
1673
1674 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1675 static int
1676 ldif_back_entry_get(
1677         Operation *op,
1678         struct berval *ndn,
1679         ObjectClass *oc,
1680         AttributeDescription *at,
1681         int rw,
1682         Entry **e )
1683 {
1684         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1685         struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1686         int rc;
1687
1688         assert( ndn != NULL );
1689         assert( !BER_BVISNULL( ndn ) );
1690
1691         ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1692         op->o_req_dn = *ndn;
1693         op->o_req_ndn = *ndn;
1694         rc = get_entry( op, e, NULL, NULL );
1695         op->o_req_dn = op_dn;
1696         op->o_req_ndn = op_ndn;
1697         ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1698
1699         if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1700                 rc = LDAP_NO_SUCH_ATTRIBUTE;
1701                 entry_free( *e );
1702                 *e = NULL;
1703         }
1704
1705         return rc;
1706 }
1707
1708 static int
1709 ldif_back_entry_release_rw (
1710         Operation *op,
1711         Entry *e,
1712         int rw )
1713 {
1714         ID id = e->e_id;
1715
1716         /* only tool mode assigns valid IDs */
1717         if ( id != 0 && id != NOID )
1718         {
1719                 struct ldif_tool *tl = &((struct ldif_info *) op->o_bd->be_private)->li_tool;
1720
1721                 id--;
1722
1723                 assert( id < tl->ecount );
1724                 assert( e == tl->entries[id] );
1725                 tl->entries[id] = NULL;
1726         }
1727
1728         entry_free( e );
1729         return 0;
1730 }
1731
1732
1733 /* Slap tools */
1734
1735 static int
1736 ldif_tool_entry_open( BackendDB *be, int mode )
1737 {
1738         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1739
1740         tl->ecurrent = 0;
1741         return 0;
1742 }
1743
1744 static int
1745 ldif_tool_entry_close( BackendDB *be )
1746 {
1747         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1748         Entry **entries = tl->entries;
1749         ID i;
1750
1751         for ( i = tl->ecount; i--; )
1752                 if ( entries[i] )
1753                         entry_free( entries[i] );
1754         SLAP_FREE( entries );
1755         tl->entries = NULL;
1756         tl->ecount = tl->elen = 0;
1757         return 0;
1758 }
1759
1760 static ID
1761 ldif_tool_entry_next( BackendDB *be )
1762 {
1763         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1764
1765         do {
1766                 Entry *e = tl->entries[ tl->ecurrent ];
1767
1768                 if ( tl->ecurrent >= tl->ecount ) {
1769                         return NOID;
1770                 }
1771
1772                 ++tl->ecurrent;
1773
1774                 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1775                         continue;
1776                 }
1777
1778                 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter  ) != LDAP_COMPARE_TRUE ) {
1779                         continue;
1780                 }
1781
1782                 break;
1783         } while ( 1 );
1784
1785         return tl->ecurrent;
1786 }
1787
1788 static ID
1789 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1790 {
1791         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1792
1793         tl->tl_base = base;
1794         tl->tl_scope = scope;
1795         tl->tl_filter = f;
1796
1797         if ( tl->entries == NULL ) {
1798                 Operation op = {0};
1799
1800                 op.o_bd = be;
1801                 op.o_req_dn = *be->be_suffix;
1802                 op.o_req_ndn = *be->be_nsuffix;
1803                 op.ors_scope = LDAP_SCOPE_SUBTREE;
1804                 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1805                         tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1806                         return NOID; /* fail ldif_tool_entry_get() */
1807                 }
1808         }
1809         return ldif_tool_entry_next( be );
1810 }
1811
1812 static ID
1813 ldif_tool_dn2id_get( BackendDB *be, struct berval *dn )
1814 {
1815         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1816
1817         Operation op = {0};
1818
1819         op.o_bd = be;
1820         op.o_req_dn = *dn;
1821         op.o_req_ndn = *dn;
1822         op.ors_scope = LDAP_SCOPE_BASE;
1823         if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1824                 return NOID;
1825         }
1826         return tl->ecount;
1827 }
1828
1829 static Entry *
1830 ldif_tool_entry_get( BackendDB *be, ID id )
1831 {
1832         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1833         Entry *e = NULL;
1834
1835         --id;
1836         if ( id < tl->ecount ) {
1837                 e = tl->entries[id];
1838         }
1839         return e;
1840 }
1841
1842 static ID
1843 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1844 {
1845         int rc;
1846         const char *errmsg = NULL;
1847         struct berval path;
1848         char *parentdir;
1849         Operation op = {0};
1850
1851         op.o_bd = be;
1852         rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1853         if ( rc == LDAP_SUCCESS ) {
1854                 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1855
1856                 SLAP_FREE( path.bv_val );
1857                 if ( parentdir != NULL )
1858                         SLAP_FREE( parentdir );
1859                 if ( rc == LDAP_SUCCESS )
1860                         return 1;
1861         }
1862
1863         if ( errmsg == NULL && rc != LDAP_OTHER )
1864                 errmsg = ldap_err2string( rc );
1865         if ( errmsg != NULL )
1866                 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1867         return NOID;
1868 }
1869
1870 static ID
1871 ldif_tool_entry_modify( BackendDB *be, Entry *e, struct berval *text )
1872 {
1873         int rc;
1874         const char *errmsg = NULL;
1875         struct berval path;
1876         Operation op = {0};
1877
1878         op.o_bd = be;
1879         ndn2path( &op, &e->e_nname, &path, 0 );
1880         rc = ldif_write_entry( &op, e, &path, NULL, &errmsg );
1881         SLAP_FREE( path.bv_val );
1882         if ( rc == LDAP_SUCCESS )
1883                 return 1;
1884
1885         if ( errmsg == NULL && rc != LDAP_OTHER )
1886                 errmsg = ldap_err2string( rc );
1887         if ( errmsg != NULL )
1888                 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1889         return NOID;
1890 }
1891
1892 static int
1893 ldif_tool_entry_delete( BackendDB *be, struct berval *ndn, struct berval *text )
1894 {
1895         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1896         int rc = LDAP_SUCCESS;
1897         const char *errmsg = NULL;
1898         struct berval path;
1899         Operation op = {0};
1900
1901         op.o_bd = be;
1902         ndn2path( &op, ndn, &path, 0 );
1903
1904         ldif2dir_len( path );
1905         ldif2dir_name( path );
1906         if ( rmdir( path.bv_val ) < 0 ) {
1907                 switch ( errno ) {
1908                 case ENOTEMPTY:
1909                         rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1910                         break;
1911                 case ENOENT:
1912                         /* is leaf, go on */
1913                         break;
1914                 default:
1915                         rc = LDAP_OTHER;
1916                         errmsg = "internal error (cannot delete subtree directory)";
1917                         break;
1918                 }
1919         }
1920
1921         if ( rc == LDAP_SUCCESS ) {
1922                 dir2ldif_name( path );
1923                 if ( unlink( path.bv_val ) < 0 ) {
1924                         rc = LDAP_NO_SUCH_OBJECT;
1925                         if ( errno != ENOENT ) {
1926                                 rc = LDAP_OTHER;
1927                                 errmsg = "internal error (cannot delete entry file)";
1928                         }
1929                 }
1930         }
1931
1932         SLAP_FREE( path.bv_val );
1933
1934         if ( errmsg == NULL && rc != LDAP_OTHER )
1935                 errmsg = ldap_err2string( rc );
1936         if ( errmsg != NULL )
1937                 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1938         return rc;
1939 }
1940
1941
1942 /* Setup */
1943
1944 static int
1945 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1946 {
1947         struct ldif_info *li;
1948
1949         li = ch_calloc( 1, sizeof(struct ldif_info) );
1950         be->be_private = li;
1951         be->be_cf_ocs = ldifocs;
1952         ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1953         ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1954         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1955         return 0;
1956 }
1957
1958 static int
1959 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1960 {
1961         struct ldif_info *li = be->be_private;
1962
1963         ch_free( li->li_base_path.bv_val );
1964         ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1965         ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1966         free( be->be_private );
1967         return 0;
1968 }
1969
1970 static int
1971 ldif_back_db_open( Backend *be, ConfigReply *cr )
1972 {
1973         struct ldif_info *li = (struct ldif_info *) be->be_private;
1974         if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1975                 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1976                 return 1;
1977         }
1978         return 0;
1979 }
1980
1981 int
1982 ldif_back_initialize( BackendInfo *bi )
1983 {
1984         static char *controls[] = {
1985                 LDAP_CONTROL_MANAGEDSAIT,
1986                 NULL
1987         };
1988         int rc;
1989
1990         bi->bi_flags |=
1991                 SLAP_BFLAG_INCREMENT |
1992                 SLAP_BFLAG_REFERRALS;
1993
1994         bi->bi_controls = controls;
1995
1996         bi->bi_open = 0;
1997         bi->bi_close = 0;
1998         bi->bi_config = 0;
1999         bi->bi_destroy = 0;
2000
2001         bi->bi_db_init = ldif_back_db_init;
2002         bi->bi_db_config = config_generic_wrapper;
2003         bi->bi_db_open = ldif_back_db_open;
2004         bi->bi_db_close = 0;
2005         bi->bi_db_destroy = ldif_back_db_destroy;
2006
2007         bi->bi_op_bind = ldif_back_bind;
2008         bi->bi_op_unbind = 0;
2009         bi->bi_op_search = ldif_back_search;
2010         bi->bi_op_compare = 0;
2011         bi->bi_op_modify = ldif_back_modify;
2012         bi->bi_op_modrdn = ldif_back_modrdn;
2013         bi->bi_op_add = ldif_back_add;
2014         bi->bi_op_delete = ldif_back_delete;
2015         bi->bi_op_abandon = 0;
2016
2017         bi->bi_extended = 0;
2018
2019         bi->bi_chk_referrals = ldif_back_referrals;
2020
2021         bi->bi_connection_init = 0;
2022         bi->bi_connection_destroy = 0;
2023
2024         bi->bi_entry_get_rw = ldif_back_entry_get;
2025         bi->bi_entry_release_rw = ldif_back_entry_release_rw;
2026
2027 #if 0   /* NOTE: uncomment to completely disable access control */
2028         bi->bi_access_allowed = slap_access_always_allowed;
2029 #endif
2030
2031         bi->bi_tool_entry_open = ldif_tool_entry_open;
2032         bi->bi_tool_entry_close = ldif_tool_entry_close;
2033         bi->bi_tool_entry_first = backend_tool_entry_first;
2034         bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
2035         bi->bi_tool_entry_next = ldif_tool_entry_next;
2036         bi->bi_tool_dn2id_get = ldif_tool_dn2id_get;
2037         bi->bi_tool_entry_get = ldif_tool_entry_get;
2038         bi->bi_tool_entry_put = ldif_tool_entry_put;
2039         bi->bi_tool_entry_modify = ldif_tool_entry_modify;
2040         bi->bi_tool_entry_delete = ldif_tool_entry_delete;
2041         bi->bi_tool_entry_reindex = 0;
2042         bi->bi_tool_sync = 0;
2043
2044         bi->bi_cf_ocs = ldifocs;
2045
2046         rc = config_register_schema( ldifcfg, ldifocs );
2047         if ( rc ) return rc;
2048         return 0;
2049 }