Home | History | Annotate | Line # | Download | only in back-ldif
      1 /*	$NetBSD: ldif.c,v 1.4 2025/09/05 21:16:27 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-2024 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.4 2025/09/05 21:16:27 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 	rs->sr_ctrls = NULL;
   1393 	send_ldap_result(op, rs);
   1394 
   1395 	return rs->sr_err;
   1396 }
   1397 
   1398 static int
   1399 ldif_back_add( Operation *op, SlapReply *rs )
   1400 {
   1401 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1402 	Entry * e = op->ora_e;
   1403 	struct berval path;
   1404 	char *parentdir;
   1405 	char textbuf[SLAP_TEXT_BUFLEN];
   1406 	int rc;
   1407 
   1408 	LDAPControl **postread_ctrl = NULL;
   1409 	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
   1410 	int num_ctrls = 0;
   1411 
   1412 	ctrls[num_ctrls] = NULL;
   1413 
   1414 	Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn );
   1415 
   1416 	rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
   1417 		&rs->sr_text, textbuf, sizeof( textbuf ) );
   1418 	if ( rc != LDAP_SUCCESS )
   1419 		goto send_res;
   1420 
   1421 	rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
   1422 	if ( rc != LDAP_SUCCESS )
   1423 		goto send_res;
   1424 
   1425 	ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
   1426 
   1427 	rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
   1428 
   1429 	if ( rc == LDAP_SUCCESS && op->o_postread ) {
   1430 		if ( postread_ctrl == NULL ) {
   1431 			postread_ctrl = &ctrls[num_ctrls++];
   1432 			ctrls[num_ctrls] = NULL;
   1433 		}
   1434 		if ( slap_read_controls( op, rs, e,
   1435 			&slap_post_read_bv, postread_ctrl ) )
   1436 		{
   1437 			Debug( LDAP_DEBUG_ANY, "ldif_back_add: "
   1438 				"post-read failed \"%s\"\n",
   1439 				e->e_name.bv_val );
   1440 			if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
   1441 				/* FIXME: is it correct to abort
   1442 					* operation if control fails? */
   1443 				rc = rs->sr_err;
   1444 			}
   1445 		}
   1446 	}
   1447 
   1448 	if ( rc == LDAP_SUCCESS ) {
   1449 		ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
   1450 		rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
   1451 		ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
   1452 
   1453 		SLAP_FREE( path.bv_val );
   1454 		if ( parentdir != NULL )
   1455 			SLAP_FREE( parentdir );
   1456 	}
   1457 
   1458 	ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
   1459 
   1460  send_res:
   1461 	rs->sr_err = rc;
   1462 	if ( num_ctrls ) rs->sr_ctrls = ctrls;
   1463 	Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
   1464 		rc, rs->sr_text ? rs->sr_text : "" );
   1465 	send_ldap_result( op, rs );
   1466 	slap_graduate_commit_csn( op );
   1467 	rs->sr_text = NULL;	/* remove possible pointer to textbuf */
   1468 	return rs->sr_err;
   1469 }
   1470 
   1471 static int
   1472 ldif_back_modify( Operation *op, SlapReply *rs )
   1473 {
   1474 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1475 	Modifications * modlst = op->orm_modlist;
   1476 	struct berval path;
   1477 	Entry *entry;
   1478 	char textbuf[SLAP_TEXT_BUFLEN];
   1479 	int rc;
   1480 
   1481 	LDAPControl **preread_ctrl = NULL;
   1482 	LDAPControl **postread_ctrl = NULL;
   1483 	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
   1484 	int num_ctrls = 0;
   1485 
   1486 	ctrls[num_ctrls] = NULL;
   1487 
   1488 	slap_mods_opattrs( op, &op->orm_modlist, 1 );
   1489 
   1490 	ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
   1491 
   1492 	rc = get_entry( op, &entry, &path, &rs->sr_text );
   1493 	if ( rc == LDAP_SUCCESS ) {
   1494 		if ( op->o_preread ) {
   1495 			if ( preread_ctrl == NULL ) {
   1496 				preread_ctrl = &ctrls[num_ctrls++];
   1497 				ctrls[num_ctrls] = NULL;
   1498 			}
   1499 			if ( slap_read_controls( op, rs, entry,
   1500 				&slap_pre_read_bv, preread_ctrl ) )
   1501 			{
   1502 				Debug( LDAP_DEBUG_ANY, "ldif_back_modify: "
   1503 					"pre-read failed \"%s\"\n",
   1504 					entry->e_name.bv_val );
   1505 				if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
   1506 					/* FIXME: is it correct to abort
   1507 					 * operation if control fails? */
   1508 					rc = rs->sr_err;
   1509 				}
   1510 			}
   1511 		}
   1512 
   1513 		rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
   1514 
   1515 		if ( rc == LDAP_SUCCESS && op->o_postread ) {
   1516 			if ( postread_ctrl == NULL ) {
   1517 				postread_ctrl = &ctrls[num_ctrls++];
   1518 				ctrls[num_ctrls] = NULL;
   1519 			}
   1520 			if ( slap_read_controls( op, rs, entry,
   1521 				&slap_post_read_bv, postread_ctrl ) )
   1522 			{
   1523 				Debug( LDAP_DEBUG_ANY, "ldif_back_modify: "
   1524 					"post-read failed \"%s\"\n",
   1525 					entry->e_name.bv_val );
   1526 				if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
   1527 					/* FIXME: is it correct to abort
   1528 					 * operation if control fails? */
   1529 					rc = rs->sr_err;
   1530 				}
   1531 			}
   1532 		}
   1533 
   1534 		if ( rc == LDAP_SUCCESS ) {
   1535 			ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
   1536 			rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
   1537 			ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
   1538 		}
   1539 
   1540 		entry_free( entry );
   1541 		SLAP_FREE( path.bv_val );
   1542 	}
   1543 
   1544 	ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
   1545 
   1546 	rs->sr_err = rc;
   1547 	if ( num_ctrls ) rs->sr_ctrls = ctrls;
   1548 	send_ldap_result( op, rs );
   1549 	slap_graduate_commit_csn( op );
   1550 	rs->sr_text = NULL;	/* remove possible pointer to textbuf */
   1551 	return rs->sr_err;
   1552 }
   1553 
   1554 static int
   1555 ldif_back_delete( Operation *op, SlapReply *rs )
   1556 {
   1557 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1558 	struct berval path;
   1559 	int rc = LDAP_SUCCESS;
   1560 	char ebuf[128];
   1561 
   1562 	LDAPControl **preread_ctrl = NULL;
   1563 	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
   1564 	int num_ctrls = 0;
   1565 
   1566 	ctrls[num_ctrls] = NULL;
   1567 
   1568 	if ( BER_BVISEMPTY( &op->o_csn )) {
   1569 		struct berval csn;
   1570 		char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
   1571 
   1572 		csn.bv_val = csnbuf;
   1573 		csn.bv_len = sizeof( csnbuf );
   1574 		slap_get_csn( op, &csn, 1 );
   1575 	}
   1576 
   1577 	ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
   1578 	ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
   1579 	if ( op->o_abandon ) {
   1580 		rc = SLAPD_ABANDON;
   1581 		goto done;
   1582 	}
   1583 
   1584 	/* pre-read */
   1585 	if ( op->o_preread ) {
   1586 		Entry *e = NULL;
   1587 
   1588 		if ( preread_ctrl == NULL ) {
   1589 			preread_ctrl = &ctrls[num_ctrls++];
   1590 			ctrls[num_ctrls] = NULL;
   1591 		}
   1592 		rc = get_entry( op, &e, &path, &rs->sr_text );
   1593 		if ( rc == LDAP_SUCCESS && slap_read_controls( op, rs, e,
   1594 			&slap_pre_read_bv, preread_ctrl ) )
   1595 		{
   1596 			Debug( LDAP_DEBUG_ANY, "ldif_back_delete: "
   1597 				"pre-read failed \"%s\"\n",
   1598 				e->e_name.bv_val );
   1599 			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
   1600 				/* FIXME: is it correct to abort
   1601 				 * operation if control fails? */
   1602 				rc = rs->sr_err;
   1603 			}
   1604 		}
   1605 		entry_free( e );
   1606 	} else {
   1607 		rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
   1608 	}
   1609 
   1610 	if ( rc != LDAP_SUCCESS ) {
   1611 		goto done;
   1612 	}
   1613 
   1614 	ldif2dir_len( path );
   1615 	ldif2dir_name( path );
   1616 	if ( rmdir( path.bv_val ) < 0 ) {
   1617 		switch ( errno ) {
   1618 		case ENOTEMPTY:
   1619 			rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
   1620 			break;
   1621 		case ENOENT:
   1622 			/* is leaf, go on */
   1623 			break;
   1624 		default:
   1625 			rc = LDAP_OTHER;
   1626 			rs->sr_text = "internal error (cannot delete subtree directory)";
   1627 			break;
   1628 		}
   1629 	}
   1630 
   1631 	if ( rc == LDAP_SUCCESS ) {
   1632 		dir2ldif_name( path );
   1633 		if ( unlink( path.bv_val ) < 0 ) {
   1634 			rc = LDAP_NO_SUCH_OBJECT;
   1635 			if ( errno != ENOENT ) {
   1636 				rc = LDAP_OTHER;
   1637 				rs->sr_text = "internal error (cannot delete entry file)";
   1638 			}
   1639 		}
   1640 	}
   1641 
   1642 	if ( rc == LDAP_OTHER ) {
   1643 		Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
   1644 			"cannot delete", path.bv_val, AC_STRERROR_R( errno, ebuf, sizeof(ebuf) ) );
   1645 	}
   1646 
   1647 	SLAP_FREE( path.bv_val );
   1648  done:
   1649 	ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
   1650 	ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
   1651 	rs->sr_err = rc;
   1652 	if ( num_ctrls ) rs->sr_ctrls = ctrls;
   1653 	send_ldap_result( op, rs );
   1654 	slap_graduate_commit_csn( op );
   1655 	return rs->sr_err;
   1656 }
   1657 
   1658 
   1659 static int
   1660 ldif_move_entry(
   1661 	Operation *op,
   1662 	Entry *entry,
   1663 	int same_ndn,
   1664 	struct berval *oldpath,
   1665 	const char **text )
   1666 {
   1667 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1668 	struct berval newpath;
   1669 	char *parentdir = NULL, *trash;
   1670 	int rc, rename_res;
   1671 	char ebuf[128];
   1672 
   1673 	if ( same_ndn ) {
   1674 		rc = LDAP_SUCCESS;
   1675 		newpath = *oldpath;
   1676 	} else {
   1677 		rc = ldif_prepare_create( op, entry, &newpath,
   1678 			op->orr_newSup ? &parentdir : NULL, text );
   1679 	}
   1680 
   1681 	if ( rc == LDAP_SUCCESS ) {
   1682 		ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
   1683 
   1684 		rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
   1685 		if ( rc == LDAP_SUCCESS && !same_ndn ) {
   1686 			trash = oldpath->bv_val; /* will be .ldif file to delete */
   1687 			ldif2dir_len( newpath );
   1688 			ldif2dir_len( *oldpath );
   1689 			/* Move subdir before deleting old entry,
   1690 			 * so .ldif always exists if subdir does.
   1691 			 */
   1692 			ldif2dir_name( newpath );
   1693 			ldif2dir_name( *oldpath );
   1694 			rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
   1695 			if ( rename_res != 0 && errno != ENOENT ) {
   1696 				rc = LDAP_OTHER;
   1697 				*text = "internal error (cannot move this subtree)";
   1698 				trash = newpath.bv_val;
   1699 			}
   1700 
   1701 			/* Delete old entry, or if error undo change */
   1702 			for (;;) {
   1703 				dir2ldif_name( newpath );
   1704 				dir2ldif_name( *oldpath );
   1705 				if ( unlink( trash ) == 0 )
   1706 					break;
   1707 				if ( rc == LDAP_SUCCESS ) {
   1708 					/* Prepare to undo change and return failure */
   1709 					rc = LDAP_OTHER;
   1710 					*text = "internal error (cannot move this entry)";
   1711 					trash = newpath.bv_val;
   1712 					if ( rename_res != 0 )
   1713 						continue;
   1714 					/* First move subdirectory back */
   1715 					ldif2dir_name( newpath );
   1716 					ldif2dir_name( *oldpath );
   1717 					if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
   1718 						continue;
   1719 				}
   1720 				*text = "added new but couldn't delete old entry!";
   1721 				break;
   1722 			}
   1723 
   1724 			if ( rc != LDAP_SUCCESS ) {
   1725 				Debug(LDAP_DEBUG_ANY,
   1726 				      "ldif_move_entry: %s (%s): \"%s\" -> \"%s\"\n",
   1727 				      *text, AC_STRERROR_R(errno, ebuf, sizeof(ebuf)),
   1728 				      op->o_req_dn.bv_val, entry->e_dn );
   1729 			}
   1730 		}
   1731 
   1732 		ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
   1733 		if ( !same_ndn )
   1734 			SLAP_FREE( newpath.bv_val );
   1735 		if ( parentdir != NULL )
   1736 			SLAP_FREE( parentdir );
   1737 	}
   1738 
   1739 	return rc;
   1740 }
   1741 
   1742 static int
   1743 ldif_back_modrdn( Operation *op, SlapReply *rs )
   1744 {
   1745 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1746 	struct berval old_path;
   1747 	Entry *entry;
   1748 	char textbuf[SLAP_TEXT_BUFLEN];
   1749 	int rc, same_ndn;
   1750 
   1751 	LDAPControl **preread_ctrl = NULL;
   1752 	LDAPControl **postread_ctrl = NULL;
   1753 	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
   1754 	int num_ctrls = 0;
   1755 
   1756 	ctrls[num_ctrls] = NULL;
   1757 
   1758 	slap_mods_opattrs( op, &op->orr_modlist, 1 );
   1759 
   1760 	ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
   1761 
   1762 	rc = get_entry( op, &entry, &old_path, &rs->sr_text );
   1763 	if ( rc == LDAP_SUCCESS ) {
   1764 		if ( op->o_preread ) {
   1765 			if ( preread_ctrl == NULL ) {
   1766 				preread_ctrl = &ctrls[num_ctrls++];
   1767 				ctrls[num_ctrls] = NULL;
   1768 			}
   1769 			if ( slap_read_controls( op, rs, entry,
   1770 				&slap_pre_read_bv, preread_ctrl ) )
   1771 			{
   1772 				Debug( LDAP_DEBUG_ANY, "ldif_back_modify: "
   1773 					"pre-read failed \"%s\"\n",
   1774 					entry->e_name.bv_val );
   1775 				if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
   1776 					/* FIXME: is it correct to abort
   1777 					 * operation if control fails? */
   1778 					rc = rs->sr_err;
   1779 					goto done;
   1780 				}
   1781 			}
   1782 		}
   1783 
   1784 		same_ndn = !ber_bvcmp( &entry->e_nname, &op->orr_nnewDN );
   1785 		ber_bvreplace( &entry->e_name, &op->orr_newDN );
   1786 		ber_bvreplace( &entry->e_nname, &op->orr_nnewDN );
   1787 
   1788 		/* perform the modifications */
   1789 		rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
   1790 		if ( rc == LDAP_SUCCESS )
   1791 			rc = ldif_move_entry( op, entry, same_ndn, &old_path,
   1792 				&rs->sr_text );
   1793 
   1794 		if ( rc == LDAP_SUCCESS && op->o_postread ) {
   1795 			if ( postread_ctrl == NULL ) {
   1796 				postread_ctrl = &ctrls[num_ctrls++];
   1797 				ctrls[num_ctrls] = NULL;
   1798 			}
   1799 			if ( slap_read_controls( op, rs, entry,
   1800 				&slap_post_read_bv, postread_ctrl ) )
   1801 			{
   1802 				Debug( LDAP_DEBUG_ANY, "ldif_back_modify: "
   1803 					"post-read failed \"%s\"\n",
   1804 					entry->e_name.bv_val );
   1805 				if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
   1806 					/* FIXME: is it correct to abort
   1807 					 * operation if control fails? */
   1808 					rc = rs->sr_err;
   1809 				}
   1810 			}
   1811 		}
   1812 
   1813 		entry_free( entry );
   1814 		SLAP_FREE( old_path.bv_val );
   1815 	}
   1816 
   1817 done:
   1818 	ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
   1819 	if ( num_ctrls ) rs->sr_ctrls = ctrls;
   1820 	rs->sr_err = rc;
   1821 	send_ldap_result( op, rs );
   1822 	slap_graduate_commit_csn( op );
   1823 	rs->sr_text = NULL;	/* remove possible pointer to textbuf */
   1824 	return rs->sr_err;
   1825 }
   1826 
   1827 
   1828 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
   1829 static int
   1830 ldif_back_entry_get(
   1831 	Operation *op,
   1832 	struct berval *ndn,
   1833 	ObjectClass *oc,
   1834 	AttributeDescription *at,
   1835 	int rw,
   1836 	Entry **e )
   1837 {
   1838 	struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
   1839 	struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
   1840 	int rc;
   1841 
   1842 	assert( ndn != NULL );
   1843 	assert( !BER_BVISNULL( ndn ) );
   1844 
   1845 	ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
   1846 	op->o_req_dn = *ndn;
   1847 	op->o_req_ndn = *ndn;
   1848 	rc = get_entry( op, e, NULL, NULL );
   1849 	op->o_req_dn = op_dn;
   1850 	op->o_req_ndn = op_ndn;
   1851 	ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
   1852 
   1853 	if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
   1854 		rc = LDAP_NO_SUCH_ATTRIBUTE;
   1855 		entry_free( *e );
   1856 		*e = NULL;
   1857 	}
   1858 
   1859 	return rc;
   1860 }
   1861 
   1862 static int
   1863 ldif_back_entry_release_rw (
   1864 	Operation *op,
   1865 	Entry *e,
   1866 	int rw )
   1867 {
   1868 	ID id = e->e_id;
   1869 
   1870 	/* only tool mode assigns valid IDs */
   1871 	if ( id != 0 && id != NOID )
   1872 	{
   1873 		struct ldif_tool *tl = &((struct ldif_info *) op->o_bd->be_private)->li_tool;
   1874 
   1875 		id--;
   1876 
   1877 		assert( id < tl->ecount );
   1878 		assert( e == tl->entries[id] );
   1879 		tl->entries[id] = NULL;
   1880 	}
   1881 
   1882 	entry_free( e );
   1883 	return 0;
   1884 }
   1885 
   1886 
   1887 /* Slap tools */
   1888 
   1889 static int
   1890 ldif_tool_entry_open( BackendDB *be, int mode )
   1891 {
   1892 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1893 
   1894 	if ( slapMode & SLAP_TOOL_DRYRUN )
   1895 		return 0;
   1896 
   1897 	tl->ecurrent = 0;
   1898 	return 0;
   1899 }
   1900 
   1901 static int
   1902 ldif_tool_entry_close( BackendDB *be )
   1903 {
   1904 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1905 	Entry **entries = tl->entries;
   1906 	ID i;
   1907 
   1908 	if ( slapMode & SLAP_TOOL_DRYRUN )
   1909 		return 0;
   1910 
   1911 	for ( i = tl->ecount; i--; )
   1912 		if ( entries[i] )
   1913 			entry_free( entries[i] );
   1914 	SLAP_FREE( entries );
   1915 	tl->entries = NULL;
   1916 	tl->ecount = tl->elen = 0;
   1917 	return 0;
   1918 }
   1919 
   1920 static ID
   1921 ldif_tool_entry_next( BackendDB *be )
   1922 {
   1923 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1924 
   1925 	do {
   1926 		Entry *e = tl->entries[ tl->ecurrent ];
   1927 
   1928 		if ( tl->ecurrent >= tl->ecount ) {
   1929 			return NOID;
   1930 		}
   1931 
   1932 		++tl->ecurrent;
   1933 
   1934 		if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
   1935 			continue;
   1936 		}
   1937 
   1938 		if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter  ) != LDAP_COMPARE_TRUE ) {
   1939 			continue;
   1940 		}
   1941 
   1942 		break;
   1943 	} while ( 1 );
   1944 
   1945 	return tl->ecurrent;
   1946 }
   1947 
   1948 static ID
   1949 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
   1950 {
   1951 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1952 
   1953 	tl->tl_base = base;
   1954 	tl->tl_scope = scope;
   1955 	tl->tl_filter = f;
   1956 
   1957 	if ( tl->entries == NULL ) {
   1958 		Operation op = {0};
   1959 
   1960 		op.o_bd = be;
   1961 		op.o_req_dn = *be->be_suffix;
   1962 		op.o_req_ndn = *be->be_nsuffix;
   1963 		op.ors_scope = LDAP_SCOPE_SUBTREE;
   1964 		if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
   1965 			tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
   1966 			return NOID; /* fail ldif_tool_entry_get() */
   1967 		}
   1968 	}
   1969 	return ldif_tool_entry_next( be );
   1970 }
   1971 
   1972 static ID
   1973 ldif_tool_dn2id_get( BackendDB *be, struct berval *dn )
   1974 {
   1975 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1976 
   1977 	Operation op = {0};
   1978 
   1979 	op.o_bd = be;
   1980 	op.o_req_dn = *dn;
   1981 	op.o_req_ndn = *dn;
   1982 	op.ors_scope = LDAP_SCOPE_BASE;
   1983 	if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
   1984 		return NOID;
   1985 	}
   1986 	return tl->ecount;
   1987 }
   1988 
   1989 static Entry *
   1990 ldif_tool_entry_get( BackendDB *be, ID id )
   1991 {
   1992 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
   1993 	Entry *e = NULL;
   1994 
   1995 	--id;
   1996 	if ( id < tl->ecount ) {
   1997 		e = tl->entries[id];
   1998 	}
   1999 	return e;
   2000 }
   2001 
   2002 static ID
   2003 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
   2004 {
   2005 	int rc;
   2006 	const char *errmsg = NULL;
   2007 	struct berval path;
   2008 	char *parentdir;
   2009 	Operation op = {0};
   2010 
   2011 	if ( slapMode & SLAP_TOOL_DRYRUN )
   2012 		return 0;
   2013 
   2014 	op.o_bd = be;
   2015 	rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
   2016 	if ( rc == LDAP_SUCCESS ) {
   2017 		rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
   2018 
   2019 		SLAP_FREE( path.bv_val );
   2020 		if ( parentdir != NULL )
   2021 			SLAP_FREE( parentdir );
   2022 		if ( rc == LDAP_SUCCESS )
   2023 			return 1;
   2024 	}
   2025 
   2026 	if ( errmsg == NULL && rc != LDAP_OTHER )
   2027 		errmsg = ldap_err2string( rc );
   2028 	if ( errmsg != NULL )
   2029 		snprintf( text->bv_val, text->bv_len, "%s", errmsg );
   2030 	return NOID;
   2031 }
   2032 
   2033 static ID
   2034 ldif_tool_entry_modify( BackendDB *be, Entry *e, struct berval *text )
   2035 {
   2036 	int rc;
   2037 	const char *errmsg = NULL;
   2038 	struct berval path;
   2039 	Operation op = {0};
   2040 
   2041 	op.o_bd = be;
   2042 	ndn2path( &op, &e->e_nname, &path, 0 );
   2043 	rc = ldif_write_entry( &op, e, &path, NULL, &errmsg );
   2044 	SLAP_FREE( path.bv_val );
   2045 	if ( rc == LDAP_SUCCESS )
   2046 		return 1;
   2047 
   2048 	if ( errmsg == NULL && rc != LDAP_OTHER )
   2049 		errmsg = ldap_err2string( rc );
   2050 	if ( errmsg != NULL )
   2051 		snprintf( text->bv_val, text->bv_len, "%s", errmsg );
   2052 	return NOID;
   2053 }
   2054 
   2055 static int
   2056 ldif_tool_entry_delete( BackendDB *be, struct berval *ndn, struct berval *text )
   2057 {
   2058 	int rc = LDAP_SUCCESS;
   2059 	const char *errmsg = NULL;
   2060 	struct berval path;
   2061 	Operation op = {0};
   2062 
   2063 	op.o_bd = be;
   2064 	ndn2path( &op, ndn, &path, 0 );
   2065 
   2066 	ldif2dir_len( path );
   2067 	ldif2dir_name( path );
   2068 	if ( rmdir( path.bv_val ) < 0 ) {
   2069 		switch ( errno ) {
   2070 		case ENOTEMPTY:
   2071 			rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
   2072 			break;
   2073 		case ENOENT:
   2074 			/* is leaf, go on */
   2075 			break;
   2076 		default:
   2077 			rc = LDAP_OTHER;
   2078 			errmsg = "internal error (cannot delete subtree directory)";
   2079 			break;
   2080 		}
   2081 	}
   2082 
   2083 	if ( rc == LDAP_SUCCESS ) {
   2084 		dir2ldif_name( path );
   2085 		if ( unlink( path.bv_val ) < 0 ) {
   2086 			rc = LDAP_NO_SUCH_OBJECT;
   2087 			if ( errno != ENOENT ) {
   2088 				rc = LDAP_OTHER;
   2089 				errmsg = "internal error (cannot delete entry file)";
   2090 			}
   2091 		}
   2092 	}
   2093 
   2094 	SLAP_FREE( path.bv_val );
   2095 
   2096 	if ( errmsg == NULL && rc != LDAP_OTHER )
   2097 		errmsg = ldap_err2string( rc );
   2098 	if ( errmsg != NULL )
   2099 		snprintf( text->bv_val, text->bv_len, "%s", errmsg );
   2100 	return rc;
   2101 }
   2102 
   2103 
   2104 /* Setup */
   2105 
   2106 static int
   2107 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
   2108 {
   2109 	struct ldif_info *li;
   2110 
   2111 	li = ch_calloc( 1, sizeof(struct ldif_info) );
   2112 	be->be_private = li;
   2113 	be->be_cf_ocs = ldifocs;
   2114 	ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
   2115 	ldap_pvt_thread_rdwr_init( &li->li_rdwr );
   2116 	SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
   2117 	return 0;
   2118 }
   2119 
   2120 static int
   2121 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
   2122 {
   2123 	struct ldif_info *li = be->be_private;
   2124 
   2125 	ch_free( li->li_base_path.bv_val );
   2126 	ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
   2127 	ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
   2128 	free( be->be_private );
   2129 	return 0;
   2130 }
   2131 
   2132 static int
   2133 ldif_back_db_open( Backend *be, ConfigReply *cr )
   2134 {
   2135 	struct ldif_info *li = (struct ldif_info *) be->be_private;
   2136 	if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
   2137 		Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n" );
   2138 		return 1;
   2139 	}
   2140 	return 0;
   2141 }
   2142 
   2143 int
   2144 ldif_back_initialize( BackendInfo *bi )
   2145 {
   2146 	static char *controls[] = {
   2147 		LDAP_CONTROL_MANAGEDSAIT,
   2148 		LDAP_CONTROL_PRE_READ,
   2149 		LDAP_CONTROL_POST_READ,
   2150 		NULL
   2151 	};
   2152 	int rc;
   2153 
   2154 	bi->bi_flags |=
   2155 		SLAP_BFLAG_INCREMENT |
   2156 		SLAP_BFLAG_REFERRALS;
   2157 
   2158 	bi->bi_controls = controls;
   2159 
   2160 	bi->bi_open = 0;
   2161 	bi->bi_close = 0;
   2162 	bi->bi_config = 0;
   2163 	bi->bi_destroy = 0;
   2164 
   2165 	bi->bi_db_init = ldif_back_db_init;
   2166 	bi->bi_db_config = config_generic_wrapper;
   2167 	bi->bi_db_open = ldif_back_db_open;
   2168 	bi->bi_db_close = 0;
   2169 	bi->bi_db_destroy = ldif_back_db_destroy;
   2170 
   2171 	bi->bi_op_bind = ldif_back_bind;
   2172 	bi->bi_op_unbind = 0;
   2173 	bi->bi_op_search = ldif_back_search;
   2174 	bi->bi_op_compare = 0;
   2175 	bi->bi_op_modify = ldif_back_modify;
   2176 	bi->bi_op_modrdn = ldif_back_modrdn;
   2177 	bi->bi_op_add = ldif_back_add;
   2178 	bi->bi_op_delete = ldif_back_delete;
   2179 	bi->bi_op_abandon = 0;
   2180 
   2181 	bi->bi_extended = 0;
   2182 
   2183 	bi->bi_chk_referrals = ldif_back_referrals;
   2184 
   2185 	bi->bi_connection_init = 0;
   2186 	bi->bi_connection_destroy = 0;
   2187 
   2188 	bi->bi_entry_get_rw = ldif_back_entry_get;
   2189 	bi->bi_entry_release_rw = ldif_back_entry_release_rw;
   2190 
   2191 #if 0	/* NOTE: uncomment to completely disable access control */
   2192 	bi->bi_access_allowed = slap_access_always_allowed;
   2193 #endif
   2194 
   2195 	bi->bi_tool_entry_open = ldif_tool_entry_open;
   2196 	bi->bi_tool_entry_close = ldif_tool_entry_close;
   2197 	bi->bi_tool_entry_first = backend_tool_entry_first;
   2198 	bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
   2199 	bi->bi_tool_entry_next = ldif_tool_entry_next;
   2200 	bi->bi_tool_dn2id_get = ldif_tool_dn2id_get;
   2201 	bi->bi_tool_entry_get = ldif_tool_entry_get;
   2202 	bi->bi_tool_entry_put = ldif_tool_entry_put;
   2203 	bi->bi_tool_entry_modify = ldif_tool_entry_modify;
   2204 	bi->bi_tool_entry_delete = ldif_tool_entry_delete;
   2205 	bi->bi_tool_entry_reindex = 0;
   2206 	bi->bi_tool_sync = 0;
   2207 
   2208 	bi->bi_cf_ocs = ldifocs;
   2209 
   2210 	rc = config_register_schema( ldifcfg, ldifocs );
   2211 	if ( rc ) return rc;
   2212 	return 0;
   2213 }
   2214