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