ldif.c revision 1.1.1.6 1 /* $NetBSD: ldif.c,v 1.1.1.6 2018/02/06 01:53:17 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-2017 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.1.1.6 2018/02/06 01:53:17 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 int i;
404
405 while (len > 7) {
406 CRC8;
407 len -= 8;
408 }
409 while (len) {
410 CRC1;
411 len--;
412 }
413
414 return crc ^ 0xffffffff;
415 }
416
417 /*
418 * Read a file, or stat() it if datap == NULL. Allocate and fill *datap.
419 * Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error.
420 */
421 static int
422 ldif_read_file( const char *path, char **datap )
423 {
424 int rc = LDAP_SUCCESS, fd, len;
425 int res = -1; /* 0:success, <0:error, >0:file too big/growing. */
426 struct stat st;
427 char *data = NULL, *ptr = NULL;
428 const char *msg;
429
430 if ( datap == NULL ) {
431 res = stat( path, &st );
432 goto done;
433 }
434 fd = open( path, O_RDONLY );
435 if ( fd >= 0 ) {
436 if ( fstat( fd, &st ) == 0 ) {
437 if ( st.st_size > INT_MAX - 2 ) {
438 res = 1;
439 } else {
440 len = st.st_size + 1; /* +1 detects file size > st.st_size */
441 *datap = data = ptr = SLAP_MALLOC( len + 1 );
442 if ( ptr != NULL ) {
443 while ( len && (res = read( fd, ptr, len )) ) {
444 if ( res > 0 ) {
445 len -= res;
446 ptr += res;
447 } else if ( errno != EINTR ) {
448 break;
449 }
450 }
451 *ptr = '\0';
452 }
453 }
454 }
455 if ( close( fd ) < 0 )
456 res = -1;
457 }
458
459 done:
460 if ( res == 0 ) {
461 #ifdef LDAP_DEBUG
462 msg = "entry file exists";
463 if ( datap ) {
464 msg = "read entry file";
465 len = ptr - data;
466 ptr = strstr( data, "\n# CRC32" );
467 if (!ptr) {
468 msg = "read entry file without checksum";
469 } else {
470 unsigned int crc1 = 0, crc2 = 1;
471 if ( sscanf( ptr + 9, "%08x", &crc1) == 1) {
472 ptr = strchr(ptr+1, '\n');
473 if ( ptr ) {
474 ptr++;
475 len -= (ptr - data);
476 crc2 = crc32( ptr, len );
477 }
478 }
479 if ( crc1 != crc2 ) {
480 Debug( LDAP_DEBUG_ANY, "ldif_read_file: checksum error on \"%s\"\n",
481 path, 0, 0 );
482 return rc;
483 }
484 }
485 }
486 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n", msg, path, 0 );
487 #endif /* LDAP_DEBUG */
488 } else {
489 if ( res < 0 && errno == ENOENT ) {
490 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
491 "no entry file \"%s\"\n", path, 0, 0 );
492 rc = LDAP_NO_SUCH_OBJECT;
493 } else {
494 msg = res < 0 ? STRERROR( errno ) : "bad stat() size";
495 Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
496 msg, path, 0 );
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
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
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
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
553 if ( op->o_abandon )
554 return SLAPD_ABANDON;
555
556 if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
557 save_errno = errno;
558 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
559 "cannot create parent directory",
560 parentdir, STRERROR( save_errno ) );
561 *text = "internal error (cannot create parent directory)";
562 return rc;
563 }
564
565 tmpfname = ldif_tempname( path );
566 fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
567 if ( fd < 0 ) {
568 save_errno = errno;
569 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
570 "cannot create file", e->e_dn, STRERROR( save_errno ) );
571 *text = "internal error (cannot create file)";
572
573 } else {
574 ber_len_t dn_len = e->e_name.bv_len;
575 struct berval rdn;
576
577 /* Only save the RDN onto disk */
578 dnRdn( &e->e_name, &rdn );
579 if ( rdn.bv_len != dn_len ) {
580 e->e_name.bv_val[rdn.bv_len] = '\0';
581 e->e_name.bv_len = rdn.bv_len;
582 }
583
584 res = -2;
585 ldap_pvt_thread_mutex_lock( &entry2str_mutex );
586 entry_as_string = entry2str( e, &entry_length );
587 if ( entry_as_string != NULL )
588 res = spew_file( fd, entry_as_string, entry_length, &save_errno );
589 ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
590
591 /* Restore full DN */
592 if ( rdn.bv_len != dn_len ) {
593 e->e_name.bv_val[rdn.bv_len] = ',';
594 e->e_name.bv_len = dn_len;
595 }
596
597 if ( close( fd ) < 0 && res >= 0 ) {
598 res = -1;
599 save_errno = errno;
600 }
601
602 if ( res >= 0 ) {
603 if ( move_file( tmpfname, path->bv_val ) == 0 ) {
604 Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
605 "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 );
606 rc = LDAP_SUCCESS;
607 } else {
608 save_errno = errno;
609 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
610 "could not put entry file for \"%s\" in place: %s\n",
611 e->e_name.bv_val, STRERROR( save_errno ), 0 );
612 *text = "internal error (could not put entry file in place)";
613 }
614 } else if ( res == -1 ) {
615 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
616 "write error to", tmpfname, STRERROR( save_errno ) );
617 *text = "internal error (write error to entry file)";
618 }
619
620 if ( rc != LDAP_SUCCESS ) {
621 unlink( tmpfname );
622 }
623 }
624
625 if ( tmpfname )
626 SLAP_FREE( tmpfname );
627 return rc;
628 }
629
630 /*
631 * Read the entry at path, or if entryp==NULL just see if it exists.
632 * pdn and pndn are the parent's DN and normalized DN, or both NULL.
633 * Return an LDAP result code.
634 */
635 static int
636 ldif_read_entry(
637 Operation *op,
638 const char *path,
639 struct berval *pdn,
640 struct berval *pndn,
641 Entry **entryp,
642 const char **text )
643 {
644 int rc;
645 Entry *entry;
646 char *entry_as_string;
647 struct berval rdn;
648
649 /* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
650 * If so we need not check for LDAP_REQ_BIND here.
651 */
652 if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND )
653 return SLAPD_ABANDON;
654
655 rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
656
657 switch ( rc ) {
658 case LDAP_SUCCESS:
659 if ( entryp == NULL )
660 break;
661 *entryp = entry = str2entry( entry_as_string );
662 SLAP_FREE( entry_as_string );
663 if ( entry == NULL ) {
664 rc = LDAP_OTHER;
665 if ( text != NULL )
666 *text = "internal error (cannot parse some entry file)";
667 break;
668 }
669 if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
670 break;
671 /* Append parent DN to DN from LDIF file */
672 rdn = entry->e_name;
673 build_new_dn( &entry->e_name, pdn, &rdn, NULL );
674 SLAP_FREE( rdn.bv_val );
675 rdn = entry->e_nname;
676 build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
677 SLAP_FREE( rdn.bv_val );
678 break;
679
680 case LDAP_OTHER:
681 if ( text != NULL )
682 *text = entryp
683 ? "internal error (cannot read some entry file)"
684 : "internal error (cannot stat some entry file)";
685 break;
686 }
687
688 return rc;
689 }
690
691 /*
692 * Read the operation's entry, or if entryp==NULL just see if it exists.
693 * Return an LDAP result code. May set *text to a message on failure.
694 * If pathp is non-NULL, set it to the entry filename on success.
695 */
696 static int
697 get_entry(
698 Operation *op,
699 Entry **entryp,
700 struct berval *pathp,
701 const char **text )
702 {
703 int rc;
704 struct berval path, pdn, pndn;
705
706 dnParent( &op->o_req_dn, &pdn );
707 dnParent( &op->o_req_ndn, &pndn );
708 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
709 if ( rc != LDAP_SUCCESS ) {
710 goto done;
711 }
712
713 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
714
715 if ( rc == LDAP_SUCCESS && pathp != NULL ) {
716 *pathp = path;
717 } else {
718 SLAP_FREE( path.bv_val );
719 }
720 done:
721 return rc;
722 }
723
724
725 /*
726 * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
727 * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
728 * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
729 * Does not sort escaped chars correctly, would need to un-escape them.
730 */
731 typedef struct bvlist {
732 struct bvlist *next;
733 char *trunc; /* filename was truncated here */
734 int inum; /* num from "attr={num}" in filename, or INT_MIN */
735 char savech; /* original char at *trunc */
736 /* BVL_NAME(&bvlist) is the filename, allocated after the struct: */
737 # define BVL_NAME(bvl) ((char *) ((bvl) + 1))
738 # define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1)
739 } bvlist;
740
741 static int
742 ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
743 {
744 int rc = LDAP_SUCCESS;
745
746 if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
747 if ( rs == NULL ) {
748 /* Save the entry for tool mode */
749 struct ldif_tool *tl =
750 &((struct ldif_info *) op->o_bd->be_private)->li_tool;
751
752 if ( tl->ecount >= tl->elen ) {
753 /* Allocate/grow entries */
754 ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
755 Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
756 sizeof(Entry *) * elen );
757 if ( entries == NULL ) {
758 Debug( LDAP_DEBUG_ANY,
759 "ldif_send_entry: out of memory\n", 0, 0, 0 );
760 rc = LDAP_OTHER;
761 goto done;
762 }
763 tl->elen = elen;
764 tl->entries = entries;
765 }
766 tl->entries[tl->ecount++] = e;
767 return rc;
768 }
769
770 else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
771 /* Send a continuation reference.
772 * (ldif_back_referrals() handles baseobject referrals.)
773 * Don't check the filter since it's only a candidate.
774 */
775 BerVarray refs = get_entry_referrals( op, e );
776 rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
777 rs->sr_entry = e;
778 rc = send_search_reference( op, rs );
779 ber_bvarray_free( rs->sr_ref );
780 ber_bvarray_free( refs );
781 rs->sr_ref = NULL;
782 rs->sr_entry = NULL;
783 }
784
785 else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
786 rs->sr_entry = e;
787 rs->sr_attrs = op->ors_attrs;
788 /* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
789 * but refraining lets us test unFREEable MODIFIABLE
790 * entries. Like entries built on the stack.
791 */
792 rs->sr_flags = REP_ENTRY_MODIFIABLE;
793 rc = send_search_entry( op, rs );
794 rs->sr_entry = NULL;
795 rs->sr_attrs = NULL;
796 }
797 }
798
799 done:
800 entry_free( e );
801 return rc;
802 }
803
804 /* Read LDIF directory <path> into <listp>. Set *fname_maxlenp. */
805 static int
806 ldif_readdir(
807 Operation *op,
808 SlapReply *rs,
809 const struct berval *path,
810 bvlist **listp,
811 ber_len_t *fname_maxlenp )
812 {
813 int rc = LDAP_SUCCESS;
814 DIR *dir_of_path;
815
816 *listp = NULL;
817 *fname_maxlenp = 0;
818
819 dir_of_path = opendir( path->bv_val );
820 if ( dir_of_path == NULL ) {
821 int save_errno = errno;
822 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
823 int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
824
825 /* Absent directory is OK (leaf entry), except the database dir */
826 if ( is_rootDSE || save_errno != ENOENT ) {
827 Debug( LDAP_DEBUG_ANY,
828 "=> ldif_search_entry: failed to opendir \"%s\": %s\n",
829 path->bv_val, STRERROR( save_errno ), 0 );
830 rc = LDAP_OTHER;
831 if ( rs != NULL )
832 rs->sr_text =
833 save_errno != ENOENT ? "internal error (bad directory)"
834 : "internal error (database directory does not exist)";
835 }
836
837 } else {
838 bvlist *ptr;
839 struct dirent *dir;
840 int save_errno = 0;
841
842 while ( (dir = readdir( dir_of_path )) != NULL ) {
843 size_t fname_len;
844 bvlist *bvl, **prev;
845 char *trunc, *idxp, *endp, *endp2;
846
847 fname_len = strlen( dir->d_name );
848 if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
849 continue;
850 if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
851 continue;
852
853 if ( *fname_maxlenp < fname_len )
854 *fname_maxlenp = fname_len;
855
856 bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
857 if ( bvl == NULL ) {
858 rc = LDAP_OTHER;
859 save_errno = errno;
860 break;
861 }
862 strcpy( BVL_NAME( bvl ), dir->d_name );
863
864 /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
865 trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
866 if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
867 (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
868 (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
869 {
870 /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
871 bvl->inum = strtol( idxp, &endp2, 10 );
872 if ( endp2 == endp ) {
873 trunc = idxp;
874 goto truncate;
875 }
876 }
877 bvl->inum = INT_MIN;
878 truncate:
879 bvl->trunc = trunc;
880 bvl->savech = *trunc;
881 *trunc = '\0';
882
883 /* Insertion sort */
884 for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
885 int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
886 if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
887 break;
888 }
889 *prev = bvl;
890 bvl->next = ptr;
891 }
892
893 if ( closedir( dir_of_path ) < 0 ) {
894 save_errno = errno;
895 rc = LDAP_OTHER;
896 if ( rs != NULL )
897 rs->sr_text = "internal error (bad directory)";
898 }
899 if ( rc != LDAP_SUCCESS ) {
900 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
901 "error reading directory", path->bv_val,
902 STRERROR( save_errno ) );
903 }
904 }
905
906 return rc;
907 }
908
909 /*
910 * Send an entry, recursively search its children, and free or save it.
911 * Return an LDAP result code. Parameters:
912 * op, rs operation and reply. rs == NULL for slap tools.
913 * e entry to search, or NULL for rootDSE.
914 * scope scope for the part of the search from this entry.
915 * path LDIF filename -- bv_len and non-directory part are overwritten.
916 */
917 static int
918 ldif_search_entry(
919 Operation *op,
920 SlapReply *rs,
921 Entry *e,
922 int scope,
923 struct berval *path )
924 {
925 int rc = LDAP_SUCCESS;
926 struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
927
928 if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
929 /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
930 * which bconfig.c seems to need. (TODO: see config_rename_one.)
931 */
932 if ( ber_dupbv( &dn, &e->e_name ) == NULL ||
933 ber_dupbv( &ndn, &e->e_nname ) == NULL )
934 {
935 Debug( LDAP_DEBUG_ANY,
936 "ldif_search_entry: out of memory\n", 0, 0, 0 );
937 rc = LDAP_OTHER;
938 goto done;
939 }
940 }
941
942 /* Send the entry if appropriate, and free or save it */
943 if ( e != NULL )
944 rc = ldif_send_entry( op, rs, e, scope );
945
946 /* Search the children */
947 if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
948 bvlist *list, *ptr;
949 struct berval fpath; /* becomes child pathname */
950 char *dir_end; /* will point past dirname in fpath */
951
952 ldif2dir_len( *path );
953 ldif2dir_name( *path );
954 rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
955
956 if ( list != NULL ) {
957 const char **text = rs == NULL ? NULL : &rs->sr_text;
958
959 if ( scope == LDAP_SCOPE_ONELEVEL )
960 scope = LDAP_SCOPE_BASE;
961 else if ( scope == LDAP_SCOPE_SUBORDINATE )
962 scope = LDAP_SCOPE_SUBTREE;
963
964 /* Allocate fpath and fill in directory part */
965 dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
966 if ( dir_end == NULL )
967 rc = LDAP_OTHER;
968
969 do {
970 ptr = list;
971
972 if ( rc == LDAP_SUCCESS ) {
973 *ptr->trunc = ptr->savech;
974 FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
975
976 rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
977 &e, text );
978 switch ( rc ) {
979 case LDAP_SUCCESS:
980 rc = ldif_search_entry( op, rs, e, scope, &fpath );
981 break;
982 case LDAP_NO_SUCH_OBJECT:
983 /* Only the search baseDN may produce noSuchObject. */
984 rc = LDAP_OTHER;
985 if ( rs != NULL )
986 rs->sr_text = "internal error "
987 "(did someone just remove an entry file?)";
988 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
989 "file listed in parent directory does not exist: "
990 "\"%s\"\n", fpath.bv_val, 0, 0 );
991 break;
992 }
993 }
994
995 list = ptr->next;
996 SLAP_FREE( ptr );
997 } while ( list != NULL );
998
999 if ( !BER_BVISNULL( &fpath ) )
1000 SLAP_FREE( fpath.bv_val );
1001 }
1002 }
1003
1004 done:
1005 if ( !BER_BVISEMPTY( &dn ) )
1006 ber_memfree( dn.bv_val );
1007 if ( !BER_BVISEMPTY( &ndn ) )
1008 ber_memfree( ndn.bv_val );
1009 return rc;
1010 }
1011
1012 static int
1013 search_tree( Operation *op, SlapReply *rs )
1014 {
1015 int rc = LDAP_SUCCESS;
1016 Entry *e = NULL;
1017 struct berval path;
1018 struct berval pdn, pndn;
1019
1020 (void) ndn2path( op, &op->o_req_ndn, &path, 1 );
1021 if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
1022 /* Read baseObject */
1023 dnParent( &op->o_req_dn, &pdn );
1024 dnParent( &op->o_req_ndn, &pndn );
1025 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
1026 rs == NULL ? NULL : &rs->sr_text );
1027 }
1028 if ( rc == LDAP_SUCCESS )
1029 rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
1030
1031 ch_free( path.bv_val );
1032 return rc;
1033 }
1034
1035
1036 /*
1037 * Prepare to create or rename an entry:
1038 * Check that the entry does not already exist.
1039 * Check that the parent entry exists and can have subordinates,
1040 * unless need_dir is NULL or adding the suffix entry.
1041 *
1042 * Return an LDAP result code. May set *text to a message on failure.
1043 * If success, set *dnpath to LDIF entry path and *need_dir to
1044 * (directory must be created ? dirname : NULL).
1045 */
1046 static int
1047 ldif_prepare_create(
1048 Operation *op,
1049 Entry *e,
1050 struct berval *dnpath,
1051 char **need_dir,
1052 const char **text )
1053 {
1054 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1055 struct berval *ndn = &e->e_nname;
1056 struct berval ppath = BER_BVNULL;
1057 struct stat st;
1058 Entry *parent = NULL;
1059 int rc;
1060
1061 if ( op->o_abandon )
1062 return SLAPD_ABANDON;
1063
1064 rc = ndn2path( op, ndn, dnpath, 0 );
1065 if ( rc != LDAP_SUCCESS ) {
1066 return rc;
1067 }
1068
1069 if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
1070 rc = LDAP_ALREADY_EXISTS;
1071
1072 } else if ( errno != ENOENT ) {
1073 Debug( LDAP_DEBUG_ANY,
1074 "ldif_prepare_create: cannot stat \"%s\": %s\n",
1075 dnpath->bv_val, STRERROR( errno ), 0 );
1076 rc = LDAP_OTHER;
1077 *text = "internal error (cannot check entry file)";
1078
1079 } else if ( need_dir != NULL ) {
1080 *need_dir = NULL;
1081 rc = get_parent_path( dnpath, &ppath );
1082 /* If parent dir exists, so does parent .ldif:
1083 * The directory gets created after and removed before the .ldif.
1084 * Except with the database directory, which has no matching entry.
1085 */
1086 if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
1087 rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
1088 ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
1089 }
1090 switch ( rc ) {
1091 case LDAP_NO_SUCH_OBJECT:
1092 /* No parent dir, check parent .ldif */
1093 dir2ldif_name( ppath );
1094 rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
1095 (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
1096 ? &parent : NULL),
1097 text );
1098 switch ( rc ) {
1099 case LDAP_SUCCESS:
1100 /* Check that parent is not a referral, unless
1101 * ldif_back_referrals() already checked.
1102 */
1103 if ( parent != NULL ) {
1104 int is_ref = is_entry_referral( parent );
1105 entry_free( parent );
1106 if ( is_ref ) {
1107 rc = LDAP_AFFECTS_MULTIPLE_DSAS;
1108 *text = op->o_tag == LDAP_REQ_MODDN
1109 ? "newSuperior is a referral object"
1110 : "parent is a referral object";
1111 break;
1112 }
1113 }
1114 /* Must create parent directory. */
1115 ldif2dir_name( ppath );
1116 *need_dir = ppath.bv_val;
1117 break;
1118 case LDAP_NO_SUCH_OBJECT:
1119 *text = op->o_tag == LDAP_REQ_MODDN
1120 ? "newSuperior object does not exist"
1121 : "parent does not exist";
1122 break;
1123 }
1124 break;
1125 case LDAP_OTHER:
1126 Debug( LDAP_DEBUG_ANY,
1127 "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
1128 ndn->bv_val, STRERROR( errno ), 0 );
1129 *text = "internal error (cannot stat parent dir)";
1130 break;
1131 }
1132 if ( *need_dir == NULL && ppath.bv_val != NULL )
1133 SLAP_FREE( ppath.bv_val );
1134 }
1135
1136 if ( rc != LDAP_SUCCESS ) {
1137 SLAP_FREE( dnpath->bv_val );
1138 BER_BVZERO( dnpath );
1139 }
1140 return rc;
1141 }
1142
1143 static int
1144 apply_modify_to_entry(
1145 Entry *entry,
1146 Modifications *modlist,
1147 Operation *op,
1148 SlapReply *rs,
1149 char *textbuf )
1150 {
1151 int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
1152 int is_oc = 0;
1153 Modification *mods;
1154
1155 if (!acl_check_modlist(op, entry, modlist)) {
1156 return LDAP_INSUFFICIENT_ACCESS;
1157 }
1158
1159 for (; modlist != NULL; modlist = modlist->sml_next) {
1160 mods = &modlist->sml_mod;
1161
1162 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
1163 is_oc = 1;
1164 }
1165 switch (mods->sm_op) {
1166 case LDAP_MOD_ADD:
1167 rc = modify_add_values(entry, mods,
1168 get_permissiveModify(op),
1169 &rs->sr_text, textbuf,
1170 SLAP_TEXT_BUFLEN );
1171 break;
1172
1173 case LDAP_MOD_DELETE:
1174 rc = modify_delete_values(entry, mods,
1175 get_permissiveModify(op),
1176 &rs->sr_text, textbuf,
1177 SLAP_TEXT_BUFLEN );
1178 break;
1179
1180 case LDAP_MOD_REPLACE:
1181 rc = modify_replace_values(entry, mods,
1182 get_permissiveModify(op),
1183 &rs->sr_text, textbuf,
1184 SLAP_TEXT_BUFLEN );
1185 break;
1186
1187 case LDAP_MOD_INCREMENT:
1188 rc = modify_increment_values( entry,
1189 mods, get_permissiveModify(op),
1190 &rs->sr_text, textbuf,
1191 SLAP_TEXT_BUFLEN );
1192 break;
1193
1194 case SLAP_MOD_SOFTADD:
1195 mods->sm_op = LDAP_MOD_ADD;
1196 rc = modify_add_values(entry, mods,
1197 get_permissiveModify(op),
1198 &rs->sr_text, textbuf,
1199 SLAP_TEXT_BUFLEN );
1200 mods->sm_op = SLAP_MOD_SOFTADD;
1201 if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
1202 rc = LDAP_SUCCESS;
1203 }
1204 break;
1205
1206 case SLAP_MOD_SOFTDEL:
1207 mods->sm_op = LDAP_MOD_DELETE;
1208 rc = modify_delete_values(entry, mods,
1209 get_permissiveModify(op),
1210 &rs->sr_text, textbuf,
1211 SLAP_TEXT_BUFLEN );
1212 mods->sm_op = SLAP_MOD_SOFTDEL;
1213 if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
1214 rc = LDAP_SUCCESS;
1215 }
1216 break;
1217
1218 case SLAP_MOD_ADD_IF_NOT_PRESENT:
1219 if ( attr_find( entry->e_attrs, mods->sm_desc ) ) {
1220 rc = LDAP_SUCCESS;
1221 break;
1222 }
1223 mods->sm_op = LDAP_MOD_ADD;
1224 rc = modify_add_values(entry, mods,
1225 get_permissiveModify(op),
1226 &rs->sr_text, textbuf,
1227 SLAP_TEXT_BUFLEN );
1228 mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
1229 break;
1230 }
1231 if(rc != LDAP_SUCCESS) break;
1232 }
1233
1234 if ( rc == LDAP_SUCCESS ) {
1235 rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
1236 if ( is_oc ) {
1237 entry->e_ocflags = 0;
1238 }
1239 /* check that the entry still obeys the schema */
1240 rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
1241 &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN );
1242 }
1243
1244 return rc;
1245 }
1246
1247
1248 static int
1249 ldif_back_referrals( Operation *op, SlapReply *rs )
1250 {
1251 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1252 struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn;
1253 ber_len_t min_dnlen;
1254 Entry *entry = NULL, **entryp;
1255 BerVarray ref;
1256 int rc;
1257
1258 min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
1259 if ( min_dnlen == 0 ) {
1260 /* Catch root DSE (empty DN), it is not a referral */
1261 min_dnlen = 1;
1262 }
1263 if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) {
1264 return LDAP_SUCCESS; /* Root DSE again */
1265 }
1266
1267 entryp = get_manageDSAit( op ) ? NULL : &entry;
1268 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1269
1270 for (;;) {
1271 dnParent( &dn, &dn );
1272 dnParent( &ndn, &ndn );
1273 rc = ldif_read_entry( op, path.bv_val, &dn, &ndn,
1274 entryp, &rs->sr_text );
1275 if ( rc != LDAP_NO_SUCH_OBJECT )
1276 break;
1277
1278 rc = LDAP_SUCCESS;
1279 if ( ndn.bv_len < min_dnlen )
1280 break;
1281 (void) get_parent_path( &path, NULL );
1282 dir2ldif_name( path );
1283 entryp = &entry;
1284 }
1285
1286 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1287 SLAP_FREE( path.bv_val );
1288
1289 if ( entry != NULL ) {
1290 if ( is_entry_referral( entry ) ) {
1291 Debug( LDAP_DEBUG_TRACE,
1292 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
1293 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn );
1294
1295 ref = get_entry_referrals( op, entry );
1296 rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn,
1297 op->o_tag == LDAP_REQ_SEARCH ?
1298 op->ors_scope : LDAP_SCOPE_DEFAULT );
1299 ber_bvarray_free( ref );
1300
1301 if ( rs->sr_ref != NULL ) {
1302 /* send referral */
1303 rc = rs->sr_err = LDAP_REFERRAL;
1304 rs->sr_matched = entry->e_dn;
1305 send_ldap_result( op, rs );
1306 ber_bvarray_free( rs->sr_ref );
1307 rs->sr_ref = NULL;
1308 } else {
1309 rc = LDAP_OTHER;
1310 rs->sr_text = "bad referral object";
1311 }
1312 rs->sr_matched = NULL;
1313 }
1314
1315 entry_free( entry );
1316 }
1317
1318 return rc;
1319 }
1320
1321
1322 /* LDAP operations */
1323
1324 static int
1325 ldif_back_bind( Operation *op, SlapReply *rs )
1326 {
1327 struct ldif_info *li;
1328 Attribute *a;
1329 AttributeDescription *password = slap_schema.si_ad_userPassword;
1330 int return_val;
1331 Entry *entry = NULL;
1332
1333 switch ( be_rootdn_bind( op, rs ) ) {
1334 case SLAP_CB_CONTINUE:
1335 break;
1336
1337 default:
1338 /* in case of success, front end will send result;
1339 * otherwise, be_rootdn_bind() did */
1340 return rs->sr_err;
1341 }
1342
1343 li = (struct ldif_info *) op->o_bd->be_private;
1344 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1345 return_val = get_entry(op, &entry, NULL, NULL);
1346
1347 /* no object is found for them */
1348 if(return_val != LDAP_SUCCESS) {
1349 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
1350 goto return_result;
1351 }
1352
1353 /* they don't have userpassword */
1354 if((a = attr_find(entry->e_attrs, password)) == NULL) {
1355 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1356 return_val = 1;
1357 goto return_result;
1358 }
1359
1360 /* authentication actually failed */
1361 if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
1362 &rs->sr_text) != 0) {
1363 rs->sr_err = LDAP_INVALID_CREDENTIALS;
1364 return_val = 1;
1365 goto return_result;
1366 }
1367
1368 /* let the front-end send success */
1369 return_val = LDAP_SUCCESS;
1370
1371 return_result:
1372 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1373 if(return_val != LDAP_SUCCESS)
1374 send_ldap_result( op, rs );
1375 if(entry != NULL)
1376 entry_free(entry);
1377 return return_val;
1378 }
1379
1380 static int
1381 ldif_back_search( Operation *op, SlapReply *rs )
1382 {
1383 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1384
1385 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1386 rs->sr_err = search_tree( op, rs );
1387 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1388 send_ldap_result(op, rs);
1389
1390 return rs->sr_err;
1391 }
1392
1393 static int
1394 ldif_back_add( Operation *op, SlapReply *rs )
1395 {
1396 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1397 Entry * e = op->ora_e;
1398 struct berval path;
1399 char *parentdir;
1400 char textbuf[SLAP_TEXT_BUFLEN];
1401 int rc;
1402
1403 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
1404
1405 rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
1406 &rs->sr_text, textbuf, sizeof( textbuf ) );
1407 if ( rc != LDAP_SUCCESS )
1408 goto send_res;
1409
1410 rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
1411 if ( rc != LDAP_SUCCESS )
1412 goto send_res;
1413
1414 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1415
1416 rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
1417 if ( rc == LDAP_SUCCESS ) {
1418 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1419 rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
1420 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1421
1422 SLAP_FREE( path.bv_val );
1423 if ( parentdir != NULL )
1424 SLAP_FREE( parentdir );
1425 }
1426
1427 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1428
1429 send_res:
1430 rs->sr_err = rc;
1431 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
1432 rc, rs->sr_text ? rs->sr_text : "", 0 );
1433 send_ldap_result( op, rs );
1434 slap_graduate_commit_csn( op );
1435 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1436 return rs->sr_err;
1437 }
1438
1439 static int
1440 ldif_back_modify( Operation *op, SlapReply *rs )
1441 {
1442 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1443 Modifications * modlst = op->orm_modlist;
1444 struct berval path;
1445 Entry *entry;
1446 char textbuf[SLAP_TEXT_BUFLEN];
1447 int rc;
1448
1449 slap_mods_opattrs( op, &op->orm_modlist, 1 );
1450
1451 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1452
1453 rc = get_entry( op, &entry, &path, &rs->sr_text );
1454 if ( rc == LDAP_SUCCESS ) {
1455 rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
1456 if ( rc == LDAP_SUCCESS ) {
1457 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1458 rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
1459 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1460 }
1461
1462 entry_free( entry );
1463 SLAP_FREE( path.bv_val );
1464 }
1465
1466 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1467
1468 rs->sr_err = rc;
1469 send_ldap_result( op, rs );
1470 slap_graduate_commit_csn( op );
1471 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1472 return rs->sr_err;
1473 }
1474
1475 static int
1476 ldif_back_delete( Operation *op, SlapReply *rs )
1477 {
1478 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1479 struct berval path;
1480 int rc = LDAP_SUCCESS;
1481
1482 if ( BER_BVISEMPTY( &op->o_csn )) {
1483 struct berval csn;
1484 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
1485
1486 csn.bv_val = csnbuf;
1487 csn.bv_len = sizeof( csnbuf );
1488 slap_get_csn( op, &csn, 1 );
1489 }
1490
1491 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1492 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1493 if ( op->o_abandon ) {
1494 rc = SLAPD_ABANDON;
1495 goto done;
1496 }
1497
1498 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
1499 if ( rc != LDAP_SUCCESS ) {
1500 goto done;
1501 }
1502
1503 ldif2dir_len( path );
1504 ldif2dir_name( path );
1505 if ( rmdir( path.bv_val ) < 0 ) {
1506 switch ( errno ) {
1507 case ENOTEMPTY:
1508 rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1509 break;
1510 case ENOENT:
1511 /* is leaf, go on */
1512 break;
1513 default:
1514 rc = LDAP_OTHER;
1515 rs->sr_text = "internal error (cannot delete subtree directory)";
1516 break;
1517 }
1518 }
1519
1520 if ( rc == LDAP_SUCCESS ) {
1521 dir2ldif_name( path );
1522 if ( unlink( path.bv_val ) < 0 ) {
1523 rc = LDAP_NO_SUCH_OBJECT;
1524 if ( errno != ENOENT ) {
1525 rc = LDAP_OTHER;
1526 rs->sr_text = "internal error (cannot delete entry file)";
1527 }
1528 }
1529 }
1530
1531 if ( rc == LDAP_OTHER ) {
1532 Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
1533 "cannot delete", path.bv_val, STRERROR( errno ) );
1534 }
1535
1536 SLAP_FREE( path.bv_val );
1537 done:
1538 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1539 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1540 rs->sr_err = rc;
1541 send_ldap_result( op, rs );
1542 slap_graduate_commit_csn( op );
1543 return rs->sr_err;
1544 }
1545
1546
1547 static int
1548 ldif_move_entry(
1549 Operation *op,
1550 Entry *entry,
1551 int same_ndn,
1552 struct berval *oldpath,
1553 const char **text )
1554 {
1555 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1556 struct berval newpath;
1557 char *parentdir = NULL, *trash;
1558 int rc, rename_res;
1559
1560 if ( same_ndn ) {
1561 rc = LDAP_SUCCESS;
1562 newpath = *oldpath;
1563 } else {
1564 rc = ldif_prepare_create( op, entry, &newpath,
1565 op->orr_newSup ? &parentdir : NULL, text );
1566 }
1567
1568 if ( rc == LDAP_SUCCESS ) {
1569 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1570
1571 rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
1572 if ( rc == LDAP_SUCCESS && !same_ndn ) {
1573 trash = oldpath->bv_val; /* will be .ldif file to delete */
1574 ldif2dir_len( newpath );
1575 ldif2dir_len( *oldpath );
1576 /* Move subdir before deleting old entry,
1577 * so .ldif always exists if subdir does.
1578 */
1579 ldif2dir_name( newpath );
1580 ldif2dir_name( *oldpath );
1581 rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
1582 if ( rename_res != 0 && errno != ENOENT ) {
1583 rc = LDAP_OTHER;
1584 *text = "internal error (cannot move this subtree)";
1585 trash = newpath.bv_val;
1586 }
1587
1588 /* Delete old entry, or if error undo change */
1589 for (;;) {
1590 dir2ldif_name( newpath );
1591 dir2ldif_name( *oldpath );
1592 if ( unlink( trash ) == 0 )
1593 break;
1594 if ( rc == LDAP_SUCCESS ) {
1595 /* Prepare to undo change and return failure */
1596 rc = LDAP_OTHER;
1597 *text = "internal error (cannot move this entry)";
1598 trash = newpath.bv_val;
1599 if ( rename_res != 0 )
1600 continue;
1601 /* First move subdirectory back */
1602 ldif2dir_name( newpath );
1603 ldif2dir_name( *oldpath );
1604 if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
1605 continue;
1606 }
1607 *text = "added new but couldn't delete old entry!";
1608 break;
1609 }
1610
1611 if ( rc != LDAP_SUCCESS ) {
1612 char s[128];
1613 snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
1614 Debug( LDAP_DEBUG_ANY,
1615 "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
1616 s, op->o_req_dn.bv_val, entry->e_dn );
1617 }
1618 }
1619
1620 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1621 if ( !same_ndn )
1622 SLAP_FREE( newpath.bv_val );
1623 if ( parentdir != NULL )
1624 SLAP_FREE( parentdir );
1625 }
1626
1627 return rc;
1628 }
1629
1630 static int
1631 ldif_back_modrdn( Operation *op, SlapReply *rs )
1632 {
1633 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1634 struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1635 struct berval p_dn, old_path;
1636 Entry *entry;
1637 char textbuf[SLAP_TEXT_BUFLEN];
1638 int rc, same_ndn;
1639
1640 slap_mods_opattrs( op, &op->orr_modlist, 1 );
1641
1642 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1643
1644 rc = get_entry( op, &entry, &old_path, &rs->sr_text );
1645 if ( rc == LDAP_SUCCESS ) {
1646 /* build new dn, and new ndn for the entry */
1647 if ( op->oq_modrdn.rs_newSup != NULL ) {
1648 p_dn = *op->oq_modrdn.rs_newSup;
1649 } else {
1650 dnParent( &entry->e_name, &p_dn );
1651 }
1652 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
1653 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1654 same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
1655 ber_memfree_x( entry->e_name.bv_val, NULL );
1656 ber_memfree_x( entry->e_nname.bv_val, NULL );
1657 entry->e_name = new_dn;
1658 entry->e_nname = new_ndn;
1659
1660 /* perform the modifications */
1661 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
1662 if ( rc == LDAP_SUCCESS )
1663 rc = ldif_move_entry( op, entry, same_ndn, &old_path,
1664 &rs->sr_text );
1665
1666 entry_free( entry );
1667 SLAP_FREE( old_path.bv_val );
1668 }
1669
1670 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1671 rs->sr_err = rc;
1672 send_ldap_result( op, rs );
1673 slap_graduate_commit_csn( op );
1674 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1675 return rs->sr_err;
1676 }
1677
1678
1679 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1680 static int
1681 ldif_back_entry_get(
1682 Operation *op,
1683 struct berval *ndn,
1684 ObjectClass *oc,
1685 AttributeDescription *at,
1686 int rw,
1687 Entry **e )
1688 {
1689 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1690 struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1691 int rc;
1692
1693 assert( ndn != NULL );
1694 assert( !BER_BVISNULL( ndn ) );
1695
1696 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1697 op->o_req_dn = *ndn;
1698 op->o_req_ndn = *ndn;
1699 rc = get_entry( op, e, NULL, NULL );
1700 op->o_req_dn = op_dn;
1701 op->o_req_ndn = op_ndn;
1702 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1703
1704 if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1705 rc = LDAP_NO_SUCH_ATTRIBUTE;
1706 entry_free( *e );
1707 *e = NULL;
1708 }
1709
1710 return rc;
1711 }
1712
1713
1714 /* Slap tools */
1715
1716 static int
1717 ldif_tool_entry_open( BackendDB *be, int mode )
1718 {
1719 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1720
1721 tl->ecurrent = 0;
1722 return 0;
1723 }
1724
1725 static int
1726 ldif_tool_entry_close( BackendDB *be )
1727 {
1728 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1729 Entry **entries = tl->entries;
1730 ID i;
1731
1732 for ( i = tl->ecount; i--; )
1733 if ( entries[i] )
1734 entry_free( entries[i] );
1735 SLAP_FREE( entries );
1736 tl->entries = NULL;
1737 tl->ecount = tl->elen = 0;
1738 return 0;
1739 }
1740
1741 static ID
1742 ldif_tool_entry_next( BackendDB *be )
1743 {
1744 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1745
1746 do {
1747 Entry *e = tl->entries[ tl->ecurrent ];
1748
1749 if ( tl->ecurrent >= tl->ecount ) {
1750 return NOID;
1751 }
1752
1753 ++tl->ecurrent;
1754
1755 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1756 continue;
1757 }
1758
1759 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter ) != LDAP_COMPARE_TRUE ) {
1760 continue;
1761 }
1762
1763 break;
1764 } while ( 1 );
1765
1766 return tl->ecurrent;
1767 }
1768
1769 static ID
1770 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1771 {
1772 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1773
1774 tl->tl_base = base;
1775 tl->tl_scope = scope;
1776 tl->tl_filter = f;
1777
1778 if ( tl->entries == NULL ) {
1779 Operation op = {0};
1780
1781 op.o_bd = be;
1782 op.o_req_dn = *be->be_suffix;
1783 op.o_req_ndn = *be->be_nsuffix;
1784 op.ors_scope = LDAP_SCOPE_SUBTREE;
1785 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1786 tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1787 return NOID; /* fail ldif_tool_entry_get() */
1788 }
1789 }
1790 return ldif_tool_entry_next( be );
1791 }
1792
1793 static Entry *
1794 ldif_tool_entry_get( BackendDB *be, ID id )
1795 {
1796 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1797 Entry *e = NULL;
1798
1799 --id;
1800 if ( id < tl->ecount ) {
1801 e = tl->entries[id];
1802 tl->entries[id] = NULL;
1803 }
1804 return e;
1805 }
1806
1807 static ID
1808 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1809 {
1810 int rc;
1811 const char *errmsg = NULL;
1812 struct berval path;
1813 char *parentdir;
1814 Operation op = {0};
1815
1816 op.o_bd = be;
1817 rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1818 if ( rc == LDAP_SUCCESS ) {
1819 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1820
1821 SLAP_FREE( path.bv_val );
1822 if ( parentdir != NULL )
1823 SLAP_FREE( parentdir );
1824 if ( rc == LDAP_SUCCESS )
1825 return 1;
1826 }
1827
1828 if ( errmsg == NULL && rc != LDAP_OTHER )
1829 errmsg = ldap_err2string( rc );
1830 if ( errmsg != NULL )
1831 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1832 return NOID;
1833 }
1834
1835
1836 /* Setup */
1837
1838 static int
1839 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1840 {
1841 struct ldif_info *li;
1842
1843 li = ch_calloc( 1, sizeof(struct ldif_info) );
1844 be->be_private = li;
1845 be->be_cf_ocs = ldifocs;
1846 ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1847 ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1848 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1849 return 0;
1850 }
1851
1852 static int
1853 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1854 {
1855 struct ldif_info *li = be->be_private;
1856
1857 ch_free( li->li_base_path.bv_val );
1858 ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1859 ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1860 free( be->be_private );
1861 return 0;
1862 }
1863
1864 static int
1865 ldif_back_db_open( Backend *be, ConfigReply *cr )
1866 {
1867 struct ldif_info *li = (struct ldif_info *) be->be_private;
1868 if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1869 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1870 return 1;
1871 }
1872 return 0;
1873 }
1874
1875 int
1876 ldif_back_initialize( BackendInfo *bi )
1877 {
1878 static char *controls[] = {
1879 LDAP_CONTROL_MANAGEDSAIT,
1880 NULL
1881 };
1882 int rc;
1883
1884 bi->bi_flags |=
1885 SLAP_BFLAG_INCREMENT |
1886 SLAP_BFLAG_REFERRALS;
1887
1888 bi->bi_controls = controls;
1889
1890 bi->bi_open = 0;
1891 bi->bi_close = 0;
1892 bi->bi_config = 0;
1893 bi->bi_destroy = 0;
1894
1895 bi->bi_db_init = ldif_back_db_init;
1896 bi->bi_db_config = config_generic_wrapper;
1897 bi->bi_db_open = ldif_back_db_open;
1898 bi->bi_db_close = 0;
1899 bi->bi_db_destroy = ldif_back_db_destroy;
1900
1901 bi->bi_op_bind = ldif_back_bind;
1902 bi->bi_op_unbind = 0;
1903 bi->bi_op_search = ldif_back_search;
1904 bi->bi_op_compare = 0;
1905 bi->bi_op_modify = ldif_back_modify;
1906 bi->bi_op_modrdn = ldif_back_modrdn;
1907 bi->bi_op_add = ldif_back_add;
1908 bi->bi_op_delete = ldif_back_delete;
1909 bi->bi_op_abandon = 0;
1910
1911 bi->bi_extended = 0;
1912
1913 bi->bi_chk_referrals = ldif_back_referrals;
1914
1915 bi->bi_connection_init = 0;
1916 bi->bi_connection_destroy = 0;
1917
1918 bi->bi_entry_get_rw = ldif_back_entry_get;
1919
1920 #if 0 /* NOTE: uncomment to completely disable access control */
1921 bi->bi_access_allowed = slap_access_always_allowed;
1922 #endif
1923
1924 bi->bi_tool_entry_open = ldif_tool_entry_open;
1925 bi->bi_tool_entry_close = ldif_tool_entry_close;
1926 bi->bi_tool_entry_first = backend_tool_entry_first;
1927 bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
1928 bi->bi_tool_entry_next = ldif_tool_entry_next;
1929 bi->bi_tool_entry_get = ldif_tool_entry_get;
1930 bi->bi_tool_entry_put = ldif_tool_entry_put;
1931 bi->bi_tool_entry_reindex = 0;
1932 bi->bi_tool_sync = 0;
1933
1934 bi->bi_tool_dn2id_get = 0;
1935 bi->bi_tool_entry_modify = 0;
1936
1937 bi->bi_cf_ocs = ldifocs;
1938
1939 rc = config_register_schema( ldifcfg, ldifocs );
1940 if ( rc ) return rc;
1941 return 0;
1942 }
1943