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