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