1 /* ldif.c - the ldif backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2018 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
17 * This work was originally developed by Eric Stokes for inclusion
18 * in OpenLDAP Software.
23 #include <ac/string.h>
24 #include <sys/types.h>
26 #include <ac/dirent.h>
29 #include <ac/unistd.h>
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;
45 /* Per-database data */
47 struct berval li_base_path; /* database directory */
48 struct ldif_tool li_tool; /* for slap tools */
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.)
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 */
61 static int write_data( int fd, const char *spew, int len, int *save_errno );
64 #define mkdir(a,b) mkdir(a)
65 #define move_file(from, to) (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
67 #define move_file(from, to) rename(from, to)
69 #define move_dir(from, to) rename(from, to)
73 #define LDIF_FILETYPE_SEP '.' /* LDIF[0] */
76 * Unsafe/translated characters in the filesystem.
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.
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.)
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.
90 * Thus an LDIF filename is a valid normalized RDN (or suffix DN)
91 * followed by ".ldif", except with '\\' replaced with LDIF_ESCAPE_CHAR.
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
101 #define LDIF_ESCAPE_CHAR '\\'
102 #define LDIF_UNSAFE_CHAR(c) ((c) == '/' || (c) == ':')
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) == '*')
116 * Left and Right "{num}" prefix to ordered RDNs ("olcDatabase={1}bdb").
117 * IX_DN* are for LDAP RDNs, IX_FS* for their .ldif filenames.
122 #define IX_FSL IX_DNL
123 #define IX_FSR IX_DNR
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.
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)))
145 * Helper macro for LDIF_NEED_ESCAPE(): Treat character x as unsafe if
146 * back-ldif does not already treat is specially.
148 #define LDIF_MAYBE_UNSAFE(c, x) \
149 (!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \
152 /* Collect other "safe char" tests here, until someone needs a fix. */
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))
160 /* Sanity check: Try to force a compilation error if !safe_filenames */
162 int assert_safe_filenames : safe_filenames ? 2 : -2;
163 } assert_safe_filenames[safe_filenames ? 2 : -2];
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 }
177 static ConfigOCs ldifocs[] = {
179 "NAME 'olcLdifConfig' "
180 "DESC 'LDIF backend configuration' "
181 "SUP olcDatabaseConfig "
182 "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg },
188 * Handle file/directory names.
191 /* Set *res = LDIF filename path for the normalized DN */
193 ndn2path( Operation *op, struct berval *dn, struct berval *res, int empty_ok )
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;
201 static const char hex[] = "0123456789ABCDEF";
203 assert( dn != NULL );
204 assert( !BER_BVISNULL( dn ) );
205 assert( suffixdn != NULL );
206 assert( !BER_BVISNULL( suffixdn ) );
207 assert( dnIsSuffix( dn, suffixdn ) );
209 if ( dn->bv_len == 0 && !empty_ok ) {
210 return LDAP_UNWILLING_TO_PERFORM;
214 end = start + dn->bv_len;
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; ) {
220 if ( LDIF_NEED_ESCAPE( ch ) )
223 res->bv_val = ch_malloc( len + 1 );
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 ) {
230 if ( DN_SEPARATOR( *next ) )
233 /* Append <dirsep> <p..end-1: RDN or database-suffix> */
234 for ( *ptr++ = LDAP_DIRSEP[0]; p < end; *ptr++ = ch ) {
236 if ( LDIF_ESCAPE_CHAR != '\\' && ch == '\\' ) {
237 ch = LDIF_ESCAPE_CHAR;
238 } else if ( IX_FSL != IX_DNL && ch == IX_DNL ) {
240 } else if ( IX_FSR != IX_DNR && ch == IX_DNR ) {
242 } else if ( LDIF_NEED_ESCAPE( ch ) ) {
243 *ptr++ = LDIF_ESCAPE_CHAR;
244 *ptr++ = hex[(ch & 0xFFU) >> 4];
245 ch = hex[ch & 0x0FU];
249 ptr = lutil_strcopy( ptr, LDIF );
250 res->bv_len = ptr - res->bv_val;
252 assert( res->bv_len <= len );
258 * *dest = dupbv(<dir + LDAP_DIRSEP>), plus room for <more>-sized filename.
259 * Return pointer past the dirname.
262 fullpath_alloc( struct berval *dest, const struct berval *dir, ber_len_t more )
264 char *s = SLAP_MALLOC( dir->bv_len + more + 2 );
269 Debug( LDAP_DEBUG_ANY, "back-ldif: out of memory\n", 0, 0, 0 );
271 s = lutil_strcopy( dest->bv_val, dir->bv_val );
272 *s++ = LDAP_DIRSEP[0];
274 dest->bv_len = s - dest->bv_val;
280 * Append filename to fullpath_alloc() dirname or replace previous filename.
281 * dir_end = fullpath_alloc() return value.
283 #define FILL_PATH(fpath, dir_end, filename) \
284 ((fpath)->bv_len = lutil_strcopy(dir_end, filename) - (fpath)->bv_val)
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)
294 /* Get the parent directory path, plus the LDIF suffix overwritten by a \0. */
296 get_parent_path( struct berval *dnpath, struct berval *res )
298 ber_len_t i = dnpath->bv_len;
300 while ( i > 0 && dnpath->bv_val[ --i ] != LDAP_DIRSEP[0] ) ;
304 res->bv_val = SLAP_MALLOC( i + 1 + STRLENOF(LDIF) );
305 if ( res->bv_val == NULL )
307 AC_MEMCPY( res->bv_val, dnpath->bv_val, i );
310 strcpy( res->bv_val + i, LDIF );
311 res->bv_val[i] = '\0';
315 /* Make temporary filename pattern for mkstemp() based on dnpath. */
317 ldif_tempname( const struct berval *dnpath )
319 static const char suffix[] = ".XXXXXX";
320 ber_len_t len = dnpath->bv_len - STRLENOF( LDIF );
321 char *name = SLAP_MALLOC( len + sizeof( suffix ) );
323 if ( name != NULL ) {
324 AC_MEMCPY( name, dnpath->bv_val, len );
325 strcpy( name + len, suffix );
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.
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,
391 #define CRC1 crc = crctab[(crc ^ *buf++) & 0xff] ^ (crc >> 8)
392 #define CRC8 CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1
394 crc32(const void *vbuf, int len)
396 const unsigned char *buf = vbuf;
397 ber_uint_t crc = 0xffffffff;
408 return crc ^ 0xffffffff;
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.
416 ldif_read_file( const char *path, char **datap )
418 int rc = LDAP_SUCCESS, fd, len;
419 int res = -1; /* 0:success, <0:error, >0:file too big/growing. */
421 char *data = NULL, *ptr = NULL;
424 if ( datap == NULL ) {
425 res = stat( path, &st );
428 fd = open( path, O_RDONLY );
430 if ( fstat( fd, &st ) == 0 ) {
431 if ( st.st_size > INT_MAX - 2 ) {
434 len = st.st_size + 1; /* +1 detects file size > st.st_size */
435 *datap = data = ptr = SLAP_MALLOC( len + 1 );
437 while ( len && (res = read( fd, ptr, len )) ) {
441 } else if ( errno != EINTR ) {
449 if ( close( fd ) < 0 )
456 msg = "entry file exists";
458 msg = "read entry file";
460 ptr = strstr( data, "\n# CRC32" );
462 msg = "read entry file without checksum";
464 unsigned int crc1 = 0, crc2 = 1;
465 if ( sscanf( ptr + 9, "%08x", &crc1) == 1) {
466 ptr = strchr(ptr+1, '\n');
470 crc2 = crc32( ptr, len );
473 if ( crc1 != crc2 ) {
474 Debug( LDAP_DEBUG_ANY, "ldif_read_file: checksum error on \"%s\"\n",
480 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n", msg, path, 0 );
481 #endif /* LDAP_DEBUG */
483 if ( res < 0 && errno == ENOENT ) {
484 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
485 "no entry file \"%s\"\n", path, 0, 0 );
486 rc = LDAP_NO_SUCH_OBJECT;
488 msg = res < 0 ? STRERROR( errno ) : "bad stat() size";
489 Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
500 * return nonnegative for success or -1 for error
501 * do not return numbers less than -1
504 spew_file( int fd, const char *spew, int len, int *save_errno )
507 #define HEADER "# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n"
508 char header[sizeof(HEADER "# CRC32 12345678\n")];
510 sprintf(header, HEADER "# CRC32 %08x\n", crc32(spew, len));
511 writeres = write_data(fd, header, sizeof(header)-1, save_errno);
512 return writeres < 0 ? writeres : write_data(fd, spew, len, save_errno);
516 write_data( int fd, const char *spew, int len, int *save_errno )
520 writeres = write(fd, spew, len);
523 if (*save_errno != EINTR)
534 /* Write an entry LDIF file. Create parentdir first if non-NULL. */
539 const struct berval *path,
540 const char *parentdir,
543 int rc = LDAP_OTHER, res, save_errno = 0;
544 int fd, entry_length;
545 char *entry_as_string, *tmpfname;
548 return SLAPD_ABANDON;
550 if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
552 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
553 "cannot create parent directory",
554 parentdir, STRERROR( save_errno ) );
555 *text = "internal error (cannot create parent directory)";
559 tmpfname = ldif_tempname( path );
560 fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
563 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
564 "cannot create file", e->e_dn, STRERROR( save_errno ) );
565 *text = "internal error (cannot create file)";
568 ber_len_t dn_len = e->e_name.bv_len;
571 /* Only save the RDN onto disk */
572 dnRdn( &e->e_name, &rdn );
573 if ( rdn.bv_len != dn_len ) {
574 e->e_name.bv_val[rdn.bv_len] = '\0';
575 e->e_name.bv_len = rdn.bv_len;
579 ldap_pvt_thread_mutex_lock( &entry2str_mutex );
580 entry_as_string = entry2str( e, &entry_length );
581 if ( entry_as_string != NULL )
582 res = spew_file( fd, entry_as_string, entry_length, &save_errno );
583 ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
585 /* Restore full DN */
586 if ( rdn.bv_len != dn_len ) {
587 e->e_name.bv_val[rdn.bv_len] = ',';
588 e->e_name.bv_len = dn_len;
591 if ( close( fd ) < 0 && res >= 0 ) {
597 if ( move_file( tmpfname, path->bv_val ) == 0 ) {
598 Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
599 "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 );
603 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
604 "could not put entry file for \"%s\" in place: %s\n",
605 e->e_name.bv_val, STRERROR( save_errno ), 0 );
606 *text = "internal error (could not put entry file in place)";
608 } else if ( res == -1 ) {
609 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
610 "write error to", tmpfname, STRERROR( save_errno ) );
611 *text = "internal error (write error to entry file)";
614 if ( rc != LDAP_SUCCESS ) {
620 SLAP_FREE( tmpfname );
625 * Read the entry at path, or if entryp==NULL just see if it exists.
626 * pdn and pndn are the parent's DN and normalized DN, or both NULL.
627 * Return an LDAP result code.
640 char *entry_as_string;
643 /* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
644 * If so we need not check for LDAP_REQ_BIND here.
646 if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND )
647 return SLAPD_ABANDON;
649 rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
653 if ( entryp == NULL )
655 *entryp = entry = str2entry( entry_as_string );
656 SLAP_FREE( entry_as_string );
657 if ( entry == NULL ) {
660 *text = "internal error (cannot parse some entry file)";
663 if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
665 /* Append parent DN to DN from LDIF file */
667 build_new_dn( &entry->e_name, pdn, &rdn, NULL );
668 SLAP_FREE( rdn.bv_val );
669 rdn = entry->e_nname;
670 build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
671 SLAP_FREE( rdn.bv_val );
677 ? "internal error (cannot read some entry file)"
678 : "internal error (cannot stat some entry file)";
686 * Read the operation's entry, or if entryp==NULL just see if it exists.
687 * Return an LDAP result code. May set *text to a message on failure.
688 * If pathp is non-NULL, set it to the entry filename on success.
694 struct berval *pathp,
698 struct berval path, pdn, pndn;
700 dnParent( &op->o_req_dn, &pdn );
701 dnParent( &op->o_req_ndn, &pndn );
702 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
703 if ( rc != LDAP_SUCCESS ) {
707 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
709 if ( rc == LDAP_SUCCESS && pathp != NULL ) {
712 SLAP_FREE( path.bv_val );
720 * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
721 * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
722 * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
723 * Does not sort escaped chars correctly, would need to un-escape them.
725 typedef struct bvlist {
727 char *trunc; /* filename was truncated here */
728 int inum; /* num from "attr={num}" in filename, or INT_MIN */
729 char savech; /* original char at *trunc */
730 /* BVL_NAME(&bvlist) is the filename, allocated after the struct: */
731 # define BVL_NAME(bvl) ((char *) ((bvl) + 1))
732 # define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1)
736 ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
738 int rc = LDAP_SUCCESS;
740 if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
742 /* Save the entry for tool mode */
743 struct ldif_tool *tl =
744 &((struct ldif_info *) op->o_bd->be_private)->li_tool;
746 if ( tl->ecount >= tl->elen ) {
747 /* Allocate/grow entries */
748 ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
749 Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
750 sizeof(Entry *) * elen );
751 if ( entries == NULL ) {
752 Debug( LDAP_DEBUG_ANY,
753 "ldif_send_entry: out of memory\n", 0, 0, 0 );
758 tl->entries = entries;
760 tl->entries[tl->ecount++] = e;
764 else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
765 /* Send a continuation reference.
766 * (ldif_back_referrals() handles baseobject referrals.)
767 * Don't check the filter since it's only a candidate.
769 BerVarray refs = get_entry_referrals( op, e );
770 rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
772 rc = send_search_reference( op, rs );
773 ber_bvarray_free( rs->sr_ref );
774 ber_bvarray_free( refs );
779 else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
781 rs->sr_attrs = op->ors_attrs;
782 /* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
783 * but refraining lets us test unFREEable MODIFIABLE
784 * entries. Like entries built on the stack.
786 rs->sr_flags = REP_ENTRY_MODIFIABLE;
787 rc = send_search_entry( op, rs );
798 /* Read LDIF directory <path> into <listp>. Set *fname_maxlenp. */
803 const struct berval *path,
805 ber_len_t *fname_maxlenp )
807 int rc = LDAP_SUCCESS;
813 dir_of_path = opendir( path->bv_val );
814 if ( dir_of_path == NULL ) {
815 int save_errno = errno;
816 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
817 int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
819 /* Absent directory is OK (leaf entry), except the database dir */
820 if ( is_rootDSE || save_errno != ENOENT ) {
821 Debug( LDAP_DEBUG_ANY,
822 "=> ldif_search_entry: failed to opendir \"%s\": %s\n",
823 path->bv_val, STRERROR( save_errno ), 0 );
827 save_errno != ENOENT ? "internal error (bad directory)"
828 : "internal error (database directory does not exist)";
836 while ( (dir = readdir( dir_of_path )) != NULL ) {
839 char *trunc, *idxp, *endp, *endp2;
841 fname_len = strlen( dir->d_name );
842 if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
844 if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
847 if ( *fname_maxlenp < fname_len )
848 *fname_maxlenp = fname_len;
850 bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
856 strcpy( BVL_NAME( bvl ), dir->d_name );
858 /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
859 trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
860 if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
861 (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
862 (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
864 /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
865 bvl->inum = strtol( idxp, &endp2, 10 );
866 if ( endp2 == endp ) {
874 bvl->savech = *trunc;
878 for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
879 int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
880 if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
887 if ( closedir( dir_of_path ) < 0 ) {
891 rs->sr_text = "internal error (bad directory)";
893 if ( rc != LDAP_SUCCESS ) {
894 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
895 "error reading directory", path->bv_val,
896 STRERROR( save_errno ) );
904 * Send an entry, recursively search its children, and free or save it.
905 * Return an LDAP result code. Parameters:
906 * op, rs operation and reply. rs == NULL for slap tools.
907 * e entry to search, or NULL for rootDSE.
908 * scope scope for the part of the search from this entry.
909 * path LDIF filename -- bv_len and non-directory part are overwritten.
917 struct berval *path )
919 int rc = LDAP_SUCCESS;
920 struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
922 if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
923 /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
924 * which bconfig.c seems to need. (TODO: see config_rename_one.)
926 if ( ber_dupbv( &dn, &e->e_name ) == NULL ||
927 ber_dupbv( &ndn, &e->e_nname ) == NULL )
929 Debug( LDAP_DEBUG_ANY,
930 "ldif_search_entry: out of memory\n", 0, 0, 0 );
936 /* Send the entry if appropriate, and free or save it */
938 rc = ldif_send_entry( op, rs, e, scope );
940 /* Search the children */
941 if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
943 struct berval fpath; /* becomes child pathname */
944 char *dir_end; /* will point past dirname in fpath */
946 ldif2dir_len( *path );
947 ldif2dir_name( *path );
948 rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
950 if ( list != NULL ) {
951 const char **text = rs == NULL ? NULL : &rs->sr_text;
953 if ( scope == LDAP_SCOPE_ONELEVEL )
954 scope = LDAP_SCOPE_BASE;
955 else if ( scope == LDAP_SCOPE_SUBORDINATE )
956 scope = LDAP_SCOPE_SUBTREE;
958 /* Allocate fpath and fill in directory part */
959 dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
960 if ( dir_end == NULL )
966 if ( rc == LDAP_SUCCESS ) {
967 *ptr->trunc = ptr->savech;
968 FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
970 rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
974 rc = ldif_search_entry( op, rs, e, scope, &fpath );
976 case LDAP_NO_SUCH_OBJECT:
977 /* Only the search baseDN may produce noSuchObject. */
980 rs->sr_text = "internal error "
981 "(did someone just remove an entry file?)";
982 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
983 "file listed in parent directory does not exist: "
984 "\"%s\"\n", fpath.bv_val, 0, 0 );
991 } while ( list != NULL );
993 if ( !BER_BVISNULL( &fpath ) )
994 SLAP_FREE( fpath.bv_val );
999 if ( !BER_BVISEMPTY( &dn ) )
1000 ber_memfree( dn.bv_val );
1001 if ( !BER_BVISEMPTY( &ndn ) )
1002 ber_memfree( ndn.bv_val );
1007 search_tree( Operation *op, SlapReply *rs )
1009 int rc = LDAP_SUCCESS;
1012 struct berval pdn, pndn;
1014 (void) ndn2path( op, &op->o_req_ndn, &path, 1 );
1015 if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
1016 /* Read baseObject */
1017 dnParent( &op->o_req_dn, &pdn );
1018 dnParent( &op->o_req_ndn, &pndn );
1019 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
1020 rs == NULL ? NULL : &rs->sr_text );
1022 if ( rc == LDAP_SUCCESS )
1023 rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
1025 ch_free( path.bv_val );
1031 * Prepare to create or rename an entry:
1032 * Check that the entry does not already exist.
1033 * Check that the parent entry exists and can have subordinates,
1034 * unless need_dir is NULL or adding the suffix entry.
1036 * Return an LDAP result code. May set *text to a message on failure.
1037 * If success, set *dnpath to LDIF entry path and *need_dir to
1038 * (directory must be created ? dirname : NULL).
1041 ldif_prepare_create(
1044 struct berval *dnpath,
1048 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1049 struct berval *ndn = &e->e_nname;
1050 struct berval ppath = BER_BVNULL;
1052 Entry *parent = NULL;
1055 if ( op->o_abandon )
1056 return SLAPD_ABANDON;
1058 rc = ndn2path( op, ndn, dnpath, 0 );
1059 if ( rc != LDAP_SUCCESS ) {
1063 if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
1064 rc = LDAP_ALREADY_EXISTS;
1066 } else if ( errno != ENOENT ) {
1067 Debug( LDAP_DEBUG_ANY,
1068 "ldif_prepare_create: cannot stat \"%s\": %s\n",
1069 dnpath->bv_val, STRERROR( errno ), 0 );
1071 *text = "internal error (cannot check entry file)";
1073 } else if ( need_dir != NULL ) {
1075 rc = get_parent_path( dnpath, &ppath );
1076 /* If parent dir exists, so does parent .ldif:
1077 * The directory gets created after and removed before the .ldif.
1078 * Except with the database directory, which has no matching entry.
1080 if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
1081 rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
1082 ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
1085 case LDAP_NO_SUCH_OBJECT:
1086 /* No parent dir, check parent .ldif */
1087 dir2ldif_name( ppath );
1088 rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
1089 (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
1094 /* Check that parent is not a referral, unless
1095 * ldif_back_referrals() already checked.
1097 if ( parent != NULL ) {
1098 int is_ref = is_entry_referral( parent );
1099 entry_free( parent );
1101 rc = LDAP_AFFECTS_MULTIPLE_DSAS;
1102 *text = op->o_tag == LDAP_REQ_MODDN
1103 ? "newSuperior is a referral object"
1104 : "parent is a referral object";
1108 /* Must create parent directory. */
1109 ldif2dir_name( ppath );
1110 *need_dir = ppath.bv_val;
1112 case LDAP_NO_SUCH_OBJECT:
1113 *text = op->o_tag == LDAP_REQ_MODDN
1114 ? "newSuperior object does not exist"
1115 : "parent does not exist";
1120 Debug( LDAP_DEBUG_ANY,
1121 "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
1122 ndn->bv_val, STRERROR( errno ), 0 );
1123 *text = "internal error (cannot stat parent dir)";
1126 if ( *need_dir == NULL && ppath.bv_val != NULL )
1127 SLAP_FREE( ppath.bv_val );
1130 if ( rc != LDAP_SUCCESS ) {
1131 SLAP_FREE( dnpath->bv_val );
1132 BER_BVZERO( dnpath );
1138 apply_modify_to_entry(
1140 Modifications *modlist,
1145 int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
1149 if (!acl_check_modlist(op, entry, modlist)) {
1150 return LDAP_INSUFFICIENT_ACCESS;
1153 for (; modlist != NULL; modlist = modlist->sml_next) {
1154 mods = &modlist->sml_mod;
1156 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
1159 switch (mods->sm_op) {
1161 rc = modify_add_values(entry, mods,
1162 get_permissiveModify(op),
1163 &rs->sr_text, textbuf,
1167 case LDAP_MOD_DELETE:
1168 rc = modify_delete_values(entry, mods,
1169 get_permissiveModify(op),
1170 &rs->sr_text, textbuf,
1174 case LDAP_MOD_REPLACE:
1175 rc = modify_replace_values(entry, mods,
1176 get_permissiveModify(op),
1177 &rs->sr_text, textbuf,
1181 case LDAP_MOD_INCREMENT:
1182 rc = modify_increment_values( entry,
1183 mods, get_permissiveModify(op),
1184 &rs->sr_text, textbuf,
1188 case SLAP_MOD_SOFTADD:
1189 mods->sm_op = LDAP_MOD_ADD;
1190 rc = modify_add_values(entry, mods,
1191 get_permissiveModify(op),
1192 &rs->sr_text, textbuf,
1194 mods->sm_op = SLAP_MOD_SOFTADD;
1195 if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
1200 case SLAP_MOD_SOFTDEL:
1201 mods->sm_op = LDAP_MOD_DELETE;
1202 rc = modify_delete_values(entry, mods,
1203 get_permissiveModify(op),
1204 &rs->sr_text, textbuf,
1206 mods->sm_op = SLAP_MOD_SOFTDEL;
1207 if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
1212 case SLAP_MOD_ADD_IF_NOT_PRESENT:
1213 if ( attr_find( entry->e_attrs, mods->sm_desc ) ) {
1217 mods->sm_op = LDAP_MOD_ADD;
1218 rc = modify_add_values(entry, mods,
1219 get_permissiveModify(op),
1220 &rs->sr_text, textbuf,
1222 mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
1225 if(rc != LDAP_SUCCESS) break;
1228 if ( rc == LDAP_SUCCESS ) {
1229 rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
1231 entry->e_ocflags = 0;
1233 /* check that the entry still obeys the schema */
1234 rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
1235 &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN );
1243 ldif_back_referrals( Operation *op, SlapReply *rs )
1245 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1246 struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn;
1247 ber_len_t min_dnlen;
1248 Entry *entry = NULL, **entryp;
1252 min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
1253 if ( min_dnlen == 0 ) {
1254 /* Catch root DSE (empty DN), it is not a referral */
1257 if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) {
1258 return LDAP_SUCCESS; /* Root DSE again */
1261 entryp = get_manageDSAit( op ) ? NULL : &entry;
1262 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1265 dnParent( &dn, &dn );
1266 dnParent( &ndn, &ndn );
1267 rc = ldif_read_entry( op, path.bv_val, &dn, &ndn,
1268 entryp, &rs->sr_text );
1269 if ( rc != LDAP_NO_SUCH_OBJECT )
1273 if ( ndn.bv_len < min_dnlen )
1275 (void) get_parent_path( &path, NULL );
1276 dir2ldif_name( path );
1280 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1281 SLAP_FREE( path.bv_val );
1283 if ( entry != NULL ) {
1284 if ( is_entry_referral( entry ) ) {
1285 Debug( LDAP_DEBUG_TRACE,
1286 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
1287 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn );
1289 ref = get_entry_referrals( op, entry );
1290 rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn,
1291 op->o_tag == LDAP_REQ_SEARCH ?
1292 op->ors_scope : LDAP_SCOPE_DEFAULT );
1293 ber_bvarray_free( ref );
1295 if ( rs->sr_ref != NULL ) {
1297 rc = rs->sr_err = LDAP_REFERRAL;
1298 rs->sr_matched = entry->e_dn;
1299 send_ldap_result( op, rs );
1300 ber_bvarray_free( rs->sr_ref );
1304 rs->sr_text = "bad referral object";
1306 rs->sr_matched = NULL;
1309 entry_free( entry );
1316 /* LDAP operations */
1319 ldif_back_bind( Operation *op, SlapReply *rs )
1321 struct ldif_info *li;
1323 AttributeDescription *password = slap_schema.si_ad_userPassword;
1325 Entry *entry = NULL;
1327 switch ( be_rootdn_bind( op, rs ) ) {
1328 case SLAP_CB_CONTINUE:
1332 /* in case of success, front end will send result;
1333 * otherwise, be_rootdn_bind() did */
1337 li = (struct ldif_info *) op->o_bd->be_private;
1338 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1339 return_val = get_entry(op, &entry, NULL, NULL);
1341 /* no object is found for them */
1342 if(return_val != LDAP_SUCCESS) {
1343 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
1347 /* they don't have userpassword */
1348 if((a = attr_find(entry->e_attrs, password)) == NULL) {
1349 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1354 /* authentication actually failed */
1355 if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
1356 &rs->sr_text) != 0) {
1357 rs->sr_err = LDAP_INVALID_CREDENTIALS;
1362 /* let the front-end send success */
1363 return_val = LDAP_SUCCESS;
1366 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1367 if(return_val != LDAP_SUCCESS)
1368 send_ldap_result( op, rs );
1375 ldif_back_search( Operation *op, SlapReply *rs )
1377 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1379 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1380 rs->sr_err = search_tree( op, rs );
1381 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1382 send_ldap_result(op, rs);
1388 ldif_back_add( Operation *op, SlapReply *rs )
1390 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1391 Entry * e = op->ora_e;
1394 char textbuf[SLAP_TEXT_BUFLEN];
1397 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
1399 rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
1400 &rs->sr_text, textbuf, sizeof( textbuf ) );
1401 if ( rc != LDAP_SUCCESS )
1404 rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
1405 if ( rc != LDAP_SUCCESS )
1408 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1410 rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
1411 if ( rc == LDAP_SUCCESS ) {
1412 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1413 rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
1414 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1416 SLAP_FREE( path.bv_val );
1417 if ( parentdir != NULL )
1418 SLAP_FREE( parentdir );
1421 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1425 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
1426 rc, rs->sr_text ? rs->sr_text : "", 0 );
1427 send_ldap_result( op, rs );
1428 slap_graduate_commit_csn( op );
1429 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1434 ldif_back_modify( Operation *op, SlapReply *rs )
1436 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1437 Modifications * modlst = op->orm_modlist;
1440 char textbuf[SLAP_TEXT_BUFLEN];
1443 slap_mods_opattrs( op, &op->orm_modlist, 1 );
1445 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1447 rc = get_entry( op, &entry, &path, &rs->sr_text );
1448 if ( rc == LDAP_SUCCESS ) {
1449 rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
1450 if ( rc == LDAP_SUCCESS ) {
1451 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1452 rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
1453 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1456 entry_free( entry );
1457 SLAP_FREE( path.bv_val );
1460 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1463 send_ldap_result( op, rs );
1464 slap_graduate_commit_csn( op );
1465 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1470 ldif_back_delete( Operation *op, SlapReply *rs )
1472 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1474 int rc = LDAP_SUCCESS;
1476 if ( BER_BVISEMPTY( &op->o_csn )) {
1478 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
1480 csn.bv_val = csnbuf;
1481 csn.bv_len = sizeof( csnbuf );
1482 slap_get_csn( op, &csn, 1 );
1485 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1486 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1487 if ( op->o_abandon ) {
1492 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
1493 if ( rc != LDAP_SUCCESS ) {
1497 ldif2dir_len( path );
1498 ldif2dir_name( path );
1499 if ( rmdir( path.bv_val ) < 0 ) {
1502 rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1505 /* is leaf, go on */
1509 rs->sr_text = "internal error (cannot delete subtree directory)";
1514 if ( rc == LDAP_SUCCESS ) {
1515 dir2ldif_name( path );
1516 if ( unlink( path.bv_val ) < 0 ) {
1517 rc = LDAP_NO_SUCH_OBJECT;
1518 if ( errno != ENOENT ) {
1520 rs->sr_text = "internal error (cannot delete entry file)";
1525 if ( rc == LDAP_OTHER ) {
1526 Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
1527 "cannot delete", path.bv_val, STRERROR( errno ) );
1530 SLAP_FREE( path.bv_val );
1532 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1533 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1535 send_ldap_result( op, rs );
1536 slap_graduate_commit_csn( op );
1546 struct berval *oldpath,
1549 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1550 struct berval newpath;
1551 char *parentdir = NULL, *trash;
1558 rc = ldif_prepare_create( op, entry, &newpath,
1559 op->orr_newSup ? &parentdir : NULL, text );
1562 if ( rc == LDAP_SUCCESS ) {
1563 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1565 rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
1566 if ( rc == LDAP_SUCCESS && !same_ndn ) {
1567 trash = oldpath->bv_val; /* will be .ldif file to delete */
1568 ldif2dir_len( newpath );
1569 ldif2dir_len( *oldpath );
1570 /* Move subdir before deleting old entry,
1571 * so .ldif always exists if subdir does.
1573 ldif2dir_name( newpath );
1574 ldif2dir_name( *oldpath );
1575 rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
1576 if ( rename_res != 0 && errno != ENOENT ) {
1578 *text = "internal error (cannot move this subtree)";
1579 trash = newpath.bv_val;
1582 /* Delete old entry, or if error undo change */
1584 dir2ldif_name( newpath );
1585 dir2ldif_name( *oldpath );
1586 if ( unlink( trash ) == 0 )
1588 if ( rc == LDAP_SUCCESS ) {
1589 /* Prepare to undo change and return failure */
1591 *text = "internal error (cannot move this entry)";
1592 trash = newpath.bv_val;
1593 if ( rename_res != 0 )
1595 /* First move subdirectory back */
1596 ldif2dir_name( newpath );
1597 ldif2dir_name( *oldpath );
1598 if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
1601 *text = "added new but couldn't delete old entry!";
1605 if ( rc != LDAP_SUCCESS ) {
1607 snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
1608 Debug( LDAP_DEBUG_ANY,
1609 "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
1610 s, op->o_req_dn.bv_val, entry->e_dn );
1614 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1616 SLAP_FREE( newpath.bv_val );
1617 if ( parentdir != NULL )
1618 SLAP_FREE( parentdir );
1625 ldif_back_modrdn( Operation *op, SlapReply *rs )
1627 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1628 struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1629 struct berval p_dn, old_path;
1631 char textbuf[SLAP_TEXT_BUFLEN];
1634 slap_mods_opattrs( op, &op->orr_modlist, 1 );
1636 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1638 rc = get_entry( op, &entry, &old_path, &rs->sr_text );
1639 if ( rc == LDAP_SUCCESS ) {
1640 /* build new dn, and new ndn for the entry */
1641 if ( op->oq_modrdn.rs_newSup != NULL ) {
1642 p_dn = *op->oq_modrdn.rs_newSup;
1644 dnParent( &entry->e_name, &p_dn );
1646 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
1647 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1648 same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
1649 ber_memfree_x( entry->e_name.bv_val, NULL );
1650 ber_memfree_x( entry->e_nname.bv_val, NULL );
1651 entry->e_name = new_dn;
1652 entry->e_nname = new_ndn;
1654 /* perform the modifications */
1655 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
1656 if ( rc == LDAP_SUCCESS )
1657 rc = ldif_move_entry( op, entry, same_ndn, &old_path,
1660 entry_free( entry );
1661 SLAP_FREE( old_path.bv_val );
1664 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1666 send_ldap_result( op, rs );
1667 slap_graduate_commit_csn( op );
1668 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1673 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1675 ldif_back_entry_get(
1679 AttributeDescription *at,
1683 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1684 struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1687 assert( ndn != NULL );
1688 assert( !BER_BVISNULL( ndn ) );
1690 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1691 op->o_req_dn = *ndn;
1692 op->o_req_ndn = *ndn;
1693 rc = get_entry( op, e, NULL, NULL );
1694 op->o_req_dn = op_dn;
1695 op->o_req_ndn = op_ndn;
1696 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1698 if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1699 rc = LDAP_NO_SUCH_ATTRIBUTE;
1711 ldif_tool_entry_open( BackendDB *be, int mode )
1713 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1720 ldif_tool_entry_close( BackendDB *be )
1722 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1723 Entry **entries = tl->entries;
1726 for ( i = tl->ecount; i--; )
1728 entry_free( entries[i] );
1729 SLAP_FREE( entries );
1731 tl->ecount = tl->elen = 0;
1736 ldif_tool_entry_next( BackendDB *be )
1738 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1741 Entry *e = tl->entries[ tl->ecurrent ];
1743 if ( tl->ecurrent >= tl->ecount ) {
1749 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1753 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter ) != LDAP_COMPARE_TRUE ) {
1760 return tl->ecurrent;
1764 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1766 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1769 tl->tl_scope = scope;
1772 if ( tl->entries == NULL ) {
1776 op.o_req_dn = *be->be_suffix;
1777 op.o_req_ndn = *be->be_nsuffix;
1778 op.ors_scope = LDAP_SCOPE_SUBTREE;
1779 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1780 tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1781 return NOID; /* fail ldif_tool_entry_get() */
1784 return ldif_tool_entry_next( be );
1788 ldif_tool_entry_get( BackendDB *be, ID id )
1790 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1794 if ( id < tl->ecount ) {
1795 e = tl->entries[id];
1796 tl->entries[id] = NULL;
1802 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1805 const char *errmsg = NULL;
1811 rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1812 if ( rc == LDAP_SUCCESS ) {
1813 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1815 SLAP_FREE( path.bv_val );
1816 if ( parentdir != NULL )
1817 SLAP_FREE( parentdir );
1818 if ( rc == LDAP_SUCCESS )
1822 if ( errmsg == NULL && rc != LDAP_OTHER )
1823 errmsg = ldap_err2string( rc );
1824 if ( errmsg != NULL )
1825 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1833 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1835 struct ldif_info *li;
1837 li = ch_calloc( 1, sizeof(struct ldif_info) );
1838 be->be_private = li;
1839 be->be_cf_ocs = ldifocs;
1840 ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1841 ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1842 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1847 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1849 struct ldif_info *li = be->be_private;
1851 ch_free( li->li_base_path.bv_val );
1852 ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1853 ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1854 free( be->be_private );
1859 ldif_back_db_open( Backend *be, ConfigReply *cr )
1861 struct ldif_info *li = (struct ldif_info *) be->be_private;
1862 if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1863 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1870 ldif_back_initialize( BackendInfo *bi )
1872 static char *controls[] = {
1873 LDAP_CONTROL_MANAGEDSAIT,
1879 SLAP_BFLAG_INCREMENT |
1880 SLAP_BFLAG_REFERRALS;
1882 bi->bi_controls = controls;
1889 bi->bi_db_init = ldif_back_db_init;
1890 bi->bi_db_config = config_generic_wrapper;
1891 bi->bi_db_open = ldif_back_db_open;
1892 bi->bi_db_close = 0;
1893 bi->bi_db_destroy = ldif_back_db_destroy;
1895 bi->bi_op_bind = ldif_back_bind;
1896 bi->bi_op_unbind = 0;
1897 bi->bi_op_search = ldif_back_search;
1898 bi->bi_op_compare = 0;
1899 bi->bi_op_modify = ldif_back_modify;
1900 bi->bi_op_modrdn = ldif_back_modrdn;
1901 bi->bi_op_add = ldif_back_add;
1902 bi->bi_op_delete = ldif_back_delete;
1903 bi->bi_op_abandon = 0;
1905 bi->bi_extended = 0;
1907 bi->bi_chk_referrals = ldif_back_referrals;
1909 bi->bi_connection_init = 0;
1910 bi->bi_connection_destroy = 0;
1912 bi->bi_entry_get_rw = ldif_back_entry_get;
1914 #if 0 /* NOTE: uncomment to completely disable access control */
1915 bi->bi_access_allowed = slap_access_always_allowed;
1918 bi->bi_tool_entry_open = ldif_tool_entry_open;
1919 bi->bi_tool_entry_close = ldif_tool_entry_close;
1920 bi->bi_tool_entry_first = backend_tool_entry_first;
1921 bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
1922 bi->bi_tool_entry_next = ldif_tool_entry_next;
1923 bi->bi_tool_entry_get = ldif_tool_entry_get;
1924 bi->bi_tool_entry_put = ldif_tool_entry_put;
1925 bi->bi_tool_entry_reindex = 0;
1926 bi->bi_tool_sync = 0;
1928 bi->bi_tool_dn2id_get = 0;
1929 bi->bi_tool_entry_modify = 0;
1931 bi->bi_cf_ocs = ldifocs;
1933 rc = config_register_schema( ldifcfg, ldifocs );
1934 if ( rc ) return rc;