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