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