ldif.c revision 1.2 1 /* $NetBSD: ldif.c,v 1.2 2020/08/11 13:15:40 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-2020 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.2 2020/08/11 13:15:40 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 "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}bdb").
122 * IX_DN* are for LDAP RDNs, IX_FS* for their .ldif filenames.
123 */
124 #define IX_DNL '{'
125 #define IX_DNR '}'
126 #ifndef IX_FSL
127 #define IX_FSL IX_DNL
128 #define IX_FSR IX_DNR
129 #endif
130
131 /*
132 * Test for unsafe chars, as well as chars handled specially by back-ldif:
133 * - If the escape char is not '\\', it must itself be escaped. Otherwise
134 * '\\' and the escape char would map to the same character.
135 * - Escape the '.' in ".ldif", so the directory for an RDN that actually
136 * ends with ".ldif" can not conflict with a file of the same name. And
137 * since some OSes/programs choke on multiple '.'s, escape all of them.
138 * - If '{' and '}' are translated to some other characters, those
139 * characters must in turn be escaped when they occur in an RDN.
140 */
141 #ifndef LDIF_NEED_ESCAPE
142 #define LDIF_NEED_ESCAPE(c) \
143 ((LDIF_UNSAFE_CHAR(c)) || \
144 LDIF_MAYBE_UNSAFE(c, LDIF_ESCAPE_CHAR) || \
145 LDIF_MAYBE_UNSAFE(c, LDIF_FILETYPE_SEP) || \
146 LDIF_MAYBE_UNSAFE(c, IX_FSL) || \
147 (IX_FSR != IX_FSL && LDIF_MAYBE_UNSAFE(c, IX_FSR)))
148 #endif
149 /*
150 * Helper macro for LDIF_NEED_ESCAPE(): Treat character x as unsafe if
151 * back-ldif does not already treat is specially.
152 */
153 #define LDIF_MAYBE_UNSAFE(c, x) \
154 (!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \
155 && (c) == (x))
156
157 /* Collect other "safe char" tests here, until someone needs a fix. */
158 enum {
159 eq_unsafe = LDIF_UNSAFE_CHAR('='),
160 safe_filenames = STRLENOF("" LDAP_DIRSEP "") == 1 && !(
161 LDIF_UNSAFE_CHAR('-') || /* for "{-1}frontend" in bconfig.c */
162 LDIF_UNSAFE_CHAR(LDIF_ESCAPE_CHAR) ||
163 LDIF_UNSAFE_CHAR(IX_FSL) || LDIF_UNSAFE_CHAR(IX_FSR))
164 };
165 /* Sanity check: Try to force a compilation error if !safe_filenames */
166 typedef struct {
167 int assert_safe_filenames : safe_filenames ? 2 : -2;
168 } assert_safe_filenames[safe_filenames ? 2 : -2];
169
170
171 static ConfigTable ldifcfg[] = {
172 { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
173 (void *)offsetof(struct ldif_info, li_base_path),
174 "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
175 "DESC 'Directory for database content' "
176 "EQUALITY caseIgnoreMatch "
177 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
178 { NULL, NULL, 0, 0, 0, ARG_IGNORED,
179 NULL, NULL, NULL, NULL }
180 };
181
182 static ConfigOCs ldifocs[] = {
183 { "( OLcfgDbOc:2.1 "
184 "NAME 'olcLdifConfig' "
185 "DESC 'LDIF backend configuration' "
186 "SUP olcDatabaseConfig "
187 "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg },
188 { NULL, 0, NULL }
189 };
190
191
192 /*
193 * Handle file/directory names.
194 */
195
196 /* Set *res = LDIF filename path for the normalized DN */
197 static int
198 ndn2path( Operation *op, struct berval *dn, struct berval *res, int empty_ok )
199 {
200 BackendDB *be = op->o_bd;
201 struct ldif_info *li = (struct ldif_info *) be->be_private;
202 struct berval *suffixdn = &be->be_nsuffix[0];
203 const char *start, *end, *next, *p;
204 char ch, *ptr;
205 ber_len_t len;
206 static const char hex[] = "0123456789ABCDEF";
207
208 assert( dn != NULL );
209 assert( !BER_BVISNULL( dn ) );
210 assert( suffixdn != NULL );
211 assert( !BER_BVISNULL( suffixdn ) );
212 assert( dnIsSuffix( dn, suffixdn ) );
213
214 if ( dn->bv_len == 0 && !empty_ok ) {
215 return LDAP_UNWILLING_TO_PERFORM;
216 }
217
218 start = dn->bv_val;
219 end = start + dn->bv_len;
220
221 /* Room for dir, dirsep, dn, LDIF, "\hexpair"-escaping of unsafe chars */
222 len = li->li_base_path.bv_len + dn->bv_len + (1 + STRLENOF( LDIF ));
223 for ( p = start; p < end; ) {
224 ch = *p++;
225 if ( LDIF_NEED_ESCAPE( ch ) )
226 len += 2;
227 }
228 res->bv_val = ch_malloc( len + 1 );
229
230 ptr = lutil_strcopy( res->bv_val, li->li_base_path.bv_val );
231 for ( next = end - suffixdn->bv_len; end > start; end = next ) {
232 /* Set p = start of DN component, next = &',' or start of DN */
233 while ( (p = next) > start ) {
234 --next;
235 if ( DN_SEPARATOR( *next ) )
236 break;
237 }
238 /* Append <dirsep> <p..end-1: RDN or database-suffix> */
239 for ( *ptr++ = LDAP_DIRSEP[0]; p < end; *ptr++ = ch ) {
240 ch = *p++;
241 if ( LDIF_ESCAPE_CHAR != '\\' && ch == '\\' ) {
242 ch = LDIF_ESCAPE_CHAR;
243 } else if ( IX_FSL != IX_DNL && ch == IX_DNL ) {
244 ch = IX_FSL;
245 } else if ( IX_FSR != IX_DNR && ch == IX_DNR ) {
246 ch = IX_FSR;
247 } else if ( LDIF_NEED_ESCAPE( ch ) ) {
248 *ptr++ = LDIF_ESCAPE_CHAR;
249 *ptr++ = hex[(ch & 0xFFU) >> 4];
250 ch = hex[ch & 0x0FU];
251 }
252 }
253 }
254 ptr = lutil_strcopy( ptr, LDIF );
255 res->bv_len = ptr - res->bv_val;
256
257 assert( res->bv_len <= len );
258
259 return LDAP_SUCCESS;
260 }
261
262 /*
263 * *dest = dupbv(<dir + LDAP_DIRSEP>), plus room for <more>-sized filename.
264 * Return pointer past the dirname.
265 */
266 static char *
267 fullpath_alloc( struct berval *dest, const struct berval *dir, ber_len_t more )
268 {
269 char *s = SLAP_MALLOC( dir->bv_len + more + 2 );
270
271 dest->bv_val = s;
272 if ( s == NULL ) {
273 dest->bv_len = 0;
274 Debug( LDAP_DEBUG_ANY, "back-ldif: out of memory\n", 0, 0, 0 );
275 } else {
276 s = lutil_strcopy( dest->bv_val, dir->bv_val );
277 *s++ = LDAP_DIRSEP[0];
278 *s = '\0';
279 dest->bv_len = s - dest->bv_val;
280 }
281 return s;
282 }
283
284 /*
285 * Append filename to fullpath_alloc() dirname or replace previous filename.
286 * dir_end = fullpath_alloc() return value.
287 */
288 #define FILL_PATH(fpath, dir_end, filename) \
289 ((fpath)->bv_len = lutil_strcopy(dir_end, filename) - (fpath)->bv_val)
290
291
292 /* .ldif entry filename length <-> subtree dirname length. */
293 #define ldif2dir_len(bv) ((bv).bv_len -= STRLENOF(LDIF))
294 #define dir2ldif_len(bv) ((bv).bv_len += STRLENOF(LDIF))
295 /* .ldif entry filename <-> subtree dirname, both with dirname length. */
296 #define ldif2dir_name(bv) ((bv).bv_val[(bv).bv_len] = '\0')
297 #define dir2ldif_name(bv) ((bv).bv_val[(bv).bv_len] = LDIF_FILETYPE_SEP)
298
299 /* Get the parent directory path, plus the LDIF suffix overwritten by a \0. */
300 static int
301 get_parent_path( struct berval *dnpath, struct berval *res )
302 {
303 ber_len_t i = dnpath->bv_len;
304
305 while ( i > 0 && dnpath->bv_val[ --i ] != LDAP_DIRSEP[0] ) ;
306 if ( res == NULL ) {
307 res = dnpath;
308 } else {
309 res->bv_val = SLAP_MALLOC( i + 1 + STRLENOF(LDIF) );
310 if ( res->bv_val == NULL )
311 return LDAP_OTHER;
312 AC_MEMCPY( res->bv_val, dnpath->bv_val, i );
313 }
314 res->bv_len = i;
315 strcpy( res->bv_val + i, LDIF );
316 res->bv_val[i] = '\0';
317 return LDAP_SUCCESS;
318 }
319
320 /* Make temporary filename pattern for mkstemp() based on dnpath. */
321 static char *
322 ldif_tempname( const struct berval *dnpath )
323 {
324 static const char suffix[] = ".XXXXXX";
325 ber_len_t len = dnpath->bv_len - STRLENOF( LDIF );
326 char *name = SLAP_MALLOC( len + sizeof( suffix ) );
327
328 if ( name != NULL ) {
329 AC_MEMCPY( name, dnpath->bv_val, len );
330 strcpy( name + len, suffix );
331 }
332 return name;
333 }
334
335 /* CRC-32 table for the polynomial:
336 * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
337 *
338 * As used by zlib
339 */
340
341 static const ber_uint_t crctab[256] = {
342 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
343 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
344 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
345 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
346 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
347 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
348 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
349 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
350 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
351 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
352 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
353 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
354 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
355 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
356 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
357 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
358 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
359 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
360 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
361 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
362 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
363 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
364 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
365 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
366 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
367 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
368 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
369 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
370 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
371 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
372 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
373 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
374 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
375 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
376 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
377 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
378 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
379 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
380 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
381 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
382 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
383 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
384 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
385 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
386 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
387 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
388 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
389 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
390 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
391 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
392 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
393 0x2d02ef8dL
394 };
395
396 #define CRC1 crc = crctab[(crc ^ *buf++) & 0xff] ^ (crc >> 8)
397 #define CRC8 CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1
398 unsigned int
399 crc32(const void *vbuf, int len)
400 {
401 const unsigned char *buf = vbuf;
402 ber_uint_t crc = 0xffffffff;
403
404 while (len > 7) {
405 CRC8;
406 len -= 8;
407 }
408 while (len) {
409 CRC1;
410 len--;
411 }
412
413 return crc ^ 0xffffffff;
414 }
415
416 /*
417 * Read a file, or stat() it if datap == NULL. Allocate and fill *datap.
418 * Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error.
419 */
420 static int
421 ldif_read_file( const char *path, char **datap )
422 {
423 int rc = LDAP_SUCCESS, fd, len;
424 int res = -1; /* 0:success, <0:error, >0:file too big/growing. */
425 struct stat st;
426 char *data = NULL, *ptr = NULL;
427 const char *msg;
428
429 if ( datap == NULL ) {
430 res = stat( path, &st );
431 goto done;
432 }
433 fd = open( path, O_RDONLY );
434 if ( fd >= 0 ) {
435 if ( fstat( fd, &st ) == 0 ) {
436 if ( st.st_size > INT_MAX - 2 ) {
437 res = 1;
438 } else {
439 len = st.st_size + 1; /* +1 detects file size > st.st_size */
440 *datap = data = ptr = SLAP_MALLOC( len + 1 );
441 if ( ptr != NULL ) {
442 while ( len && (res = read( fd, ptr, len )) ) {
443 if ( res > 0 ) {
444 len -= res;
445 ptr += res;
446 } else if ( errno != EINTR ) {
447 break;
448 }
449 }
450 *ptr = '\0';
451 }
452 }
453 }
454 if ( close( fd ) < 0 )
455 res = -1;
456 }
457
458 done:
459 if ( res == 0 ) {
460 #ifdef LDAP_DEBUG
461 msg = "entry file exists";
462 if ( datap ) {
463 msg = "read entry file";
464 len = ptr - data;
465 ptr = strstr( data, "\n# CRC32" );
466 if (!ptr) {
467 msg = "read entry file without checksum";
468 } else {
469 unsigned int crc1 = 0, crc2 = 1;
470 if ( sscanf( ptr + 9, "%08x", &crc1) == 1) {
471 ptr = strchr(ptr+1, '\n');
472 if ( ptr ) {
473 ptr++;
474 len -= (ptr - data);
475 crc2 = crc32( ptr, len );
476 }
477 }
478 if ( crc1 != crc2 ) {
479 Debug( LDAP_DEBUG_ANY, "ldif_read_file: checksum error on \"%s\"\n",
480 path, 0, 0 );
481 return rc;
482 }
483 }
484 }
485 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n", msg, path, 0 );
486 #endif /* LDAP_DEBUG */
487 } else {
488 if ( res < 0 && errno == ENOENT ) {
489 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
490 "no entry file \"%s\"\n", path, 0, 0 );
491 rc = LDAP_NO_SUCH_OBJECT;
492 } else {
493 msg = res < 0 ? STRERROR( errno ) : "bad stat() size";
494 Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
495 msg, path, 0 );
496 rc = LDAP_OTHER;
497 }
498 if ( data != NULL )
499 SLAP_FREE( data );
500 }
501 return rc;
502 }
503
504 /*
505 * return nonnegative for success or -1 for error
506 * do not return numbers less than -1
507 */
508 static int
509 spew_file( int fd, const char *spew, int len, int *save_errno )
510 {
511 int writeres;
512 #define HEADER "# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n"
513 char header[sizeof(HEADER "# CRC32 12345678\n")];
514
515 sprintf(header, HEADER "# CRC32 %08x\n", crc32(spew, len));
516 writeres = write_data(fd, header, sizeof(header)-1, save_errno);
517 return writeres < 0 ? writeres : write_data(fd, spew, len, save_errno);
518 }
519
520 static int
521 write_data( int fd, const char *spew, int len, int *save_errno )
522 {
523 int writeres = 0;
524 while(len > 0) {
525 writeres = write(fd, spew, len);
526 if(writeres == -1) {
527 *save_errno = errno;
528 if (*save_errno != EINTR)
529 break;
530 }
531 else {
532 spew += writeres;
533 len -= writeres;
534 }
535 }
536 return writeres;
537 }
538
539 /* Write an entry LDIF file. Create parentdir first if non-NULL. */
540 static int
541 ldif_write_entry(
542 Operation *op,
543 Entry *e,
544 const struct berval *path,
545 const char *parentdir,
546 const char **text )
547 {
548 int rc = LDAP_OTHER, res, save_errno = 0;
549 int fd, entry_length;
550 char *entry_as_string, *tmpfname;
551
552 if ( op->o_abandon )
553 return SLAPD_ABANDON;
554
555 if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
556 save_errno = errno;
557 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
558 "cannot create parent directory",
559 parentdir, STRERROR( save_errno ) );
560 *text = "internal error (cannot create parent directory)";
561 return rc;
562 }
563
564 tmpfname = ldif_tempname( path );
565 fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
566 if ( fd < 0 ) {
567 save_errno = errno;
568 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
569 "cannot create file", e->e_dn, STRERROR( save_errno ) );
570 *text = "internal error (cannot create file)";
571
572 } else {
573 ber_len_t dn_len = e->e_name.bv_len;
574 struct berval rdn;
575
576 /* Only save the RDN onto disk */
577 dnRdn( &e->e_name, &rdn );
578 if ( rdn.bv_len != dn_len ) {
579 e->e_name.bv_val[rdn.bv_len] = '\0';
580 e->e_name.bv_len = rdn.bv_len;
581 }
582
583 res = -2;
584 ldap_pvt_thread_mutex_lock( &entry2str_mutex );
585 entry_as_string = entry2str( e, &entry_length );
586 if ( entry_as_string != NULL )
587 res = spew_file( fd, entry_as_string, entry_length, &save_errno );
588 ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
589
590 /* Restore full DN */
591 if ( rdn.bv_len != dn_len ) {
592 e->e_name.bv_val[rdn.bv_len] = ',';
593 e->e_name.bv_len = dn_len;
594 }
595
596 if ( close( fd ) < 0 && res >= 0 ) {
597 res = -1;
598 save_errno = errno;
599 }
600
601 if ( res >= 0 ) {
602 if ( move_file( tmpfname, path->bv_val ) == 0 ) {
603 Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
604 "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 );
605 rc = LDAP_SUCCESS;
606 } else {
607 save_errno = errno;
608 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
609 "could not put entry file for \"%s\" in place: %s\n",
610 e->e_name.bv_val, STRERROR( save_errno ), 0 );
611 *text = "internal error (could not put entry file in place)";
612 }
613 } else if ( res == -1 ) {
614 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
615 "write error to", tmpfname, STRERROR( save_errno ) );
616 *text = "internal error (write error to entry file)";
617 }
618
619 if ( rc != LDAP_SUCCESS ) {
620 unlink( tmpfname );
621 }
622 }
623
624 if ( tmpfname )
625 SLAP_FREE( tmpfname );
626 return rc;
627 }
628
629 /*
630 * Read the entry at path, or if entryp==NULL just see if it exists.
631 * pdn and pndn are the parent's DN and normalized DN, or both NULL.
632 * Return an LDAP result code.
633 */
634 static int
635 ldif_read_entry(
636 Operation *op,
637 const char *path,
638 struct berval *pdn,
639 struct berval *pndn,
640 Entry **entryp,
641 const char **text )
642 {
643 int rc;
644 Entry *entry;
645 char *entry_as_string;
646 struct berval rdn;
647
648 /* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
649 * If so we need not check for LDAP_REQ_BIND here.
650 */
651 if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND )
652 return SLAPD_ABANDON;
653
654 rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
655
656 switch ( rc ) {
657 case LDAP_SUCCESS:
658 if ( entryp == NULL )
659 break;
660 *entryp = entry = str2entry( entry_as_string );
661 SLAP_FREE( entry_as_string );
662 if ( entry == NULL ) {
663 rc = LDAP_OTHER;
664 if ( text != NULL )
665 *text = "internal error (cannot parse some entry file)";
666 break;
667 }
668 if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
669 break;
670 /* Append parent DN to DN from LDIF file */
671 rdn = entry->e_name;
672 build_new_dn( &entry->e_name, pdn, &rdn, NULL );
673 SLAP_FREE( rdn.bv_val );
674 rdn = entry->e_nname;
675 build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
676 SLAP_FREE( rdn.bv_val );
677 break;
678
679 case LDAP_OTHER:
680 if ( text != NULL )
681 *text = entryp
682 ? "internal error (cannot read some entry file)"
683 : "internal error (cannot stat some entry file)";
684 break;
685 }
686
687 return rc;
688 }
689
690 /*
691 * Read the operation's entry, or if entryp==NULL just see if it exists.
692 * Return an LDAP result code. May set *text to a message on failure.
693 * If pathp is non-NULL, set it to the entry filename on success.
694 */
695 static int
696 get_entry(
697 Operation *op,
698 Entry **entryp,
699 struct berval *pathp,
700 const char **text )
701 {
702 int rc;
703 struct berval path, pdn, pndn;
704
705 dnParent( &op->o_req_dn, &pdn );
706 dnParent( &op->o_req_ndn, &pndn );
707 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
708 if ( rc != LDAP_SUCCESS ) {
709 goto done;
710 }
711
712 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
713
714 if ( rc == LDAP_SUCCESS && pathp != NULL ) {
715 *pathp = path;
716 } else {
717 SLAP_FREE( path.bv_val );
718 }
719 done:
720 return rc;
721 }
722
723
724 /*
725 * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
726 * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
727 * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
728 * Does not sort escaped chars correctly, would need to un-escape them.
729 */
730 typedef struct bvlist {
731 struct bvlist *next;
732 char *trunc; /* filename was truncated here */
733 int inum; /* num from "attr={num}" in filename, or INT_MIN */
734 char savech; /* original char at *trunc */
735 /* BVL_NAME(&bvlist) is the filename, allocated after the struct: */
736 # define BVL_NAME(bvl) ((char *) ((bvl) + 1))
737 # define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1)
738 } bvlist;
739
740 static int
741 ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
742 {
743 int rc = LDAP_SUCCESS;
744
745 if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
746 if ( rs == NULL ) {
747 /* Save the entry for tool mode */
748 struct ldif_tool *tl =
749 &((struct ldif_info *) op->o_bd->be_private)->li_tool;
750
751 if ( tl->ecount >= tl->elen ) {
752 /* Allocate/grow entries */
753 ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
754 Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
755 sizeof(Entry *) * elen );
756 if ( entries == NULL ) {
757 Debug( LDAP_DEBUG_ANY,
758 "ldif_send_entry: out of memory\n", 0, 0, 0 );
759 rc = LDAP_OTHER;
760 goto done;
761 }
762 tl->elen = elen;
763 tl->entries = entries;
764 }
765 tl->entries[tl->ecount++] = e;
766 return rc;
767 }
768
769 else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
770 /* Send a continuation reference.
771 * (ldif_back_referrals() handles baseobject referrals.)
772 * Don't check the filter since it's only a candidate.
773 */
774 BerVarray refs = get_entry_referrals( op, e );
775 rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
776 rs->sr_entry = e;
777 rc = send_search_reference( op, rs );
778 ber_bvarray_free( rs->sr_ref );
779 ber_bvarray_free( refs );
780 rs->sr_ref = NULL;
781 rs->sr_entry = NULL;
782 }
783
784 else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
785 rs->sr_entry = e;
786 rs->sr_attrs = op->ors_attrs;
787 /* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
788 * but refraining lets us test unFREEable MODIFIABLE
789 * entries. Like entries built on the stack.
790 */
791 rs->sr_flags = REP_ENTRY_MODIFIABLE;
792 rc = send_search_entry( op, rs );
793 rs->sr_entry = NULL;
794 rs->sr_attrs = NULL;
795 }
796 }
797
798 done:
799 entry_free( e );
800 return rc;
801 }
802
803 /* Read LDIF directory <path> into <listp>. Set *fname_maxlenp. */
804 static int
805 ldif_readdir(
806 Operation *op,
807 SlapReply *rs,
808 const struct berval *path,
809 bvlist **listp,
810 ber_len_t *fname_maxlenp )
811 {
812 int rc = LDAP_SUCCESS;
813 DIR *dir_of_path;
814
815 *listp = NULL;
816 *fname_maxlenp = 0;
817
818 dir_of_path = opendir( path->bv_val );
819 if ( dir_of_path == NULL ) {
820 int save_errno = errno;
821 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
822 int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
823
824 /* Absent directory is OK (leaf entry), except the database dir */
825 if ( is_rootDSE || save_errno != ENOENT ) {
826 Debug( LDAP_DEBUG_ANY,
827 "=> ldif_search_entry: failed to opendir \"%s\": %s\n",
828 path->bv_val, STRERROR( save_errno ), 0 );
829 rc = LDAP_OTHER;
830 if ( rs != NULL )
831 rs->sr_text =
832 save_errno != ENOENT ? "internal error (bad directory)"
833 : "internal error (database directory does not exist)";
834 }
835
836 } else {
837 bvlist *ptr;
838 struct dirent *dir;
839 int save_errno = 0;
840
841 while ( (dir = readdir( dir_of_path )) != NULL ) {
842 size_t fname_len;
843 bvlist *bvl, **prev;
844 char *trunc, *idxp, *endp, *endp2;
845
846 fname_len = strlen( dir->d_name );
847 if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
848 continue;
849 if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
850 continue;
851
852 if ( *fname_maxlenp < fname_len )
853 *fname_maxlenp = fname_len;
854
855 bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
856 if ( bvl == NULL ) {
857 rc = LDAP_OTHER;
858 save_errno = errno;
859 break;
860 }
861 strcpy( BVL_NAME( bvl ), dir->d_name );
862
863 /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
864 trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
865 if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
866 (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
867 (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
868 {
869 /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
870 bvl->inum = strtol( idxp, &endp2, 10 );
871 if ( endp2 == endp ) {
872 trunc = idxp;
873 goto truncate;
874 }
875 }
876 bvl->inum = INT_MIN;
877 truncate:
878 bvl->trunc = trunc;
879 bvl->savech = *trunc;
880 *trunc = '\0';
881
882 /* Insertion sort */
883 for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
884 int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
885 if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
886 break;
887 }
888 *prev = bvl;
889 bvl->next = ptr;
890 }
891
892 if ( closedir( dir_of_path ) < 0 ) {
893 save_errno = errno;
894 rc = LDAP_OTHER;
895 if ( rs != NULL )
896 rs->sr_text = "internal error (bad directory)";
897 }
898 if ( rc != LDAP_SUCCESS ) {
899 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
900 "error reading directory", path->bv_val,
901 STRERROR( save_errno ) );
902 }
903 }
904
905 return rc;
906 }
907
908 /*
909 * Send an entry, recursively search its children, and free or save it.
910 * Return an LDAP result code. Parameters:
911 * op, rs operation and reply. rs == NULL for slap tools.
912 * e entry to search, or NULL for rootDSE.
913 * scope scope for the part of the search from this entry.
914 * path LDIF filename -- bv_len and non-directory part are overwritten.
915 */
916 static int
917 ldif_search_entry(
918 Operation *op,
919 SlapReply *rs,
920 Entry *e,
921 int scope,
922 struct berval *path )
923 {
924 int rc = LDAP_SUCCESS;
925 struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
926
927 if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
928 /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
929 * which bconfig.c seems to need. (TODO: see config_rename_one.)
930 */
931 if ( ber_dupbv( &dn, &e->e_name ) == NULL ||
932 ber_dupbv( &ndn, &e->e_nname ) == NULL )
933 {
934 Debug( LDAP_DEBUG_ANY,
935 "ldif_search_entry: out of memory\n", 0, 0, 0 );
936 rc = LDAP_OTHER;
937 goto done;
938 }
939 }
940
941 /* Send the entry if appropriate, and free or save it */
942 if ( e != NULL )
943 rc = ldif_send_entry( op, rs, e, scope );
944
945 /* Search the children */
946 if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
947 bvlist *list, *ptr;
948 struct berval fpath; /* becomes child pathname */
949 char *dir_end; /* will point past dirname in fpath */
950
951 ldif2dir_len( *path );
952 ldif2dir_name( *path );
953 rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
954
955 if ( list != NULL ) {
956 const char **text = rs == NULL ? NULL : &rs->sr_text;
957
958 if ( scope == LDAP_SCOPE_ONELEVEL )
959 scope = LDAP_SCOPE_BASE;
960 else if ( scope == LDAP_SCOPE_SUBORDINATE )
961 scope = LDAP_SCOPE_SUBTREE;
962
963 /* Allocate fpath and fill in directory part */
964 dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
965 if ( dir_end == NULL )
966 rc = LDAP_OTHER;
967
968 do {
969 ptr = list;
970
971 if ( rc == LDAP_SUCCESS ) {
972 *ptr->trunc = ptr->savech;
973 FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
974
975 rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
976 &e, text );
977 switch ( rc ) {
978 case LDAP_SUCCESS:
979 rc = ldif_search_entry( op, rs, e, scope, &fpath );
980 break;
981 case LDAP_NO_SUCH_OBJECT:
982 /* Only the search baseDN may produce noSuchObject. */
983 rc = LDAP_OTHER;
984 if ( rs != NULL )
985 rs->sr_text = "internal error "
986 "(did someone just remove an entry file?)";
987 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
988 "file listed in parent directory does not exist: "
989 "\"%s\"\n", fpath.bv_val, 0, 0 );
990 break;
991 }
992 }
993
994 list = ptr->next;
995 SLAP_FREE( ptr );
996 } while ( list != NULL );
997
998 if ( !BER_BVISNULL( &fpath ) )
999 SLAP_FREE( fpath.bv_val );
1000 }
1001 }
1002
1003 done:
1004 if ( !BER_BVISEMPTY( &dn ) )
1005 ber_memfree( dn.bv_val );
1006 if ( !BER_BVISEMPTY( &ndn ) )
1007 ber_memfree( ndn.bv_val );
1008 return rc;
1009 }
1010
1011 static int
1012 search_tree( Operation *op, SlapReply *rs )
1013 {
1014 int rc = LDAP_SUCCESS;
1015 Entry *e = NULL;
1016 struct berval path;
1017 struct berval pdn, pndn;
1018
1019 (void) ndn2path( op, &op->o_req_ndn, &path, 1 );
1020 if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
1021 /* Read baseObject */
1022 dnParent( &op->o_req_dn, &pdn );
1023 dnParent( &op->o_req_ndn, &pndn );
1024 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
1025 rs == NULL ? NULL : &rs->sr_text );
1026 }
1027 if ( rc == LDAP_SUCCESS )
1028 rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
1029
1030 ch_free( path.bv_val );
1031 return rc;
1032 }
1033
1034
1035 /*
1036 * Prepare to create or rename an entry:
1037 * Check that the entry does not already exist.
1038 * Check that the parent entry exists and can have subordinates,
1039 * unless need_dir is NULL or adding the suffix entry.
1040 *
1041 * Return an LDAP result code. May set *text to a message on failure.
1042 * If success, set *dnpath to LDIF entry path and *need_dir to
1043 * (directory must be created ? dirname : NULL).
1044 */
1045 static int
1046 ldif_prepare_create(
1047 Operation *op,
1048 Entry *e,
1049 struct berval *dnpath,
1050 char **need_dir,
1051 const char **text )
1052 {
1053 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1054 struct berval *ndn = &e->e_nname;
1055 struct berval ppath = BER_BVNULL;
1056 struct stat st;
1057 Entry *parent = NULL;
1058 int rc;
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, STRERROR( errno ), 0 );
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, STRERROR( errno ), 0 );
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
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
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
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
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 send_ldap_result(op, rs);
1388
1389 return rs->sr_err;
1390 }
1391
1392 static int
1393 ldif_back_add( Operation *op, SlapReply *rs )
1394 {
1395 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1396 Entry * e = op->ora_e;
1397 struct berval path;
1398 char *parentdir;
1399 char textbuf[SLAP_TEXT_BUFLEN];
1400 int rc;
1401
1402 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
1403
1404 rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
1405 &rs->sr_text, textbuf, sizeof( textbuf ) );
1406 if ( rc != LDAP_SUCCESS )
1407 goto send_res;
1408
1409 rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
1410 if ( rc != LDAP_SUCCESS )
1411 goto send_res;
1412
1413 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1414
1415 rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
1416 if ( rc == LDAP_SUCCESS ) {
1417 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1418 rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
1419 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1420
1421 SLAP_FREE( path.bv_val );
1422 if ( parentdir != NULL )
1423 SLAP_FREE( parentdir );
1424 }
1425
1426 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1427
1428 send_res:
1429 rs->sr_err = rc;
1430 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
1431 rc, rs->sr_text ? rs->sr_text : "", 0 );
1432 send_ldap_result( op, rs );
1433 slap_graduate_commit_csn( op );
1434 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1435 return rs->sr_err;
1436 }
1437
1438 static int
1439 ldif_back_modify( Operation *op, SlapReply *rs )
1440 {
1441 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1442 Modifications * modlst = op->orm_modlist;
1443 struct berval path;
1444 Entry *entry;
1445 char textbuf[SLAP_TEXT_BUFLEN];
1446 int rc;
1447
1448 slap_mods_opattrs( op, &op->orm_modlist, 1 );
1449
1450 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1451
1452 rc = get_entry( op, &entry, &path, &rs->sr_text );
1453 if ( rc == LDAP_SUCCESS ) {
1454 rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
1455 if ( rc == LDAP_SUCCESS ) {
1456 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1457 rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
1458 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1459 }
1460
1461 entry_free( entry );
1462 SLAP_FREE( path.bv_val );
1463 }
1464
1465 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1466
1467 rs->sr_err = rc;
1468 send_ldap_result( op, rs );
1469 slap_graduate_commit_csn( op );
1470 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1471 return rs->sr_err;
1472 }
1473
1474 static int
1475 ldif_back_delete( Operation *op, SlapReply *rs )
1476 {
1477 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1478 struct berval path;
1479 int rc = LDAP_SUCCESS;
1480
1481 if ( BER_BVISEMPTY( &op->o_csn )) {
1482 struct berval csn;
1483 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
1484
1485 csn.bv_val = csnbuf;
1486 csn.bv_len = sizeof( csnbuf );
1487 slap_get_csn( op, &csn, 1 );
1488 }
1489
1490 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1491 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1492 if ( op->o_abandon ) {
1493 rc = SLAPD_ABANDON;
1494 goto done;
1495 }
1496
1497 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
1498 if ( rc != LDAP_SUCCESS ) {
1499 goto done;
1500 }
1501
1502 ldif2dir_len( path );
1503 ldif2dir_name( path );
1504 if ( rmdir( path.bv_val ) < 0 ) {
1505 switch ( errno ) {
1506 case ENOTEMPTY:
1507 rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1508 break;
1509 case ENOENT:
1510 /* is leaf, go on */
1511 break;
1512 default:
1513 rc = LDAP_OTHER;
1514 rs->sr_text = "internal error (cannot delete subtree directory)";
1515 break;
1516 }
1517 }
1518
1519 if ( rc == LDAP_SUCCESS ) {
1520 dir2ldif_name( path );
1521 if ( unlink( path.bv_val ) < 0 ) {
1522 rc = LDAP_NO_SUCH_OBJECT;
1523 if ( errno != ENOENT ) {
1524 rc = LDAP_OTHER;
1525 rs->sr_text = "internal error (cannot delete entry file)";
1526 }
1527 }
1528 }
1529
1530 if ( rc == LDAP_OTHER ) {
1531 Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
1532 "cannot delete", path.bv_val, STRERROR( errno ) );
1533 }
1534
1535 SLAP_FREE( path.bv_val );
1536 done:
1537 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1538 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1539 rs->sr_err = rc;
1540 send_ldap_result( op, rs );
1541 slap_graduate_commit_csn( op );
1542 return rs->sr_err;
1543 }
1544
1545
1546 static int
1547 ldif_move_entry(
1548 Operation *op,
1549 Entry *entry,
1550 int same_ndn,
1551 struct berval *oldpath,
1552 const char **text )
1553 {
1554 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1555 struct berval newpath;
1556 char *parentdir = NULL, *trash;
1557 int rc, rename_res;
1558
1559 if ( same_ndn ) {
1560 rc = LDAP_SUCCESS;
1561 newpath = *oldpath;
1562 } else {
1563 rc = ldif_prepare_create( op, entry, &newpath,
1564 op->orr_newSup ? &parentdir : NULL, text );
1565 }
1566
1567 if ( rc == LDAP_SUCCESS ) {
1568 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1569
1570 rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
1571 if ( rc == LDAP_SUCCESS && !same_ndn ) {
1572 trash = oldpath->bv_val; /* will be .ldif file to delete */
1573 ldif2dir_len( newpath );
1574 ldif2dir_len( *oldpath );
1575 /* Move subdir before deleting old entry,
1576 * so .ldif always exists if subdir does.
1577 */
1578 ldif2dir_name( newpath );
1579 ldif2dir_name( *oldpath );
1580 rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
1581 if ( rename_res != 0 && errno != ENOENT ) {
1582 rc = LDAP_OTHER;
1583 *text = "internal error (cannot move this subtree)";
1584 trash = newpath.bv_val;
1585 }
1586
1587 /* Delete old entry, or if error undo change */
1588 for (;;) {
1589 dir2ldif_name( newpath );
1590 dir2ldif_name( *oldpath );
1591 if ( unlink( trash ) == 0 )
1592 break;
1593 if ( rc == LDAP_SUCCESS ) {
1594 /* Prepare to undo change and return failure */
1595 rc = LDAP_OTHER;
1596 *text = "internal error (cannot move this entry)";
1597 trash = newpath.bv_val;
1598 if ( rename_res != 0 )
1599 continue;
1600 /* First move subdirectory back */
1601 ldif2dir_name( newpath );
1602 ldif2dir_name( *oldpath );
1603 if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
1604 continue;
1605 }
1606 *text = "added new but couldn't delete old entry!";
1607 break;
1608 }
1609
1610 if ( rc != LDAP_SUCCESS ) {
1611 char s[128];
1612 snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
1613 Debug( LDAP_DEBUG_ANY,
1614 "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
1615 s, op->o_req_dn.bv_val, entry->e_dn );
1616 }
1617 }
1618
1619 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1620 if ( !same_ndn )
1621 SLAP_FREE( newpath.bv_val );
1622 if ( parentdir != NULL )
1623 SLAP_FREE( parentdir );
1624 }
1625
1626 return rc;
1627 }
1628
1629 static int
1630 ldif_back_modrdn( Operation *op, SlapReply *rs )
1631 {
1632 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1633 struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1634 struct berval p_dn, old_path;
1635 Entry *entry;
1636 char textbuf[SLAP_TEXT_BUFLEN];
1637 int rc, same_ndn;
1638
1639 slap_mods_opattrs( op, &op->orr_modlist, 1 );
1640
1641 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1642
1643 rc = get_entry( op, &entry, &old_path, &rs->sr_text );
1644 if ( rc == LDAP_SUCCESS ) {
1645 /* build new dn, and new ndn for the entry */
1646 if ( op->oq_modrdn.rs_newSup != NULL ) {
1647 p_dn = *op->oq_modrdn.rs_newSup;
1648 } else {
1649 dnParent( &entry->e_name, &p_dn );
1650 }
1651 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
1652 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1653 same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
1654 ber_memfree_x( entry->e_name.bv_val, NULL );
1655 ber_memfree_x( entry->e_nname.bv_val, NULL );
1656 entry->e_name = new_dn;
1657 entry->e_nname = new_ndn;
1658
1659 /* perform the modifications */
1660 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
1661 if ( rc == LDAP_SUCCESS )
1662 rc = ldif_move_entry( op, entry, same_ndn, &old_path,
1663 &rs->sr_text );
1664
1665 entry_free( entry );
1666 SLAP_FREE( old_path.bv_val );
1667 }
1668
1669 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1670 rs->sr_err = rc;
1671 send_ldap_result( op, rs );
1672 slap_graduate_commit_csn( op );
1673 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1674 return rs->sr_err;
1675 }
1676
1677
1678 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1679 static int
1680 ldif_back_entry_get(
1681 Operation *op,
1682 struct berval *ndn,
1683 ObjectClass *oc,
1684 AttributeDescription *at,
1685 int rw,
1686 Entry **e )
1687 {
1688 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1689 struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1690 int rc;
1691
1692 assert( ndn != NULL );
1693 assert( !BER_BVISNULL( ndn ) );
1694
1695 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1696 op->o_req_dn = *ndn;
1697 op->o_req_ndn = *ndn;
1698 rc = get_entry( op, e, NULL, NULL );
1699 op->o_req_dn = op_dn;
1700 op->o_req_ndn = op_ndn;
1701 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1702
1703 if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1704 rc = LDAP_NO_SUCH_ATTRIBUTE;
1705 entry_free( *e );
1706 *e = NULL;
1707 }
1708
1709 return rc;
1710 }
1711
1712
1713 /* Slap tools */
1714
1715 static int
1716 ldif_tool_entry_open( BackendDB *be, int mode )
1717 {
1718 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1719
1720 tl->ecurrent = 0;
1721 return 0;
1722 }
1723
1724 static int
1725 ldif_tool_entry_close( BackendDB *be )
1726 {
1727 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1728 Entry **entries = tl->entries;
1729 ID i;
1730
1731 for ( i = tl->ecount; i--; )
1732 if ( entries[i] )
1733 entry_free( entries[i] );
1734 SLAP_FREE( entries );
1735 tl->entries = NULL;
1736 tl->ecount = tl->elen = 0;
1737 return 0;
1738 }
1739
1740 static ID
1741 ldif_tool_entry_next( BackendDB *be )
1742 {
1743 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1744
1745 do {
1746 Entry *e = tl->entries[ tl->ecurrent ];
1747
1748 if ( tl->ecurrent >= tl->ecount ) {
1749 return NOID;
1750 }
1751
1752 ++tl->ecurrent;
1753
1754 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1755 continue;
1756 }
1757
1758 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter ) != LDAP_COMPARE_TRUE ) {
1759 continue;
1760 }
1761
1762 break;
1763 } while ( 1 );
1764
1765 return tl->ecurrent;
1766 }
1767
1768 static ID
1769 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1770 {
1771 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1772
1773 tl->tl_base = base;
1774 tl->tl_scope = scope;
1775 tl->tl_filter = f;
1776
1777 if ( tl->entries == NULL ) {
1778 Operation op = {0};
1779
1780 op.o_bd = be;
1781 op.o_req_dn = *be->be_suffix;
1782 op.o_req_ndn = *be->be_nsuffix;
1783 op.ors_scope = LDAP_SCOPE_SUBTREE;
1784 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1785 tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1786 return NOID; /* fail ldif_tool_entry_get() */
1787 }
1788 }
1789 return ldif_tool_entry_next( be );
1790 }
1791
1792 static Entry *
1793 ldif_tool_entry_get( BackendDB *be, ID id )
1794 {
1795 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1796 Entry *e = NULL;
1797
1798 --id;
1799 if ( id < tl->ecount ) {
1800 e = tl->entries[id];
1801 tl->entries[id] = NULL;
1802 }
1803 return e;
1804 }
1805
1806 static ID
1807 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1808 {
1809 int rc;
1810 const char *errmsg = NULL;
1811 struct berval path;
1812 char *parentdir;
1813 Operation op = {0};
1814
1815 op.o_bd = be;
1816 rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1817 if ( rc == LDAP_SUCCESS ) {
1818 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1819
1820 SLAP_FREE( path.bv_val );
1821 if ( parentdir != NULL )
1822 SLAP_FREE( parentdir );
1823 if ( rc == LDAP_SUCCESS )
1824 return 1;
1825 }
1826
1827 if ( errmsg == NULL && rc != LDAP_OTHER )
1828 errmsg = ldap_err2string( rc );
1829 if ( errmsg != NULL )
1830 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1831 return NOID;
1832 }
1833
1834
1835 /* Setup */
1836
1837 static int
1838 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1839 {
1840 struct ldif_info *li;
1841
1842 li = ch_calloc( 1, sizeof(struct ldif_info) );
1843 be->be_private = li;
1844 be->be_cf_ocs = ldifocs;
1845 ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1846 ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1847 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1848 return 0;
1849 }
1850
1851 static int
1852 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1853 {
1854 struct ldif_info *li = be->be_private;
1855
1856 ch_free( li->li_base_path.bv_val );
1857 ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1858 ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1859 free( be->be_private );
1860 return 0;
1861 }
1862
1863 static int
1864 ldif_back_db_open( Backend *be, ConfigReply *cr )
1865 {
1866 struct ldif_info *li = (struct ldif_info *) be->be_private;
1867 if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1868 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1869 return 1;
1870 }
1871 return 0;
1872 }
1873
1874 int
1875 ldif_back_initialize( BackendInfo *bi )
1876 {
1877 static char *controls[] = {
1878 LDAP_CONTROL_MANAGEDSAIT,
1879 NULL
1880 };
1881 int rc;
1882
1883 bi->bi_flags |=
1884 SLAP_BFLAG_INCREMENT |
1885 SLAP_BFLAG_REFERRALS;
1886
1887 bi->bi_controls = controls;
1888
1889 bi->bi_open = 0;
1890 bi->bi_close = 0;
1891 bi->bi_config = 0;
1892 bi->bi_destroy = 0;
1893
1894 bi->bi_db_init = ldif_back_db_init;
1895 bi->bi_db_config = config_generic_wrapper;
1896 bi->bi_db_open = ldif_back_db_open;
1897 bi->bi_db_close = 0;
1898 bi->bi_db_destroy = ldif_back_db_destroy;
1899
1900 bi->bi_op_bind = ldif_back_bind;
1901 bi->bi_op_unbind = 0;
1902 bi->bi_op_search = ldif_back_search;
1903 bi->bi_op_compare = 0;
1904 bi->bi_op_modify = ldif_back_modify;
1905 bi->bi_op_modrdn = ldif_back_modrdn;
1906 bi->bi_op_add = ldif_back_add;
1907 bi->bi_op_delete = ldif_back_delete;
1908 bi->bi_op_abandon = 0;
1909
1910 bi->bi_extended = 0;
1911
1912 bi->bi_chk_referrals = ldif_back_referrals;
1913
1914 bi->bi_connection_init = 0;
1915 bi->bi_connection_destroy = 0;
1916
1917 bi->bi_entry_get_rw = ldif_back_entry_get;
1918
1919 #if 0 /* NOTE: uncomment to completely disable access control */
1920 bi->bi_access_allowed = slap_access_always_allowed;
1921 #endif
1922
1923 bi->bi_tool_entry_open = ldif_tool_entry_open;
1924 bi->bi_tool_entry_close = ldif_tool_entry_close;
1925 bi->bi_tool_entry_first = backend_tool_entry_first;
1926 bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
1927 bi->bi_tool_entry_next = ldif_tool_entry_next;
1928 bi->bi_tool_entry_get = ldif_tool_entry_get;
1929 bi->bi_tool_entry_put = ldif_tool_entry_put;
1930 bi->bi_tool_entry_reindex = 0;
1931 bi->bi_tool_sync = 0;
1932
1933 bi->bi_tool_dn2id_get = 0;
1934 bi->bi_tool_entry_modify = 0;
1935
1936 bi->bi_cf_ocs = ldifocs;
1937
1938 rc = config_register_schema( ldifcfg, ldifocs );
1939 if ( rc ) return rc;
1940 return 0;
1941 }
1942