1/* ldif.c - the ldif backend */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2005-2011 The OpenLDAP Foundation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16/* ACKNOWLEDGEMENTS:
17 * This work was originally developed by Eric Stokes for inclusion
18 * in OpenLDAP Software.
19 */
20
21#include "portable.h"
22#include <stdio.h>
23#include <ac/string.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <ac/dirent.h>
27#include <fcntl.h>
28#include <ac/errno.h>
29#include <ac/unistd.h>
30#include "slap.h"
31#include "lutil.h"
32#include "config.h"
33
34struct 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 */
46struct 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
61static 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. */
153enum {
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 */
161typedef struct {
162	int assert_safe_filenames : safe_filenames ? 2 : -2;
163} assert_safe_filenames[safe_filenames ? 2 : -2];
164
165
166static 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
177static 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 */
192static int
193ndn2path( 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 */
261static char *
262fullpath_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. */
295static int
296get_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. */
316static char *
317ldif_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
336static 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
393unsigned int
394crc32(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 */
416static int
417ldif_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 */
504static int
505spew_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
516static int
517write_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. */
536static int
537ldif_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 */
630static int
631ldif_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 */
691static int
692get_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 */
726typedef 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
736static int
737ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
738{
739	int rc = LDAP_SUCCESS;
740
741	if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
742		if ( rs == NULL ) {
743			/* Save the entry for tool mode */
744			struct ldif_tool *tl =
745				&((struct ldif_info *) op->o_bd->be_private)->li_tool;
746
747			if ( tl->ecount >= tl->elen ) {
748				/* Allocate/grow entries */
749				ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
750				Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
751					sizeof(Entry *) * elen );
752				if ( entries == NULL ) {
753					Debug( LDAP_DEBUG_ANY,
754						"ldif_send_entry: out of memory\n", 0, 0, 0 );
755					rc = LDAP_OTHER;
756					goto done;
757				}
758				tl->elen = elen;
759				tl->entries = entries;
760			}
761			tl->entries[tl->ecount++] = e;
762			return rc;
763		}
764
765		else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
766			/* Send a continuation reference.
767			 * (ldif_back_referrals() handles baseobject referrals.)
768			 * Don't check the filter since it's only a candidate.
769			 */
770			BerVarray refs = get_entry_referrals( op, e );
771			rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
772			rs->sr_entry = e;
773			rc = send_search_reference( op, rs );
774			ber_bvarray_free( rs->sr_ref );
775			ber_bvarray_free( refs );
776			rs->sr_ref = NULL;
777			rs->sr_entry = NULL;
778		}
779
780		else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
781			rs->sr_entry = e;
782			rs->sr_attrs = op->ors_attrs;
783			/* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
784			 * but refraining lets us test unFREEable MODIFIABLE
785			 * entries.  Like entries built on the stack.
786			 */
787			rs->sr_flags = REP_ENTRY_MODIFIABLE;
788			rc = send_search_entry( op, rs );
789			rs->sr_entry = NULL;
790			rs->sr_attrs = NULL;
791		}
792	}
793
794 done:
795	entry_free( e );
796	return rc;
797}
798
799/* Read LDIF directory <path> into <listp>.  Set *fname_maxlenp. */
800static int
801ldif_readdir(
802	Operation *op,
803	SlapReply *rs,
804	const struct berval *path,
805	bvlist **listp,
806	ber_len_t *fname_maxlenp )
807{
808	int rc = LDAP_SUCCESS;
809	DIR *dir_of_path;
810
811	*listp = NULL;
812	*fname_maxlenp = 0;
813
814	dir_of_path = opendir( path->bv_val );
815	if ( dir_of_path == NULL ) {
816		int save_errno = errno;
817		struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
818		int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
819
820		/* Absent directory is OK (leaf entry), except the database dir */
821		if ( is_rootDSE || save_errno != ENOENT ) {
822			Debug( LDAP_DEBUG_ANY,
823				"=> ldif_search_entry: failed to opendir \"%s\": %s\n",
824				path->bv_val, STRERROR( save_errno ), 0 );
825			rc = LDAP_OTHER;
826			if ( rs != NULL )
827				rs->sr_text =
828					save_errno != ENOENT ? "internal error (bad directory)"
829					: !is_rootDSE ? "internal error (missing 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 */
913static int
914ldif_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
1008static int
1009search_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 */
1042static int
1043ldif_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
1139static int
1140apply_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
1244static int
1245ldif_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
1320static int
1321ldif_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
1376static int
1377ldif_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
1389static int
1390ldif_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
1435static int
1436ldif_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
1471static int
1472ldif_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
1543static int
1544ldif_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
1626static int
1627ldif_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. */
1676static int
1677ldif_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
1710/* Slap tools */
1711
1712static int
1713ldif_tool_entry_open( BackendDB *be, int mode )
1714{
1715	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1716
1717	tl->ecurrent = 0;
1718	return 0;
1719}
1720
1721static int
1722ldif_tool_entry_close( BackendDB *be )
1723{
1724	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1725	Entry **entries = tl->entries;
1726	ID i;
1727
1728	for ( i = tl->ecount; i--; )
1729		if ( entries[i] )
1730			entry_free( entries[i] );
1731	SLAP_FREE( entries );
1732	tl->entries = NULL;
1733	tl->ecount = tl->elen = 0;
1734	return 0;
1735}
1736
1737static ID
1738ldif_tool_entry_next( BackendDB *be )
1739{
1740	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1741
1742	do {
1743		Entry *e = tl->entries[ tl->ecurrent ];
1744
1745		if ( tl->ecurrent >= tl->ecount ) {
1746			return NOID;
1747		}
1748
1749		++tl->ecurrent;
1750
1751		if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1752			continue;
1753		}
1754
1755		if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter  ) != LDAP_COMPARE_TRUE ) {
1756			continue;
1757		}
1758
1759		break;
1760	} while ( 1 );
1761
1762	return tl->ecurrent;
1763}
1764
1765static ID
1766ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1767{
1768	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1769
1770	tl->tl_base = base;
1771	tl->tl_scope = scope;
1772	tl->tl_filter = f;
1773
1774	if ( tl->entries == NULL ) {
1775		Operation op = {0};
1776
1777		op.o_bd = be;
1778		op.o_req_dn = *be->be_suffix;
1779		op.o_req_ndn = *be->be_nsuffix;
1780		op.ors_scope = LDAP_SCOPE_SUBTREE;
1781		if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1782			tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1783			return 0; /* fail ldif_tool_entry_get() */
1784		}
1785	}
1786	return ldif_tool_entry_next( be );
1787}
1788
1789static Entry *
1790ldif_tool_entry_get( BackendDB *be, ID id )
1791{
1792	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1793	Entry *e = NULL;
1794
1795	--id;
1796	if ( id < tl->ecount ) {
1797		e = tl->entries[id];
1798		tl->entries[id] = NULL;
1799	}
1800	return e;
1801}
1802
1803static ID
1804ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1805{
1806	int rc;
1807	const char *errmsg = NULL;
1808	struct berval path;
1809	char *parentdir;
1810	Operation op = {0};
1811
1812	op.o_bd = be;
1813	rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1814	if ( rc == LDAP_SUCCESS ) {
1815		rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1816
1817		SLAP_FREE( path.bv_val );
1818		if ( parentdir != NULL )
1819			SLAP_FREE( parentdir );
1820		if ( rc == LDAP_SUCCESS )
1821			return 1;
1822	}
1823
1824	if ( errmsg == NULL && rc != LDAP_OTHER )
1825		errmsg = ldap_err2string( rc );
1826	if ( errmsg != NULL )
1827		snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1828	return NOID;
1829}
1830
1831
1832/* Setup */
1833
1834static int
1835ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1836{
1837	struct ldif_info *li;
1838
1839	li = ch_calloc( 1, sizeof(struct ldif_info) );
1840	be->be_private = li;
1841	be->be_cf_ocs = ldifocs;
1842	ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1843	ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1844	SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1845	return 0;
1846}
1847
1848static int
1849ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1850{
1851	struct ldif_info *li = be->be_private;
1852
1853	ch_free( li->li_base_path.bv_val );
1854	ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1855	ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1856	free( be->be_private );
1857	return 0;
1858}
1859
1860static int
1861ldif_back_db_open( Backend *be, ConfigReply *cr )
1862{
1863	struct ldif_info *li = (struct ldif_info *) be->be_private;
1864	if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1865		Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1866		return 1;
1867	}
1868	return 0;
1869}
1870
1871int
1872ldif_back_initialize( BackendInfo *bi )
1873{
1874	static char *controls[] = {
1875		LDAP_CONTROL_MANAGEDSAIT,
1876		NULL
1877	};
1878	int rc;
1879
1880	bi->bi_flags |=
1881		SLAP_BFLAG_INCREMENT |
1882		SLAP_BFLAG_REFERRALS;
1883
1884	bi->bi_controls = controls;
1885
1886	bi->bi_open = 0;
1887	bi->bi_close = 0;
1888	bi->bi_config = 0;
1889	bi->bi_destroy = 0;
1890
1891	bi->bi_db_init = ldif_back_db_init;
1892	bi->bi_db_config = config_generic_wrapper;
1893	bi->bi_db_open = ldif_back_db_open;
1894	bi->bi_db_close = 0;
1895	bi->bi_db_destroy = ldif_back_db_destroy;
1896
1897	bi->bi_op_bind = ldif_back_bind;
1898	bi->bi_op_unbind = 0;
1899	bi->bi_op_search = ldif_back_search;
1900	bi->bi_op_compare = 0;
1901	bi->bi_op_modify = ldif_back_modify;
1902	bi->bi_op_modrdn = ldif_back_modrdn;
1903	bi->bi_op_add = ldif_back_add;
1904	bi->bi_op_delete = ldif_back_delete;
1905	bi->bi_op_abandon = 0;
1906
1907	bi->bi_extended = 0;
1908
1909	bi->bi_chk_referrals = ldif_back_referrals;
1910
1911	bi->bi_connection_init = 0;
1912	bi->bi_connection_destroy = 0;
1913
1914	bi->bi_entry_get_rw = ldif_back_entry_get;
1915
1916#if 0	/* NOTE: uncomment to completely disable access control */
1917	bi->bi_access_allowed = slap_access_always_allowed;
1918#endif
1919
1920	bi->bi_tool_entry_open = ldif_tool_entry_open;
1921	bi->bi_tool_entry_close = ldif_tool_entry_close;
1922	bi->bi_tool_entry_first = backend_tool_entry_first;
1923	bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
1924	bi->bi_tool_entry_next = ldif_tool_entry_next;
1925	bi->bi_tool_entry_get = ldif_tool_entry_get;
1926	bi->bi_tool_entry_put = ldif_tool_entry_put;
1927	bi->bi_tool_entry_reindex = 0;
1928	bi->bi_tool_sync = 0;
1929
1930	bi->bi_tool_dn2id_get = 0;
1931	bi->bi_tool_entry_modify = 0;
1932
1933	bi->bi_cf_ocs = ldifocs;
1934
1935	rc = config_register_schema( ldifcfg, ldifocs );
1936	if ( rc ) return rc;
1937	return 0;
1938}
1939