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