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