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