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