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