]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldif/ldif.c
ITS#8043 don't leave dangling syncops
[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                         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
1709 /* Slap tools */
1710
1711 static int
1712 ldif_tool_entry_open( BackendDB *be, int mode )
1713 {
1714         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1715
1716         tl->ecurrent = 0;
1717         return 0;
1718 }
1719
1720 static int
1721 ldif_tool_entry_close( BackendDB *be )
1722 {
1723         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1724         Entry **entries = tl->entries;
1725         ID i;
1726
1727         for ( i = tl->ecount; i--; )
1728                 if ( entries[i] )
1729                         entry_free( entries[i] );
1730         SLAP_FREE( entries );
1731         tl->entries = NULL;
1732         tl->ecount = tl->elen = 0;
1733         return 0;
1734 }
1735
1736 static ID
1737 ldif_tool_entry_next( BackendDB *be )
1738 {
1739         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1740
1741         do {
1742                 Entry *e = tl->entries[ tl->ecurrent ];
1743
1744                 if ( tl->ecurrent >= tl->ecount ) {
1745                         return NOID;
1746                 }
1747
1748                 ++tl->ecurrent;
1749
1750                 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1751                         continue;
1752                 }
1753
1754                 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter  ) != LDAP_COMPARE_TRUE ) {
1755                         continue;
1756                 }
1757
1758                 break;
1759         } while ( 1 );
1760
1761         return tl->ecurrent;
1762 }
1763
1764 static ID
1765 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1766 {
1767         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1768
1769         tl->tl_base = base;
1770         tl->tl_scope = scope;
1771         tl->tl_filter = f;
1772
1773         if ( tl->entries == NULL ) {
1774                 Operation op = {0};
1775
1776                 op.o_bd = be;
1777                 op.o_req_dn = *be->be_suffix;
1778                 op.o_req_ndn = *be->be_nsuffix;
1779                 op.ors_scope = LDAP_SCOPE_SUBTREE;
1780                 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1781                         tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1782                         return NOID; /* fail ldif_tool_entry_get() */
1783                 }
1784         }
1785         return ldif_tool_entry_next( be );
1786 }
1787
1788 static Entry *
1789 ldif_tool_entry_get( BackendDB *be, ID id )
1790 {
1791         struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1792         Entry *e = NULL;
1793
1794         --id;
1795         if ( id < tl->ecount ) {
1796                 e = tl->entries[id];
1797                 tl->entries[id] = NULL;
1798         }
1799         return e;
1800 }
1801
1802 static ID
1803 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1804 {
1805         int rc;
1806         const char *errmsg = NULL;
1807         struct berval path;
1808         char *parentdir;
1809         Operation op = {0};
1810
1811         op.o_bd = be;
1812         rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1813         if ( rc == LDAP_SUCCESS ) {
1814                 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1815
1816                 SLAP_FREE( path.bv_val );
1817                 if ( parentdir != NULL )
1818                         SLAP_FREE( parentdir );
1819                 if ( rc == LDAP_SUCCESS )
1820                         return 1;
1821         }
1822
1823         if ( errmsg == NULL && rc != LDAP_OTHER )
1824                 errmsg = ldap_err2string( rc );
1825         if ( errmsg != NULL )
1826                 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1827         return NOID;
1828 }
1829
1830
1831 /* Setup */
1832
1833 static int
1834 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1835 {
1836         struct ldif_info *li;
1837
1838         li = ch_calloc( 1, sizeof(struct ldif_info) );
1839         be->be_private = li;
1840         be->be_cf_ocs = ldifocs;
1841         ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1842         ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1843         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1844         return 0;
1845 }
1846
1847 static int
1848 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1849 {
1850         struct ldif_info *li = be->be_private;
1851
1852         ch_free( li->li_base_path.bv_val );
1853         ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1854         ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1855         free( be->be_private );
1856         return 0;
1857 }
1858
1859 static int
1860 ldif_back_db_open( Backend *be, ConfigReply *cr )
1861 {
1862         struct ldif_info *li = (struct ldif_info *) be->be_private;
1863         if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1864                 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1865                 return 1;
1866         }
1867         return 0;
1868 }
1869
1870 int
1871 ldif_back_initialize( BackendInfo *bi )
1872 {
1873         static char *controls[] = {
1874                 LDAP_CONTROL_MANAGEDSAIT,
1875                 NULL
1876         };
1877         int rc;
1878
1879         bi->bi_flags |=
1880                 SLAP_BFLAG_INCREMENT |
1881                 SLAP_BFLAG_REFERRALS;
1882
1883         bi->bi_controls = controls;
1884
1885         bi->bi_open = 0;
1886         bi->bi_close = 0;
1887         bi->bi_config = 0;
1888         bi->bi_destroy = 0;
1889
1890         bi->bi_db_init = ldif_back_db_init;
1891         bi->bi_db_config = config_generic_wrapper;
1892         bi->bi_db_open = ldif_back_db_open;
1893         bi->bi_db_close = 0;
1894         bi->bi_db_destroy = ldif_back_db_destroy;
1895
1896         bi->bi_op_bind = ldif_back_bind;
1897         bi->bi_op_unbind = 0;
1898         bi->bi_op_search = ldif_back_search;
1899         bi->bi_op_compare = 0;
1900         bi->bi_op_modify = ldif_back_modify;
1901         bi->bi_op_modrdn = ldif_back_modrdn;
1902         bi->bi_op_add = ldif_back_add;
1903         bi->bi_op_delete = ldif_back_delete;
1904         bi->bi_op_abandon = 0;
1905
1906         bi->bi_extended = 0;
1907
1908         bi->bi_chk_referrals = ldif_back_referrals;
1909
1910         bi->bi_connection_init = 0;
1911         bi->bi_connection_destroy = 0;
1912
1913         bi->bi_entry_get_rw = ldif_back_entry_get;
1914
1915 #if 0   /* NOTE: uncomment to completely disable access control */
1916         bi->bi_access_allowed = slap_access_always_allowed;
1917 #endif
1918
1919         bi->bi_tool_entry_open = ldif_tool_entry_open;
1920         bi->bi_tool_entry_close = ldif_tool_entry_close;
1921         bi->bi_tool_entry_first = backend_tool_entry_first;
1922         bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
1923         bi->bi_tool_entry_next = ldif_tool_entry_next;
1924         bi->bi_tool_entry_get = ldif_tool_entry_get;
1925         bi->bi_tool_entry_put = ldif_tool_entry_put;
1926         bi->bi_tool_entry_reindex = 0;
1927         bi->bi_tool_sync = 0;
1928
1929         bi->bi_tool_dn2id_get = 0;
1930         bi->bi_tool_entry_modify = 0;
1931
1932         bi->bi_cf_ocs = ldifocs;
1933
1934         rc = config_register_schema( ldifcfg, ldifocs );
1935         if ( rc ) return rc;
1936         return 0;
1937 }