Home | History | Annotate | Line # | Download | only in back-ldif
ldif.c revision 1.1.1.9
      1 /*	$NetBSD: ldif.c,v 1.1.1.9 2021/08/14 16:05:23 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-2021 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.1.1.9 2021/08/14 16:05:23 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 "slap-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}mdb").
    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" );
    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 );
    481 					return rc;
    482 				}
    483 			}
    484 		}
    485 		Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n", msg, path );
    486 #endif /* LDAP_DEBUG */
    487 	} else {
    488 		char ebuf[128];
    489 		if ( res < 0 && errno == ENOENT ) {
    490 			Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
    491 				"no entry file \"%s\"\n", path );
    492 			rc = LDAP_NO_SUCH_OBJECT;
    493 		} else {
    494 			msg = res < 0 ? AC_STRERROR_R( errno, ebuf, sizeof(ebuf) ) : "bad stat() size";
    495 			Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
    496 				msg, path );
    497 			rc = LDAP_OTHER;
    498 		}
    499 		if ( data != NULL )
    500 			SLAP_FREE( data );
    501 	}
    502 	return rc;
    503 }
    504 
    505 /*
    506  * return nonnegative for success or -1 for error
    507  * do not return numbers less than -1
    508  */
    509 static int
    510 spew_file( int fd, const char *spew, int len, int *save_errno )
    511 {
    512 	int writeres;
    513 #define HEADER	"# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n"
    514 	char header[sizeof(HEADER "# CRC32 12345678\n")];
    515 
    516 	sprintf(header, HEADER "# CRC32 %08x\n", crc32(spew, len));
    517 	writeres = write_data(fd, header, sizeof(header)-1, save_errno);
    518 	return writeres < 0 ? writeres : write_data(fd, spew, len, save_errno);
    519 }
    520 
    521 static int
    522 write_data( int fd, const char *spew, int len, int *save_errno )
    523 {
    524 	int writeres = 0;
    525 	while(len > 0) {
    526 		writeres = write(fd, spew, len);
    527 		if(writeres == -1) {
    528 			*save_errno = errno;
    529 			if (*save_errno != EINTR)
    530 				break;
    531 		}
    532 		else {
    533 			spew += writeres;
    534 			len -= writeres;
    535 		}
    536 	}
    537 	return writeres;
    538 }
    539 
    540 /* Write an entry LDIF file.  Create parentdir first if non-NULL. */
    541 static int
    542 ldif_write_entry(
    543 	Operation *op,
    544 	Entry *e,
    545 	const struct berval *path,
    546 	const char *parentdir,
    547 	const char **text )
    548 {
    549 	int rc = LDAP_OTHER, res, save_errno = 0;
    550 	int fd, entry_length;
    551 	char *entry_as_string, *tmpfname;
    552 	char ebuf[128];
    553 
    554 	if ( op->o_abandon )
    555 		return SLAPD_ABANDON;
    556 
    557 	if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
    558 		save_errno = errno;
    559 		Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
    560 			"cannot create parent directory",
    561 			parentdir, AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
    562 		*text = "internal error (cannot create parent directory)";
    563 		return rc;
    564 	}
    565 
    566 	tmpfname = ldif_tempname( path );
    567 	fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
    568 	if ( fd < 0 ) {
    569 		save_errno = errno;
    570 		Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
    571 			"cannot create file", e->e_dn, AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
    572 		*text = "internal error (cannot create file)";
    573 
    574 	} else {
    575 		ber_len_t dn_len = e->e_name.bv_len;
    576 		struct berval rdn;
    577 
    578 		/* Only save the RDN onto disk */
    579 		dnRdn( &e->e_name, &rdn );
    580 		if ( rdn.bv_len != dn_len ) {
    581 			e->e_name.bv_val[rdn.bv_len] = '\0';
    582 			e->e_name.bv_len = rdn.bv_len;
    583 		}
    584 
    585 		res = -2;
    586 		ldap_pvt_thread_mutex_lock( &entry2str_mutex );
    587 		entry_as_string = entry2str( e, &entry_length );
    588 		if ( entry_as_string != NULL )
    589 			res = spew_file( fd, entry_as_string, entry_length, &save_errno );
    590 		ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
    591 
    592 		/* Restore full DN */
    593 		if ( rdn.bv_len != dn_len ) {
    594 			e->e_name.bv_val[rdn.bv_len] = ',';
    595 			e->e_name.bv_len = dn_len;
    596 		}
    597 
    598 		if ( close( fd ) < 0 && res >= 0 ) {
    599 			res = -1;
    600 			save_errno = errno;
    601 		}
    602 
    603 		if ( res >= 0 ) {
    604 			if ( move_file( tmpfname, path->bv_val ) == 0 ) {
    605 				Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
    606 					"wrote entry \"%s\"\n", e->e_name.bv_val );
    607 				rc = LDAP_SUCCESS;
    608 			} else {
    609 				save_errno = errno;
    610 				Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
    611 					"could not put entry file for \"%s\" in place: %s\n",
    612 					e->e_name.bv_val, AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
    613 				*text = "internal error (could not put entry file in place)";
    614 			}
    615 		} else if ( res == -1 ) {
    616 			Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
    617 				"write error to", tmpfname, AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
    618 			*text = "internal error (write error to entry file)";
    619 		}
    620 
    621 		if ( rc != LDAP_SUCCESS ) {
    622 			unlink( tmpfname );
    623 		}
    624 	}
    625 
    626 	if ( tmpfname )
    627 		SLAP_FREE( tmpfname );
    628 	return rc;
    629 }
    630 
    631 /*
    632  * Read the entry at path, or if entryp==NULL just see if it exists.
    633  * pdn and pndn are the parent's DN and normalized DN, or both NULL.
    634  * Return an LDAP result code.
    635  */
    636 static int
    637 ldif_read_entry(
    638 	Operation *op,
    639 	const char *path,
    640 	struct berval *pdn,
    641 	struct berval *pndn,
    642 	Entry **entryp,
    643 	const char **text )
    644 {
    645 	int rc;
    646 	Entry *entry;
    647 	char *entry_as_string;
    648 	struct berval rdn;
    649 
    650 	/* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
    651 	 * If so we need not check for LDAP_REQ_BIND here.
    652 	 */
    653 	if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND )
    654 		return SLAPD_ABANDON;
    655 
    656 	rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
    657 
    658 	switch ( rc ) {
    659 	case LDAP_SUCCESS:
    660 		if ( entryp == NULL )
    661 			break;
    662 		*entryp = entry = str2entry( entry_as_string );
    663 		SLAP_FREE( entry_as_string );
    664 		if ( entry == NULL ) {
    665 			rc = LDAP_OTHER;
    666 			if ( text != NULL )
    667 				*text = "internal error (cannot parse some entry file)";
    668 			break;
    669 		}
    670 		if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
    671 			break;
    672 		/* Append parent DN to DN from LDIF file */
    673 		rdn = entry->e_name;
    674 		build_new_dn( &entry->e_name, pdn, &rdn, NULL );
    675 		SLAP_FREE( rdn.bv_val );
    676 		rdn = entry->e_nname;
    677 		build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
    678 		SLAP_FREE( rdn.bv_val );
    679 		break;
    680 
    681 	case LDAP_OTHER:
    682 		if ( text != NULL )
    683 			*text = entryp
    684 				? "internal error (cannot read some entry file)"
    685 				: "internal error (cannot stat some entry file)";
    686 		break;
    687 	}
    688 
    689 	return rc;
    690 }
    691 
    692 /*
    693  * Read the operation's entry, or if entryp==NULL just see if it exists.
    694  * Return an LDAP result code.  May set *text to a message on failure.
    695  * If pathp is non-NULL, set it to the entry filename on success.
    696  */
    697 static int
    698 get_entry(
    699 	Operation *op,
    700 	Entry **entryp,
    701 	struct berval *pathp,
    702 	const char **text )
    703 {
    704 	int rc;
    705 	struct berval path, pdn, pndn;
    706 
    707 	dnParent( &op->o_req_dn, &pdn );
    708 	dnParent( &op->o_req_ndn, &pndn );
    709 	rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
    710 	if ( rc != LDAP_SUCCESS ) {
    711 		goto done;
    712 	}
    713 
    714 	rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
    715 
    716 	if ( rc == LDAP_SUCCESS && pathp != NULL ) {
    717 		*pathp = path;
    718 	} else {
    719 		SLAP_FREE( path.bv_val );
    720 	}
    721  done:
    722 	return rc;
    723 }
    724 
    725 
    726 /*
    727  * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
    728  * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
    729  * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
    730  * Does not sort escaped chars correctly, would need to un-escape them.
    731  */
    732 typedef struct bvlist {
    733 	struct bvlist *next;
    734 	char *trunc;	/* filename was truncated here */
    735 	int  inum;		/* num from "attr={num}" in filename, or INT_MIN */
    736 	char savech;	/* original char at *trunc */
    737 	/* BVL_NAME(&bvlist) is the filename, allocated after the struct: */
    738 #	define BVL_NAME(bvl)     ((char *) ((bvl) + 1))
    739 #	define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1)
    740 } bvlist;
    741 
    742 static int
    743 ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
    744 {
    745 	int rc = LDAP_SUCCESS;
    746 
    747 	if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
    748 		if ( rs == NULL ) {
    749 			/* Save the entry for tool mode */
    750 			struct ldif_tool *tl =
    751 				&((struct ldif_info *) op->o_bd->be_private)->li_tool;
    752 
    753 			if ( tl->ecount >= tl->elen ) {
    754 				/* Allocate/grow entries */
    755 				ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
    756 				Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
    757 					sizeof(Entry *) * elen );
    758 				if ( entries == NULL ) {
    759 					Debug( LDAP_DEBUG_ANY,
    760 						"ldif_send_entry: out of memory\n" );
    761 					rc = LDAP_OTHER;
    762 					goto done;
    763 				}
    764 				tl->elen = elen;
    765 				tl->entries = entries;
    766 			}
    767 			tl->entries[tl->ecount++] = e;
    768 			e->e_id = tl->ecount;
    769 			return rc;
    770 		}
    771 
    772 		else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
    773 			/* Send a continuation reference.
    774 			 * (ldif_back_referrals() handles baseobject referrals.)
    775 			 * Don't check the filter since it's only a candidate.
    776 			 */
    777 			BerVarray refs = get_entry_referrals( op, e );
    778 			rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
    779 			rs->sr_entry = e;
    780 			rc = send_search_reference( op, rs );
    781 			ber_bvarray_free( rs->sr_ref );
    782 			ber_bvarray_free( refs );
    783 			rs->sr_ref = NULL;
    784 			rs->sr_entry = NULL;
    785 		}
    786 
    787 		else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
    788 			rs->sr_entry = e;
    789 			rs->sr_attrs = op->ors_attrs;
    790 			/* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
    791 			 * but refraining lets us test unFREEable MODIFIABLE
    792 			 * entries.  Like entries built on the stack.
    793 			 */
    794 			rs->sr_flags = REP_ENTRY_MODIFIABLE;
    795 			rc = send_search_entry( op, rs );
    796 			rs->sr_entry = NULL;
    797 			rs->sr_attrs = NULL;
    798 		}
    799 	}
    800 
    801  done:
    802 	entry_free( e );
    803 	return rc;
    804 }
    805 
    806 /* Read LDIF directory <path> into <listp>.  Set *fname_maxlenp. */
    807 static int
    808 ldif_readdir(
    809 	Operation *op,
    810 	SlapReply *rs,
    811 	const struct berval *path,
    812 	bvlist **listp,
    813 	ber_len_t *fname_maxlenp )
    814 {
    815 	int rc = LDAP_SUCCESS;
    816 	DIR *dir_of_path;
    817 	char ebuf[128];
    818 
    819 	*listp = NULL;
    820 	*fname_maxlenp = 0;
    821 
    822 	dir_of_path = opendir( path->bv_val );
    823 	if ( dir_of_path == NULL ) {
    824 		int save_errno = errno;
    825 		struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
    826 		int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
    827 
    828 		/* Absent directory is OK (leaf entry), except the database dir */
    829 		if ( is_rootDSE || save_errno != ENOENT ) {
    830 			Debug( LDAP_DEBUG_ANY,
    831 				"=> ldif_search_entry: failed to opendir \"%s\": %s\n",
    832 				path->bv_val, AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
    833 			rc = LDAP_OTHER;
    834 			if ( rs != NULL )
    835 				rs->sr_text =
    836 					save_errno != ENOENT ? "internal error (bad directory)"
    837 					: "internal error (database directory does not exist)";
    838 		}
    839 
    840 	} else {
    841 		bvlist *ptr;
    842 		struct dirent *dir;
    843 		int save_errno = 0;
    844 
    845 		while ( (dir = readdir( dir_of_path )) != NULL ) {
    846 			size_t fname_len;
    847 			bvlist *bvl, **prev;
    848 			char *trunc, *idxp, *endp, *endp2;
    849 
    850 			fname_len = strlen( dir->d_name );
    851 			if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
    852 				continue;
    853 			if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
    854 				continue;
    855 
    856 			if ( *fname_maxlenp < fname_len )
    857 				*fname_maxlenp = fname_len;
    858 
    859 			bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
    860 			if ( bvl == NULL ) {
    861 				rc = LDAP_OTHER;
    862 				save_errno = errno;
    863 				break;
    864 			}
    865 			strcpy( BVL_NAME( bvl ), dir->d_name );
    866 
    867 			/* Make it sortable by ("attr=val" or <preceding {num}, num>) */
    868 			trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
    869 			if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
    870 				 (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
    871 				 (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
    872 			{
    873 				/* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
    874 				bvl->inum = strtol( idxp, &endp2, 10 );
    875 				if ( endp2 == endp ) {
    876 					trunc = idxp;
    877 					goto truncate;
    878 				}
    879 			}
    880 			bvl->inum = INT_MIN;
    881 		truncate:
    882 			bvl->trunc = trunc;
    883 			bvl->savech = *trunc;
    884 			*trunc = '\0';
    885 
    886 			/* Insertion sort */
    887 			for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
    888 				int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
    889 				if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
    890 					break;
    891 			}
    892 			*prev = bvl;
    893 			bvl->next = ptr;
    894 		}
    895 
    896 		if ( closedir( dir_of_path ) < 0 ) {
    897 			save_errno = errno;
    898 			rc = LDAP_OTHER;
    899 			if ( rs != NULL )
    900 				rs->sr_text = "internal error (bad directory)";
    901 		}
    902 		if ( rc != LDAP_SUCCESS ) {
    903 			Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
    904 				"error reading directory", path->bv_val,
    905 				AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
    906 		}
    907 	}
    908 
    909 	return rc;
    910 }
    911 
    912 /*
    913  * Send an entry, recursively search its children, and free or save it.
    914  * Return an LDAP result code.  Parameters:
    915  *  op, rs  operation and reply.  rs == NULL for slap tools.
    916  *  e       entry to search, or NULL for rootDSE.
    917  *  scope   scope for the part of the search from this entry.
    918  *  path    LDIF filename -- bv_len and non-directory part are overwritten.
    919  */
    920 static int
    921 ldif_search_entry(
    922 	Operation *op,
    923 	SlapReply *rs,
    924 	Entry *e,
    925 	int scope,
    926 	struct berval *path )
    927 {
    928 	int rc = LDAP_SUCCESS;
    929 	struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
    930 
    931 	if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
    932 		/* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
    933 		 * which bconfig.c seems to need.  (TODO: see config_rename_one.)
    934 		 */
    935 		if ( ber_dupbv( &dn,  &e->e_name  ) == NULL ||
    936 			 ber_dupbv( &ndn, &e->e_nname ) == NULL )
    937 		{
    938 			Debug( LDAP_DEBUG_ANY,
    939 				"ldif_search_entry: out of memory\n" );
    940 			rc = LDAP_OTHER;
    941 			goto done;
    942 		}
    943 	}
    944 
    945 	/* Send the entry if appropriate, and free or save it */
    946 	if ( e != NULL )
    947 		rc = ldif_send_entry( op, rs, e, scope );
    948 
    949 	/* Search the children */
    950 	if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
    951 		bvlist *list, *ptr;
    952 		struct berval fpath;	/* becomes child pathname */
    953 		char *dir_end;	/* will point past dirname in fpath */
    954 
    955 		ldif2dir_len( *path );
    956 		ldif2dir_name( *path );
    957 		rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
    958 
    959 		if ( list != NULL ) {
    960 			const char **text = rs == NULL ? NULL : &rs->sr_text;
    961 
    962 			if ( scope == LDAP_SCOPE_ONELEVEL )
    963 				scope = LDAP_SCOPE_BASE;
    964 			else if ( scope == LDAP_SCOPE_SUBORDINATE )
    965 				scope = LDAP_SCOPE_SUBTREE;
    966 
    967 			/* Allocate fpath and fill in directory part */
    968 			dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
    969 			if ( dir_end == NULL )
    970 				rc = LDAP_OTHER;
    971 
    972 			do {
    973 				ptr = list;
    974 
    975 				if ( rc == LDAP_SUCCESS ) {
    976 					*ptr->trunc = ptr->savech;
    977 					FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
    978 
    979 					rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
    980 						&e, text );
    981 					switch ( rc ) {
    982 					case LDAP_SUCCESS:
    983 						rc = ldif_search_entry( op, rs, e, scope, &fpath );
    984 						break;
    985 					case LDAP_NO_SUCH_OBJECT:
    986 						/* Only the search baseDN may produce noSuchObject. */
    987 						rc = LDAP_OTHER;
    988 						if ( rs != NULL )
    989 							rs->sr_text = "internal error "
    990 								"(did someone just remove an entry file?)";
    991 						Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
    992 							"file listed in parent directory does not exist: "
    993 							"\"%s\"\n", fpath.bv_val );
    994 						break;
    995 					}
    996 				}
    997 
    998 				list = ptr->next;
    999 				SLAP_FREE( ptr );
   1000 			} while ( list != NULL );
   1001 
   1002 			if ( !BER_BVISNULL( &fpath ) )
   1003 				SLAP_FREE( fpath.bv_val );
   1004 		}
   1005 	}
   1006 
   1007  done:
   1008 	if ( !BER_BVISEMPTY( &dn ) )
   1009 		ber_memfree( dn.bv_val );
   1010 	if ( !BER_BVISEMPTY( &ndn ) )
   1011 		ber_memfree( ndn.bv_val );
   1012 	return rc;
   1013 }
   1014 
   1015 static int
   1016 search_tree( Operation *op, SlapReply *rs )
   1017 {
   1018 	int rc = LDAP_SUCCESS;
   1019 	Entry *e = NULL;
   1020 	struct berval path;
   1021 	struct berval pdn, pndn;
   1022 
   1023 	(void) ndn2path( op, &op->o_req_ndn, &path, 1 );
   1024 	if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
   1025 		/* Read baseObject */
   1026 		dnParent( &op->o_req_dn, &pdn );
   1027 		dnParent( &op->o_req_ndn, &pndn );
   1028 		rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
   1029 			rs == NULL ? NULL : &rs->sr_text );
   1030 	}
   1031 	if ( rc == LDAP_SUCCESS )
   1032 		rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
   1033 
   1034 	ch_free( path.bv_val );
   1035 	return rc;
   1036 }
   1037 
   1038 
   1039 /*
   1040  * Prepare to create or rename an entry:
   1041  * Check that the entry does not already exist.
   1042  * Check that the parent entry exists and can have subordinates,
   1043  * unless need_dir is NULL or adding the suffix entry.
   1044  *
   1045  * Return an LDAP result code.  May set *text to a message on failure.
   1046  * If success, set *dnpath to LDIF entry path and *need_dir to
   1047  * (directory must be created ? dirname : NULL).
   1048  */
   1049 static int
   1050 ldif_prepare_create(
   1051 	Operation *op,
   1052 	Entry *e,
   1053 	struct berval *dnpath,
   1054 	char **need_dir,
   1055 	const char **text )
   1056 {
   1057 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1058 	struct berval *ndn = &e->e_nname;
   1059 	struct berval ppath = BER_BVNULL;
   1060 	struct stat st;
   1061 	Entry *parent = NULL;
   1062 	int rc;
   1063 	char ebuf[128];
   1064 
   1065 	if ( op->o_abandon )
   1066 		return SLAPD_ABANDON;
   1067 
   1068 	rc = ndn2path( op, ndn, dnpath, 0 );
   1069 	if ( rc != LDAP_SUCCESS ) {
   1070 		return rc;
   1071 	}
   1072 
   1073 	if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
   1074 		rc = LDAP_ALREADY_EXISTS;
   1075 
   1076 	} else if ( errno != ENOENT ) {
   1077 		Debug( LDAP_DEBUG_ANY,
   1078 			"ldif_prepare_create: cannot stat \"%s\": %s\n",
   1079 			dnpath->bv_val, AC_STRERROR_R( errno, ebuf, sizeof(ebuf) ) );
   1080 		rc = LDAP_OTHER;
   1081 		*text = "internal error (cannot check entry file)";
   1082 
   1083 	} else if ( need_dir != NULL ) {
   1084 		*need_dir = NULL;
   1085 		rc = get_parent_path( dnpath, &ppath );
   1086 		/* If parent dir exists, so does parent .ldif:
   1087 		 * The directory gets created after and removed before the .ldif.
   1088 		 * Except with the database directory, which has no matching entry.
   1089 		 */
   1090 		if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
   1091 			rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
   1092 				? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
   1093 		}
   1094 		switch ( rc ) {
   1095 		case LDAP_NO_SUCH_OBJECT:
   1096 			/* No parent dir, check parent .ldif */
   1097 			dir2ldif_name( ppath );
   1098 			rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
   1099 				(op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
   1100 				 ? &parent : NULL),
   1101 				text );
   1102 			switch ( rc ) {
   1103 			case LDAP_SUCCESS:
   1104 				/* Check that parent is not a referral, unless
   1105 				 * ldif_back_referrals() already checked.
   1106 				 */
   1107 				if ( parent != NULL ) {
   1108 					int is_ref = is_entry_referral( parent );
   1109 					entry_free( parent );
   1110 					if ( is_ref ) {
   1111 						rc = LDAP_AFFECTS_MULTIPLE_DSAS;
   1112 						*text = op->o_tag == LDAP_REQ_MODDN
   1113 							? "newSuperior is a referral object"
   1114 							: "parent is a referral object";
   1115 						break;
   1116 					}
   1117 				}
   1118 				/* Must create parent directory. */
   1119 				ldif2dir_name( ppath );
   1120 				*need_dir = ppath.bv_val;
   1121 				break;
   1122 			case LDAP_NO_SUCH_OBJECT:
   1123 				*text = op->o_tag == LDAP_REQ_MODDN
   1124 					? "newSuperior object does not exist"
   1125 					: "parent does not exist";
   1126 				break;
   1127 			}
   1128 			break;
   1129 		case LDAP_OTHER:
   1130 			Debug( LDAP_DEBUG_ANY,
   1131 				"ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
   1132 				ndn->bv_val, AC_STRERROR_R( errno, ebuf, sizeof(ebuf) ) );
   1133 			*text = "internal error (cannot stat parent dir)";
   1134 			break;
   1135 		}
   1136 		if ( *need_dir == NULL && ppath.bv_val != NULL )
   1137 			SLAP_FREE( ppath.bv_val );
   1138 	}
   1139 
   1140 	if ( rc != LDAP_SUCCESS ) {
   1141 		SLAP_FREE( dnpath->bv_val );
   1142 		BER_BVZERO( dnpath );
   1143 	}
   1144 	return rc;
   1145 }
   1146 
   1147 static int
   1148 apply_modify_to_entry(
   1149 	Entry *entry,
   1150 	Modifications *modlist,
   1151 	Operation *op,
   1152 	SlapReply *rs,
   1153 	char *textbuf )
   1154 {
   1155 	int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
   1156 	int is_oc = 0;
   1157 	Modification *mods;
   1158 
   1159 	if (!acl_check_modlist(op, entry, modlist)) {
   1160 		return LDAP_INSUFFICIENT_ACCESS;
   1161 	}
   1162 
   1163 	for (; modlist != NULL; modlist = modlist->sml_next) {
   1164 		mods = &modlist->sml_mod;
   1165 
   1166 		if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
   1167 			is_oc = 1;
   1168 		}
   1169 		switch (mods->sm_op) {
   1170 		case LDAP_MOD_ADD:
   1171 			rc = modify_add_values(entry, mods,
   1172 				   get_permissiveModify(op),
   1173 				   &rs->sr_text, textbuf,
   1174 				   SLAP_TEXT_BUFLEN );
   1175 			break;
   1176 
   1177 		case LDAP_MOD_DELETE:
   1178 			rc = modify_delete_values(entry, mods,
   1179 				get_permissiveModify(op),
   1180 				&rs->sr_text, textbuf,
   1181 				SLAP_TEXT_BUFLEN );
   1182 			break;
   1183 
   1184 		case LDAP_MOD_REPLACE:
   1185 			rc = modify_replace_values(entry, mods,
   1186 				 get_permissiveModify(op),
   1187 				 &rs->sr_text, textbuf,
   1188 				 SLAP_TEXT_BUFLEN );
   1189 			break;
   1190 
   1191 		case LDAP_MOD_INCREMENT:
   1192 			rc = modify_increment_values( entry,
   1193 				mods, get_permissiveModify(op),
   1194 				&rs->sr_text, textbuf,
   1195 				SLAP_TEXT_BUFLEN );
   1196 			break;
   1197 
   1198 		case SLAP_MOD_SOFTADD:
   1199 			mods->sm_op = LDAP_MOD_ADD;
   1200 			rc = modify_add_values(entry, mods,
   1201 				   get_permissiveModify(op),
   1202 				   &rs->sr_text, textbuf,
   1203 				   SLAP_TEXT_BUFLEN );
   1204 			mods->sm_op = SLAP_MOD_SOFTADD;
   1205 			if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
   1206 				rc = LDAP_SUCCESS;
   1207 			}
   1208 			break;
   1209 
   1210 		case SLAP_MOD_SOFTDEL:
   1211 			mods->sm_op = LDAP_MOD_DELETE;
   1212 			rc = modify_delete_values(entry, mods,
   1213 				   get_permissiveModify(op),
   1214 				   &rs->sr_text, textbuf,
   1215 				   SLAP_TEXT_BUFLEN );
   1216 			mods->sm_op = SLAP_MOD_SOFTDEL;
   1217 			if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
   1218 				rc = LDAP_SUCCESS;
   1219 			}
   1220 			break;
   1221 
   1222 		case SLAP_MOD_ADD_IF_NOT_PRESENT:
   1223 			if ( attr_find( entry->e_attrs, mods->sm_desc ) ) {
   1224 				rc = LDAP_SUCCESS;
   1225 				break;
   1226 			}
   1227 			mods->sm_op = LDAP_MOD_ADD;
   1228 			rc = modify_add_values(entry, mods,
   1229 				   get_permissiveModify(op),
   1230 				   &rs->sr_text, textbuf,
   1231 				   SLAP_TEXT_BUFLEN );
   1232 			mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
   1233 			break;
   1234 		}
   1235 		if(rc != LDAP_SUCCESS) break;
   1236 	}
   1237 
   1238 	if ( rc == LDAP_SUCCESS ) {
   1239 		rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
   1240 		if ( is_oc ) {
   1241 			entry->e_ocflags = 0;
   1242 		}
   1243 		/* check that the entry still obeys the schema */
   1244 		rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
   1245 			  &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN );
   1246 	}
   1247 
   1248 	return rc;
   1249 }
   1250 
   1251 
   1252 static int
   1253 ldif_back_referrals( Operation *op, SlapReply *rs )
   1254 {
   1255 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1256 	struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn;
   1257 	ber_len_t min_dnlen;
   1258 	Entry *entry = NULL, **entryp;
   1259 	BerVarray ref;
   1260 	int rc;
   1261 
   1262 	min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
   1263 	if ( min_dnlen == 0 ) {
   1264 		/* Catch root DSE (empty DN), it is not a referral */
   1265 		min_dnlen = 1;
   1266 	}
   1267 	if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) {
   1268 		return LDAP_SUCCESS;	/* Root DSE again */
   1269 	}
   1270 
   1271 	entryp = get_manageDSAit( op ) ? NULL : &entry;
   1272 	ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
   1273 
   1274 	for (;;) {
   1275 		dnParent( &dn, &dn );
   1276 		dnParent( &ndn, &ndn );
   1277 		rc = ldif_read_entry( op, path.bv_val, &dn, &ndn,
   1278 			entryp, &rs->sr_text );
   1279 		if ( rc != LDAP_NO_SUCH_OBJECT )
   1280 			break;
   1281 
   1282 		rc = LDAP_SUCCESS;
   1283 		if ( ndn.bv_len < min_dnlen )
   1284 			break;
   1285 		(void) get_parent_path( &path, NULL );
   1286 		dir2ldif_name( path );
   1287 		entryp = &entry;
   1288 	}
   1289 
   1290 	ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
   1291 	SLAP_FREE( path.bv_val );
   1292 
   1293 	if ( entry != NULL ) {
   1294 		if ( is_entry_referral( entry ) ) {
   1295 			Debug( LDAP_DEBUG_TRACE,
   1296 				"ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
   1297 				(unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn );
   1298 
   1299 			ref = get_entry_referrals( op, entry );
   1300 			rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn,
   1301 				op->o_tag == LDAP_REQ_SEARCH ?
   1302 				op->ors_scope : LDAP_SCOPE_DEFAULT );
   1303 			ber_bvarray_free( ref );
   1304 
   1305 			if ( rs->sr_ref != NULL ) {
   1306 				/* send referral */
   1307 				rc = rs->sr_err = LDAP_REFERRAL;
   1308 				rs->sr_matched = entry->e_dn;
   1309 				send_ldap_result( op, rs );
   1310 				ber_bvarray_free( rs->sr_ref );
   1311 				rs->sr_ref = NULL;
   1312 			} else {
   1313 				rc = LDAP_OTHER;
   1314 				rs->sr_text = "bad referral object";
   1315 			}
   1316 			rs->sr_matched = NULL;
   1317 		}
   1318 
   1319 		entry_free( entry );
   1320 	}
   1321 
   1322 	return rc;
   1323 }
   1324 
   1325 
   1326 /* LDAP operations */
   1327 
   1328 static int
   1329 ldif_back_bind( Operation *op, SlapReply *rs )
   1330 {
   1331 	struct ldif_info *li;
   1332 	Attribute *a;
   1333 	AttributeDescription *password = slap_schema.si_ad_userPassword;
   1334 	int return_val;
   1335 	Entry *entry = NULL;
   1336 
   1337 	switch ( be_rootdn_bind( op, rs ) ) {
   1338 	case SLAP_CB_CONTINUE:
   1339 		break;
   1340 
   1341 	default:
   1342 		/* in case of success, front end will send result;
   1343 		 * otherwise, be_rootdn_bind() did */
   1344 		return rs->sr_err;
   1345 	}
   1346 
   1347 	li = (struct ldif_info *) op->o_bd->be_private;
   1348 	ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
   1349 	return_val = get_entry(op, &entry, NULL, NULL);
   1350 
   1351 	/* no object is found for them */
   1352 	if(return_val != LDAP_SUCCESS) {
   1353 		rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
   1354 		goto return_result;
   1355 	}
   1356 
   1357 	/* they don't have userpassword */
   1358 	if((a = attr_find(entry->e_attrs, password)) == NULL) {
   1359 		rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
   1360 		return_val = 1;
   1361 		goto return_result;
   1362 	}
   1363 
   1364 	/* authentication actually failed */
   1365 	if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
   1366 			     &rs->sr_text) != 0) {
   1367 		rs->sr_err = LDAP_INVALID_CREDENTIALS;
   1368 		return_val = 1;
   1369 		goto return_result;
   1370 	}
   1371 
   1372 	/* let the front-end send success */
   1373 	return_val = LDAP_SUCCESS;
   1374 
   1375  return_result:
   1376 	ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
   1377 	if(return_val != LDAP_SUCCESS)
   1378 		send_ldap_result( op, rs );
   1379 	if(entry != NULL)
   1380 		entry_free(entry);
   1381 	return return_val;
   1382 }
   1383 
   1384 static int
   1385 ldif_back_search( Operation *op, SlapReply *rs )
   1386 {
   1387 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1388 
   1389 	ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
   1390 	rs->sr_err = search_tree( op, rs );
   1391 	ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
   1392 	send_ldap_result(op, rs);
   1393 
   1394 	return rs->sr_err;
   1395 }
   1396 
   1397 static int
   1398 ldif_back_add( Operation *op, SlapReply *rs )
   1399 {
   1400 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1401 	Entry * e = op->ora_e;
   1402 	struct berval path;
   1403 	char *parentdir;
   1404 	char textbuf[SLAP_TEXT_BUFLEN];
   1405 	int rc;
   1406 
   1407 	Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn );
   1408 
   1409 	rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
   1410 		&rs->sr_text, textbuf, sizeof( textbuf ) );
   1411 	if ( rc != LDAP_SUCCESS )
   1412 		goto send_res;
   1413 
   1414 	rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
   1415 	if ( rc != LDAP_SUCCESS )
   1416 		goto send_res;
   1417 
   1418 	ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
   1419 
   1420 	rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
   1421 	if ( rc == LDAP_SUCCESS ) {
   1422 		ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
   1423 		rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
   1424 		ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
   1425 
   1426 		SLAP_FREE( path.bv_val );
   1427 		if ( parentdir != NULL )
   1428 			SLAP_FREE( parentdir );
   1429 	}
   1430 
   1431 	ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
   1432 
   1433  send_res:
   1434 	rs->sr_err = rc;
   1435 	Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
   1436 		rc, rs->sr_text ? rs->sr_text : "" );
   1437 	send_ldap_result( op, rs );
   1438 	slap_graduate_commit_csn( op );
   1439 	rs->sr_text = NULL;	/* remove possible pointer to textbuf */
   1440 	return rs->sr_err;
   1441 }
   1442 
   1443 static int
   1444 ldif_back_modify( Operation *op, SlapReply *rs )
   1445 {
   1446 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1447 	Modifications * modlst = op->orm_modlist;
   1448 	struct berval path;
   1449 	Entry *entry;
   1450 	char textbuf[SLAP_TEXT_BUFLEN];
   1451 	int rc;
   1452 
   1453 	slap_mods_opattrs( op, &op->orm_modlist, 1 );
   1454 
   1455 	ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
   1456 
   1457 	rc = get_entry( op, &entry, &path, &rs->sr_text );
   1458 	if ( rc == LDAP_SUCCESS ) {
   1459 		rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
   1460 		if ( rc == LDAP_SUCCESS ) {
   1461 			ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
   1462 			rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
   1463 			ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
   1464 		}
   1465 
   1466 		entry_free( entry );
   1467 		SLAP_FREE( path.bv_val );
   1468 	}
   1469 
   1470 	ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
   1471 
   1472 	rs->sr_err = rc;
   1473 	send_ldap_result( op, rs );
   1474 	slap_graduate_commit_csn( op );
   1475 	rs->sr_text = NULL;	/* remove possible pointer to textbuf */
   1476 	return rs->sr_err;
   1477 }
   1478 
   1479 static int
   1480 ldif_back_delete( Operation *op, SlapReply *rs )
   1481 {
   1482 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1483 	struct berval path;
   1484 	int rc = LDAP_SUCCESS;
   1485 	char ebuf[128];
   1486 
   1487 	if ( BER_BVISEMPTY( &op->o_csn )) {
   1488 		struct berval csn;
   1489 		char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
   1490 
   1491 		csn.bv_val = csnbuf;
   1492 		csn.bv_len = sizeof( csnbuf );
   1493 		slap_get_csn( op, &csn, 1 );
   1494 	}
   1495 
   1496 	ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
   1497 	ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
   1498 	if ( op->o_abandon ) {
   1499 		rc = SLAPD_ABANDON;
   1500 		goto done;
   1501 	}
   1502 
   1503 	rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
   1504 	if ( rc != LDAP_SUCCESS ) {
   1505 		goto done;
   1506 	}
   1507 
   1508 	ldif2dir_len( path );
   1509 	ldif2dir_name( path );
   1510 	if ( rmdir( path.bv_val ) < 0 ) {
   1511 		switch ( errno ) {
   1512 		case ENOTEMPTY:
   1513 			rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
   1514 			break;
   1515 		case ENOENT:
   1516 			/* is leaf, go on */
   1517 			break;
   1518 		default:
   1519 			rc = LDAP_OTHER;
   1520 			rs->sr_text = "internal error (cannot delete subtree directory)";
   1521 			break;
   1522 		}
   1523 	}
   1524 
   1525 	if ( rc == LDAP_SUCCESS ) {
   1526 		dir2ldif_name( path );
   1527 		if ( unlink( path.bv_val ) < 0 ) {
   1528 			rc = LDAP_NO_SUCH_OBJECT;
   1529 			if ( errno != ENOENT ) {
   1530 				rc = LDAP_OTHER;
   1531 				rs->sr_text = "internal error (cannot delete entry file)";
   1532 			}
   1533 		}
   1534 	}
   1535 
   1536 	if ( rc == LDAP_OTHER ) {
   1537 		Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
   1538 			"cannot delete", path.bv_val, AC_STRERROR_R( errno, ebuf, sizeof(ebuf) ) );
   1539 	}
   1540 
   1541 	SLAP_FREE( path.bv_val );
   1542  done:
   1543 	ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
   1544 	ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
   1545 	rs->sr_err = rc;
   1546 	send_ldap_result( op, rs );
   1547 	slap_graduate_commit_csn( op );
   1548 	return rs->sr_err;
   1549 }
   1550 
   1551 
   1552 static int
   1553 ldif_move_entry(
   1554 	Operation *op,
   1555 	Entry *entry,
   1556 	int same_ndn,
   1557 	struct berval *oldpath,
   1558 	const char **text )
   1559 {
   1560 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1561 	struct berval newpath;
   1562 	char *parentdir = NULL, *trash;
   1563 	int rc, rename_res;
   1564 	char ebuf[128];
   1565 
   1566 	if ( same_ndn ) {
   1567 		rc = LDAP_SUCCESS;
   1568 		newpath = *oldpath;
   1569 	} else {
   1570 		rc = ldif_prepare_create( op, entry, &newpath,
   1571 			op->orr_newSup ? &parentdir : NULL, text );
   1572 	}
   1573 
   1574 	if ( rc == LDAP_SUCCESS ) {
   1575 		ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
   1576 
   1577 		rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
   1578 		if ( rc == LDAP_SUCCESS && !same_ndn ) {
   1579 			trash = oldpath->bv_val; /* will be .ldif file to delete */
   1580 			ldif2dir_len( newpath );
   1581 			ldif2dir_len( *oldpath );
   1582 			/* Move subdir before deleting old entry,
   1583 			 * so .ldif always exists if subdir does.
   1584 			 */
   1585 			ldif2dir_name( newpath );
   1586 			ldif2dir_name( *oldpath );
   1587 			rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
   1588 			if ( rename_res != 0 && errno != ENOENT ) {
   1589 				rc = LDAP_OTHER;
   1590 				*text = "internal error (cannot move this subtree)";
   1591 				trash = newpath.bv_val;
   1592 			}
   1593 
   1594 			/* Delete old entry, or if error undo change */
   1595 			for (;;) {
   1596 				dir2ldif_name( newpath );
   1597 				dir2ldif_name( *oldpath );
   1598 				if ( unlink( trash ) == 0 )
   1599 					break;
   1600 				if ( rc == LDAP_SUCCESS ) {
   1601 					/* Prepare to undo change and return failure */
   1602 					rc = LDAP_OTHER;
   1603 					*text = "internal error (cannot move this entry)";
   1604 					trash = newpath.bv_val;
   1605 					if ( rename_res != 0 )
   1606 						continue;
   1607 					/* First move subdirectory back */
   1608 					ldif2dir_name( newpath );
   1609 					ldif2dir_name( *oldpath );
   1610 					if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
   1611 						continue;
   1612 				}
   1613 				*text = "added new but couldn't delete old entry!";
   1614 				break;
   1615 			}
   1616 
   1617 			if ( rc != LDAP_SUCCESS ) {
   1618 				Debug(LDAP_DEBUG_ANY,
   1619 				      "ldif_move_entry: %s (%s): \"%s\" -> \"%s\"\n",
   1620 				      *text, AC_STRERROR_R(errno, ebuf, sizeof(ebuf)),
   1621 				      op->o_req_dn.bv_val, entry->e_dn );
   1622 			}
   1623 		}
   1624 
   1625 		ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
   1626 		if ( !same_ndn )
   1627 			SLAP_FREE( newpath.bv_val );
   1628 		if ( parentdir != NULL )
   1629 			SLAP_FREE( parentdir );
   1630 	}
   1631 
   1632 	return rc;
   1633 }
   1634 
   1635 static int
   1636 ldif_back_modrdn( Operation *op, SlapReply *rs )
   1637 {
   1638 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1639 	struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
   1640 	struct berval p_dn, old_path;
   1641 	Entry *entry;
   1642 	char textbuf[SLAP_TEXT_BUFLEN];
   1643 	int rc, same_ndn;
   1644 
   1645 	slap_mods_opattrs( op, &op->orr_modlist, 1 );
   1646 
   1647 	ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
   1648 
   1649 	rc = get_entry( op, &entry, &old_path, &rs->sr_text );
   1650 	if ( rc == LDAP_SUCCESS ) {
   1651 		/* build new dn, and new ndn for the entry */
   1652 		if ( op->oq_modrdn.rs_newSup != NULL ) {
   1653 			p_dn = *op->oq_modrdn.rs_newSup;
   1654 		} else {
   1655 			dnParent( &entry->e_name, &p_dn );
   1656 		}
   1657 		build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
   1658 		dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
   1659 		same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
   1660 		ber_memfree_x( entry->e_name.bv_val, NULL );
   1661 		ber_memfree_x( entry->e_nname.bv_val, NULL );
   1662 		entry->e_name = new_dn;
   1663 		entry->e_nname = new_ndn;
   1664 
   1665 		/* perform the modifications */
   1666 		rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
   1667 		if ( rc == LDAP_SUCCESS )
   1668 			rc = ldif_move_entry( op, entry, same_ndn, &old_path,
   1669 				&rs->sr_text );
   1670 
   1671 		entry_free( entry );
   1672 		SLAP_FREE( old_path.bv_val );
   1673 	}
   1674 
   1675 	ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
   1676 	rs->sr_err = rc;
   1677 	send_ldap_result( op, rs );
   1678 	slap_graduate_commit_csn( op );
   1679 	rs->sr_text = NULL;	/* remove possible pointer to textbuf */
   1680 	return rs->sr_err;
   1681 }
   1682 
   1683 
   1684 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
   1685 static int
   1686 ldif_back_entry_get(
   1687 	Operation *op,
   1688 	struct berval *ndn,
   1689 	ObjectClass *oc,
   1690 	AttributeDescription *at,
   1691 	int rw,
   1692 	Entry **e )
   1693 {
   1694 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1695 	struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
   1696 	int rc;
   1697 
   1698 	assert( ndn != NULL );
   1699 	assert( !BER_BVISNULL( ndn ) );
   1700 
   1701 	ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
   1702 	op->o_req_dn = *ndn;
   1703 	op->o_req_ndn = *ndn;
   1704 	rc = get_entry( op, e, NULL, NULL );
   1705 	op->o_req_dn = op_dn;
   1706 	op->o_req_ndn = op_ndn;
   1707 	ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
   1708 
   1709 	if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
   1710 		rc = LDAP_NO_SUCH_ATTRIBUTE;
   1711 		entry_free( *e );
   1712 		*e = NULL;
   1713 	}
   1714 
   1715 	return rc;
   1716 }
   1717 
   1718 static int
   1719 ldif_back_entry_release_rw (
   1720 	Operation *op,
   1721 	Entry *e,
   1722 	int rw )
   1723 {
   1724 	ID id = e->e_id;
   1725 
   1726 	/* only tool mode assigns valid IDs */
   1727 	if ( id != 0 && id != NOID )
   1728 	{
   1729 		struct ldif_tool *tl = &((struct ldif_info *) op->o_bd->be_private)->li_tool;
   1730 
   1731 		id--;
   1732 
   1733 		assert( id < tl->ecount );
   1734 		assert( e == tl->entries[id] );
   1735 		tl->entries[id] = NULL;
   1736 	}
   1737 
   1738 	entry_free( e );
   1739 	return 0;
   1740 }
   1741 
   1742 
   1743 /* Slap tools */
   1744 
   1745 static int
   1746 ldif_tool_entry_open( BackendDB *be, int mode )
   1747 {
   1748 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1749 
   1750 	tl->ecurrent = 0;
   1751 	return 0;
   1752 }
   1753 
   1754 static int
   1755 ldif_tool_entry_close( BackendDB *be )
   1756 {
   1757 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1758 	Entry **entries = tl->entries;
   1759 	ID i;
   1760 
   1761 	for ( i = tl->ecount; i--; )
   1762 		if ( entries[i] )
   1763 			entry_free( entries[i] );
   1764 	SLAP_FREE( entries );
   1765 	tl->entries = NULL;
   1766 	tl->ecount = tl->elen = 0;
   1767 	return 0;
   1768 }
   1769 
   1770 static ID
   1771 ldif_tool_entry_next( BackendDB *be )
   1772 {
   1773 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1774 
   1775 	do {
   1776 		Entry *e = tl->entries[ tl->ecurrent ];
   1777 
   1778 		if ( tl->ecurrent >= tl->ecount ) {
   1779 			return NOID;
   1780 		}
   1781 
   1782 		++tl->ecurrent;
   1783 
   1784 		if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
   1785 			continue;
   1786 		}
   1787 
   1788 		if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter  ) != LDAP_COMPARE_TRUE ) {
   1789 			continue;
   1790 		}
   1791 
   1792 		break;
   1793 	} while ( 1 );
   1794 
   1795 	return tl->ecurrent;
   1796 }
   1797 
   1798 static ID
   1799 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
   1800 {
   1801 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1802 
   1803 	tl->tl_base = base;
   1804 	tl->tl_scope = scope;
   1805 	tl->tl_filter = f;
   1806 
   1807 	if ( tl->entries == NULL ) {
   1808 		Operation op = {0};
   1809 
   1810 		op.o_bd = be;
   1811 		op.o_req_dn = *be->be_suffix;
   1812 		op.o_req_ndn = *be->be_nsuffix;
   1813 		op.ors_scope = LDAP_SCOPE_SUBTREE;
   1814 		if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
   1815 			tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
   1816 			return NOID; /* fail ldif_tool_entry_get() */
   1817 		}
   1818 	}
   1819 	return ldif_tool_entry_next( be );
   1820 }
   1821 
   1822 static ID
   1823 ldif_tool_dn2id_get( BackendDB *be, struct berval *dn )
   1824 {
   1825 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1826 
   1827 	Operation op = {0};
   1828 
   1829 	op.o_bd = be;
   1830 	op.o_req_dn = *dn;
   1831 	op.o_req_ndn = *dn;
   1832 	op.ors_scope = LDAP_SCOPE_BASE;
   1833 	if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
   1834 		return NOID;
   1835 	}
   1836 	return tl->ecount;
   1837 }
   1838 
   1839 static Entry *
   1840 ldif_tool_entry_get( BackendDB *be, ID id )
   1841 {
   1842 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1843 	Entry *e = NULL;
   1844 
   1845 	--id;
   1846 	if ( id < tl->ecount ) {
   1847 		e = tl->entries[id];
   1848 	}
   1849 	return e;
   1850 }
   1851 
   1852 static ID
   1853 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
   1854 {
   1855 	int rc;
   1856 	const char *errmsg = NULL;
   1857 	struct berval path;
   1858 	char *parentdir;
   1859 	Operation op = {0};
   1860 
   1861 	op.o_bd = be;
   1862 	rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
   1863 	if ( rc == LDAP_SUCCESS ) {
   1864 		rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
   1865 
   1866 		SLAP_FREE( path.bv_val );
   1867 		if ( parentdir != NULL )
   1868 			SLAP_FREE( parentdir );
   1869 		if ( rc == LDAP_SUCCESS )
   1870 			return 1;
   1871 	}
   1872 
   1873 	if ( errmsg == NULL && rc != LDAP_OTHER )
   1874 		errmsg = ldap_err2string( rc );
   1875 	if ( errmsg != NULL )
   1876 		snprintf( text->bv_val, text->bv_len, "%s", errmsg );
   1877 	return NOID;
   1878 }
   1879 
   1880 static ID
   1881 ldif_tool_entry_modify( BackendDB *be, Entry *e, struct berval *text )
   1882 {
   1883 	int rc;
   1884 	const char *errmsg = NULL;
   1885 	struct berval path;
   1886 	Operation op = {0};
   1887 
   1888 	op.o_bd = be;
   1889 	ndn2path( &op, &e->e_nname, &path, 0 );
   1890 	rc = ldif_write_entry( &op, e, &path, NULL, &errmsg );
   1891 	SLAP_FREE( path.bv_val );
   1892 	if ( rc == LDAP_SUCCESS )
   1893 		return 1;
   1894 
   1895 	if ( errmsg == NULL && rc != LDAP_OTHER )
   1896 		errmsg = ldap_err2string( rc );
   1897 	if ( errmsg != NULL )
   1898 		snprintf( text->bv_val, text->bv_len, "%s", errmsg );
   1899 	return NOID;
   1900 }
   1901 
   1902 static int
   1903 ldif_tool_entry_delete( BackendDB *be, struct berval *ndn, struct berval *text )
   1904 {
   1905 	int rc = LDAP_SUCCESS;
   1906 	const char *errmsg = NULL;
   1907 	struct berval path;
   1908 	Operation op = {0};
   1909 
   1910 	op.o_bd = be;
   1911 	ndn2path( &op, ndn, &path, 0 );
   1912 
   1913 	ldif2dir_len( path );
   1914 	ldif2dir_name( path );
   1915 	if ( rmdir( path.bv_val ) < 0 ) {
   1916 		switch ( errno ) {
   1917 		case ENOTEMPTY:
   1918 			rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
   1919 			break;
   1920 		case ENOENT:
   1921 			/* is leaf, go on */
   1922 			break;
   1923 		default:
   1924 			rc = LDAP_OTHER;
   1925 			errmsg = "internal error (cannot delete subtree directory)";
   1926 			break;
   1927 		}
   1928 	}
   1929 
   1930 	if ( rc == LDAP_SUCCESS ) {
   1931 		dir2ldif_name( path );
   1932 		if ( unlink( path.bv_val ) < 0 ) {
   1933 			rc = LDAP_NO_SUCH_OBJECT;
   1934 			if ( errno != ENOENT ) {
   1935 				rc = LDAP_OTHER;
   1936 				errmsg = "internal error (cannot delete entry file)";
   1937 			}
   1938 		}
   1939 	}
   1940 
   1941 	SLAP_FREE( path.bv_val );
   1942 
   1943 	if ( errmsg == NULL && rc != LDAP_OTHER )
   1944 		errmsg = ldap_err2string( rc );
   1945 	if ( errmsg != NULL )
   1946 		snprintf( text->bv_val, text->bv_len, "%s", errmsg );
   1947 	return rc;
   1948 }
   1949 
   1950 
   1951 /* Setup */
   1952 
   1953 static int
   1954 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
   1955 {
   1956 	struct ldif_info *li;
   1957 
   1958 	li = ch_calloc( 1, sizeof(struct ldif_info) );
   1959 	be->be_private = li;
   1960 	be->be_cf_ocs = ldifocs;
   1961 	ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
   1962 	ldap_pvt_thread_rdwr_init( &li->li_rdwr );
   1963 	SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
   1964 	return 0;
   1965 }
   1966 
   1967 static int
   1968 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
   1969 {
   1970 	struct ldif_info *li = be->be_private;
   1971 
   1972 	ch_free( li->li_base_path.bv_val );
   1973 	ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
   1974 	ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
   1975 	free( be->be_private );
   1976 	return 0;
   1977 }
   1978 
   1979 static int
   1980 ldif_back_db_open( Backend *be, ConfigReply *cr )
   1981 {
   1982 	struct ldif_info *li = (struct ldif_info *) be->be_private;
   1983 	if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
   1984 		Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n" );
   1985 		return 1;
   1986 	}
   1987 	return 0;
   1988 }
   1989 
   1990 int
   1991 ldif_back_initialize( BackendInfo *bi )
   1992 {
   1993 	static char *controls[] = {
   1994 		LDAP_CONTROL_MANAGEDSAIT,
   1995 		NULL
   1996 	};
   1997 	int rc;
   1998 
   1999 	bi->bi_flags |=
   2000 		SLAP_BFLAG_INCREMENT |
   2001 		SLAP_BFLAG_REFERRALS;
   2002 
   2003 	bi->bi_controls = controls;
   2004 
   2005 	bi->bi_open = 0;
   2006 	bi->bi_close = 0;
   2007 	bi->bi_config = 0;
   2008 	bi->bi_destroy = 0;
   2009 
   2010 	bi->bi_db_init = ldif_back_db_init;
   2011 	bi->bi_db_config = config_generic_wrapper;
   2012 	bi->bi_db_open = ldif_back_db_open;
   2013 	bi->bi_db_close = 0;
   2014 	bi->bi_db_destroy = ldif_back_db_destroy;
   2015 
   2016 	bi->bi_op_bind = ldif_back_bind;
   2017 	bi->bi_op_unbind = 0;
   2018 	bi->bi_op_search = ldif_back_search;
   2019 	bi->bi_op_compare = 0;
   2020 	bi->bi_op_modify = ldif_back_modify;
   2021 	bi->bi_op_modrdn = ldif_back_modrdn;
   2022 	bi->bi_op_add = ldif_back_add;
   2023 	bi->bi_op_delete = ldif_back_delete;
   2024 	bi->bi_op_abandon = 0;
   2025 
   2026 	bi->bi_extended = 0;
   2027 
   2028 	bi->bi_chk_referrals = ldif_back_referrals;
   2029 
   2030 	bi->bi_connection_init = 0;
   2031 	bi->bi_connection_destroy = 0;
   2032 
   2033 	bi->bi_entry_get_rw = ldif_back_entry_get;
   2034 	bi->bi_entry_release_rw = ldif_back_entry_release_rw;
   2035 
   2036 #if 0	/* NOTE: uncomment to completely disable access control */
   2037 	bi->bi_access_allowed = slap_access_always_allowed;
   2038 #endif
   2039 
   2040 	bi->bi_tool_entry_open = ldif_tool_entry_open;
   2041 	bi->bi_tool_entry_close = ldif_tool_entry_close;
   2042 	bi->bi_tool_entry_first = backend_tool_entry_first;
   2043 	bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
   2044 	bi->bi_tool_entry_next = ldif_tool_entry_next;
   2045 	bi->bi_tool_dn2id_get = ldif_tool_dn2id_get;
   2046 	bi->bi_tool_entry_get = ldif_tool_entry_get;
   2047 	bi->bi_tool_entry_put = ldif_tool_entry_put;
   2048 	bi->bi_tool_entry_modify = ldif_tool_entry_modify;
   2049 	bi->bi_tool_entry_delete = ldif_tool_entry_delete;
   2050 	bi->bi_tool_entry_reindex = 0;
   2051 	bi->bi_tool_sync = 0;
   2052 
   2053 	bi->bi_cf_ocs = ldifocs;
   2054 
   2055 	rc = config_register_schema( ldifcfg, ldifocs );
   2056 	if ( rc ) return rc;
   2057 	return 0;
   2058 }
   2059