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