1 /* ldif.c - the ldif backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2013 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;
409 return crc ^ 0xffffffff;
413 * Read a file, or stat() it if datap == NULL. Allocate and fill *datap.
414 * Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error.
417 ldif_read_file( const char *path, char **datap )
419 int rc = LDAP_SUCCESS, fd, len;
420 int res = -1; /* 0:success, <0:error, >0:file too big/growing. */
422 char *data = NULL, *ptr = NULL;
425 if ( datap == NULL ) {
426 res = stat( path, &st );
429 fd = open( path, O_RDONLY );
431 if ( fstat( fd, &st ) == 0 ) {
432 if ( st.st_size > INT_MAX - 2 ) {
435 len = st.st_size + 1; /* +1 detects file size > st.st_size */
436 *datap = data = ptr = SLAP_MALLOC( len + 1 );
438 while ( len && (res = read( fd, ptr, len )) ) {
442 } else if ( errno != EINTR ) {
450 if ( close( fd ) < 0 )
457 msg = "entry file exists";
459 msg = "read entry file";
461 ptr = strstr( data, "\n# CRC32" );
463 msg = "read entry file without checksum";
465 unsigned int crc1 = 0, crc2 = 1;
466 if ( sscanf( ptr + 9, "%08x", &crc1) == 1) {
467 ptr = strchr(ptr+1, '\n');
471 crc2 = crc32( ptr, len );
474 if ( crc1 != crc2 ) {
475 Debug( LDAP_DEBUG_ANY, "ldif_read_file: checksum error on \"%s\"\n",
481 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n", msg, path, 0 );
482 #endif /* LDAP_DEBUG */
484 if ( res < 0 && errno == ENOENT ) {
485 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
486 "no entry file \"%s\"\n", path, 0, 0 );
487 rc = LDAP_NO_SUCH_OBJECT;
489 msg = res < 0 ? STRERROR( errno ) : "bad stat() size";
490 Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
501 * return nonnegative for success or -1 for error
502 * do not return numbers less than -1
505 spew_file( int fd, const char *spew, int len, int *save_errno )
508 #define HEADER "# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n"
509 char header[sizeof(HEADER "# CRC32 12345678\n")];
511 sprintf(header, HEADER "# CRC32 %08x\n", crc32(spew, len));
512 writeres = write_data(fd, header, sizeof(header)-1, save_errno);
513 return writeres < 0 ? writeres : write_data(fd, spew, len, save_errno);
517 write_data( int fd, const char *spew, int len, int *save_errno )
521 writeres = write(fd, spew, len);
524 if (*save_errno != EINTR)
535 /* Write an entry LDIF file. Create parentdir first if non-NULL. */
540 const struct berval *path,
541 const char *parentdir,
544 int rc = LDAP_OTHER, res, save_errno = 0;
545 int fd, entry_length;
546 char *entry_as_string, *tmpfname;
549 return SLAPD_ABANDON;
551 if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
553 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
554 "cannot create parent directory",
555 parentdir, STRERROR( save_errno ) );
556 *text = "internal error (cannot create parent directory)";
560 tmpfname = ldif_tempname( path );
561 fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
564 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
565 "cannot create file", e->e_dn, STRERROR( save_errno ) );
566 *text = "internal error (cannot create file)";
569 ber_len_t dn_len = e->e_name.bv_len;
572 /* Only save the RDN onto disk */
573 dnRdn( &e->e_name, &rdn );
574 if ( rdn.bv_len != dn_len ) {
575 e->e_name.bv_val[rdn.bv_len] = '\0';
576 e->e_name.bv_len = rdn.bv_len;
580 ldap_pvt_thread_mutex_lock( &entry2str_mutex );
581 entry_as_string = entry2str( e, &entry_length );
582 if ( entry_as_string != NULL )
583 res = spew_file( fd, entry_as_string, entry_length, &save_errno );
584 ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
586 /* Restore full DN */
587 if ( rdn.bv_len != dn_len ) {
588 e->e_name.bv_val[rdn.bv_len] = ',';
589 e->e_name.bv_len = dn_len;
592 if ( close( fd ) < 0 && res >= 0 ) {
598 if ( move_file( tmpfname, path->bv_val ) == 0 ) {
599 Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
600 "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 );
604 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
605 "could not put entry file for \"%s\" in place: %s\n",
606 e->e_name.bv_val, STRERROR( save_errno ), 0 );
607 *text = "internal error (could not put entry file in place)";
609 } else if ( res == -1 ) {
610 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
611 "write error to", tmpfname, STRERROR( save_errno ) );
612 *text = "internal error (write error to entry file)";
615 if ( rc != LDAP_SUCCESS ) {
621 SLAP_FREE( tmpfname );
626 * Read the entry at path, or if entryp==NULL just see if it exists.
627 * pdn and pndn are the parent's DN and normalized DN, or both NULL.
628 * Return an LDAP result code.
641 char *entry_as_string;
644 /* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
645 * If so we need not check for LDAP_REQ_BIND here.
647 if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND )
648 return SLAPD_ABANDON;
650 rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
654 if ( entryp == NULL )
656 *entryp = entry = str2entry( entry_as_string );
657 SLAP_FREE( entry_as_string );
658 if ( entry == NULL ) {
661 *text = "internal error (cannot parse some entry file)";
664 if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
666 /* Append parent DN to DN from LDIF file */
668 build_new_dn( &entry->e_name, pdn, &rdn, NULL );
669 SLAP_FREE( rdn.bv_val );
670 rdn = entry->e_nname;
671 build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
672 SLAP_FREE( rdn.bv_val );
678 ? "internal error (cannot read some entry file)"
679 : "internal error (cannot stat some entry file)";
687 * Read the operation's entry, or if entryp==NULL just see if it exists.
688 * Return an LDAP result code. May set *text to a message on failure.
689 * If pathp is non-NULL, set it to the entry filename on success.
695 struct berval *pathp,
699 struct berval path, pdn, pndn;
701 dnParent( &op->o_req_dn, &pdn );
702 dnParent( &op->o_req_ndn, &pndn );
703 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
704 if ( rc != LDAP_SUCCESS ) {
708 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
710 if ( rc == LDAP_SUCCESS && pathp != NULL ) {
713 SLAP_FREE( path.bv_val );
721 * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
722 * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
723 * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
724 * Does not sort escaped chars correctly, would need to un-escape them.
726 typedef struct bvlist {
728 char *trunc; /* filename was truncated here */
729 int inum; /* num from "attr={num}" in filename, or INT_MIN */
730 char savech; /* original char at *trunc */
731 /* BVL_NAME(&bvlist) is the filename, allocated after the struct: */
732 # define BVL_NAME(bvl) ((char *) ((bvl) + 1))
733 # define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1)
737 ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
739 int rc = LDAP_SUCCESS;
741 if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
743 /* Save the entry for tool mode */
744 struct ldif_tool *tl =
745 &((struct ldif_info *) op->o_bd->be_private)->li_tool;
747 if ( tl->ecount >= tl->elen ) {
748 /* Allocate/grow entries */
749 ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
750 Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
751 sizeof(Entry *) * elen );
752 if ( entries == NULL ) {
753 Debug( LDAP_DEBUG_ANY,
754 "ldif_send_entry: out of memory\n", 0, 0, 0 );
759 tl->entries = entries;
761 tl->entries[tl->ecount++] = e;
765 else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
766 /* Send a continuation reference.
767 * (ldif_back_referrals() handles baseobject referrals.)
768 * Don't check the filter since it's only a candidate.
770 BerVarray refs = get_entry_referrals( op, e );
771 rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
773 rc = send_search_reference( op, rs );
774 ber_bvarray_free( rs->sr_ref );
775 ber_bvarray_free( refs );
780 else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
782 rs->sr_attrs = op->ors_attrs;
783 /* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
784 * but refraining lets us test unFREEable MODIFIABLE
785 * entries. Like entries built on the stack.
787 rs->sr_flags = REP_ENTRY_MODIFIABLE;
788 rc = send_search_entry( op, rs );
799 /* Read LDIF directory <path> into <listp>. Set *fname_maxlenp. */
804 const struct berval *path,
806 ber_len_t *fname_maxlenp )
808 int rc = LDAP_SUCCESS;
814 dir_of_path = opendir( path->bv_val );
815 if ( dir_of_path == NULL ) {
816 int save_errno = errno;
817 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
818 int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
820 /* Absent directory is OK (leaf entry), except the database dir */
821 if ( is_rootDSE || save_errno != ENOENT ) {
822 Debug( LDAP_DEBUG_ANY,
823 "=> ldif_search_entry: failed to opendir \"%s\": %s\n",
824 path->bv_val, STRERROR( save_errno ), 0 );
828 save_errno != ENOENT ? "internal error (bad directory)"
829 : !is_rootDSE ? "internal error (missing directory)"
830 : "internal error (database directory does not exist)";
838 while ( (dir = readdir( dir_of_path )) != NULL ) {
841 char *trunc, *idxp, *endp, *endp2;
843 fname_len = strlen( dir->d_name );
844 if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
846 if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
849 if ( *fname_maxlenp < fname_len )
850 *fname_maxlenp = fname_len;
852 bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
858 strcpy( BVL_NAME( bvl ), dir->d_name );
860 /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
861 trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
862 if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
863 (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
864 (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
866 /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
867 bvl->inum = strtol( idxp, &endp2, 10 );
868 if ( endp2 == endp ) {
876 bvl->savech = *trunc;
880 for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
881 int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
882 if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
889 if ( closedir( dir_of_path ) < 0 ) {
893 rs->sr_text = "internal error (bad directory)";
895 if ( rc != LDAP_SUCCESS ) {
896 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
897 "error reading directory", path->bv_val,
898 STRERROR( save_errno ) );
906 * Send an entry, recursively search its children, and free or save it.
907 * Return an LDAP result code. Parameters:
908 * op, rs operation and reply. rs == NULL for slap tools.
909 * e entry to search, or NULL for rootDSE.
910 * scope scope for the part of the search from this entry.
911 * path LDIF filename -- bv_len and non-directory part are overwritten.
919 struct berval *path )
921 int rc = LDAP_SUCCESS;
922 struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
924 if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
925 /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
926 * which bconfig.c seems to need. (TODO: see config_rename_one.)
928 if ( ber_dupbv( &dn, &e->e_name ) == NULL ||
929 ber_dupbv( &ndn, &e->e_nname ) == NULL )
931 Debug( LDAP_DEBUG_ANY,
932 "ldif_search_entry: out of memory\n", 0, 0, 0 );
938 /* Send the entry if appropriate, and free or save it */
940 rc = ldif_send_entry( op, rs, e, scope );
942 /* Search the children */
943 if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
945 struct berval fpath; /* becomes child pathname */
946 char *dir_end; /* will point past dirname in fpath */
948 ldif2dir_len( *path );
949 ldif2dir_name( *path );
950 rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
952 if ( list != NULL ) {
953 const char **text = rs == NULL ? NULL : &rs->sr_text;
955 if ( scope == LDAP_SCOPE_ONELEVEL )
956 scope = LDAP_SCOPE_BASE;
957 else if ( scope == LDAP_SCOPE_SUBORDINATE )
958 scope = LDAP_SCOPE_SUBTREE;
960 /* Allocate fpath and fill in directory part */
961 dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
962 if ( dir_end == NULL )
968 if ( rc == LDAP_SUCCESS ) {
969 *ptr->trunc = ptr->savech;
970 FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
972 rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
976 rc = ldif_search_entry( op, rs, e, scope, &fpath );
978 case LDAP_NO_SUCH_OBJECT:
979 /* Only the search baseDN may produce noSuchObject. */
982 rs->sr_text = "internal error "
983 "(did someone just remove an entry file?)";
984 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
985 "file listed in parent directory does not exist: "
986 "\"%s\"\n", fpath.bv_val, 0, 0 );
993 } while ( list != NULL );
995 if ( !BER_BVISNULL( &fpath ) )
996 SLAP_FREE( fpath.bv_val );
1001 if ( !BER_BVISEMPTY( &dn ) )
1002 ber_memfree( dn.bv_val );
1003 if ( !BER_BVISEMPTY( &ndn ) )
1004 ber_memfree( ndn.bv_val );
1009 search_tree( Operation *op, SlapReply *rs )
1011 int rc = LDAP_SUCCESS;
1014 struct berval pdn, pndn;
1016 (void) ndn2path( op, &op->o_req_ndn, &path, 1 );
1017 if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
1018 /* Read baseObject */
1019 dnParent( &op->o_req_dn, &pdn );
1020 dnParent( &op->o_req_ndn, &pndn );
1021 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
1022 rs == NULL ? NULL : &rs->sr_text );
1024 if ( rc == LDAP_SUCCESS )
1025 rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
1027 ch_free( path.bv_val );
1033 * Prepare to create or rename an entry:
1034 * Check that the entry does not already exist.
1035 * Check that the parent entry exists and can have subordinates,
1036 * unless need_dir is NULL or adding the suffix entry.
1038 * Return an LDAP result code. May set *text to a message on failure.
1039 * If success, set *dnpath to LDIF entry path and *need_dir to
1040 * (directory must be created ? dirname : NULL).
1043 ldif_prepare_create(
1046 struct berval *dnpath,
1050 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1051 struct berval *ndn = &e->e_nname;
1052 struct berval ppath = BER_BVNULL;
1054 Entry *parent = NULL;
1057 if ( op->o_abandon )
1058 return SLAPD_ABANDON;
1060 rc = ndn2path( op, ndn, dnpath, 0 );
1061 if ( rc != LDAP_SUCCESS ) {
1065 if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
1066 rc = LDAP_ALREADY_EXISTS;
1068 } else if ( errno != ENOENT ) {
1069 Debug( LDAP_DEBUG_ANY,
1070 "ldif_prepare_create: cannot stat \"%s\": %s\n",
1071 dnpath->bv_val, STRERROR( errno ), 0 );
1073 *text = "internal error (cannot check entry file)";
1075 } else if ( need_dir != NULL ) {
1077 rc = get_parent_path( dnpath, &ppath );
1078 /* If parent dir exists, so does parent .ldif:
1079 * The directory gets created after and removed before the .ldif.
1080 * Except with the database directory, which has no matching entry.
1082 if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
1083 rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
1084 ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
1087 case LDAP_NO_SUCH_OBJECT:
1088 /* No parent dir, check parent .ldif */
1089 dir2ldif_name( ppath );
1090 rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
1091 (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
1096 /* Check that parent is not a referral, unless
1097 * ldif_back_referrals() already checked.
1099 if ( parent != NULL ) {
1100 int is_ref = is_entry_referral( parent );
1101 entry_free( parent );
1103 rc = LDAP_AFFECTS_MULTIPLE_DSAS;
1104 *text = op->o_tag == LDAP_REQ_MODDN
1105 ? "newSuperior is a referral object"
1106 : "parent is a referral object";
1110 /* Must create parent directory. */
1111 ldif2dir_name( ppath );
1112 *need_dir = ppath.bv_val;
1114 case LDAP_NO_SUCH_OBJECT:
1115 *text = op->o_tag == LDAP_REQ_MODDN
1116 ? "newSuperior object does not exist"
1117 : "parent does not exist";
1122 Debug( LDAP_DEBUG_ANY,
1123 "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
1124 ndn->bv_val, STRERROR( errno ), 0 );
1125 *text = "internal error (cannot stat parent dir)";
1128 if ( *need_dir == NULL && ppath.bv_val != NULL )
1129 SLAP_FREE( ppath.bv_val );
1132 if ( rc != LDAP_SUCCESS ) {
1133 SLAP_FREE( dnpath->bv_val );
1134 BER_BVZERO( dnpath );
1140 apply_modify_to_entry(
1142 Modifications *modlist,
1147 int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
1151 if (!acl_check_modlist(op, entry, modlist)) {
1152 return LDAP_INSUFFICIENT_ACCESS;
1155 for (; modlist != NULL; modlist = modlist->sml_next) {
1156 mods = &modlist->sml_mod;
1158 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
1161 switch (mods->sm_op) {
1163 rc = modify_add_values(entry, mods,
1164 get_permissiveModify(op),
1165 &rs->sr_text, textbuf,
1169 case LDAP_MOD_DELETE:
1170 rc = modify_delete_values(entry, mods,
1171 get_permissiveModify(op),
1172 &rs->sr_text, textbuf,
1176 case LDAP_MOD_REPLACE:
1177 rc = modify_replace_values(entry, mods,
1178 get_permissiveModify(op),
1179 &rs->sr_text, textbuf,
1183 case LDAP_MOD_INCREMENT:
1184 rc = modify_increment_values( entry,
1185 mods, get_permissiveModify(op),
1186 &rs->sr_text, textbuf,
1190 case SLAP_MOD_SOFTADD:
1191 mods->sm_op = LDAP_MOD_ADD;
1192 rc = modify_add_values(entry, mods,
1193 get_permissiveModify(op),
1194 &rs->sr_text, textbuf,
1196 mods->sm_op = SLAP_MOD_SOFTADD;
1197 if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
1202 case SLAP_MOD_SOFTDEL:
1203 mods->sm_op = LDAP_MOD_DELETE;
1204 rc = modify_delete_values(entry, mods,
1205 get_permissiveModify(op),
1206 &rs->sr_text, textbuf,
1208 mods->sm_op = SLAP_MOD_SOFTDEL;
1209 if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
1214 case SLAP_MOD_ADD_IF_NOT_PRESENT:
1215 if ( attr_find( entry->e_attrs, mods->sm_desc ) ) {
1219 mods->sm_op = LDAP_MOD_ADD;
1220 rc = modify_add_values(entry, mods,
1221 get_permissiveModify(op),
1222 &rs->sr_text, textbuf,
1224 mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
1227 if(rc != LDAP_SUCCESS) break;
1230 if ( rc == LDAP_SUCCESS ) {
1231 rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
1233 entry->e_ocflags = 0;
1235 /* check that the entry still obeys the schema */
1236 rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
1237 &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN );
1245 ldif_back_referrals( Operation *op, SlapReply *rs )
1247 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1248 struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn;
1249 ber_len_t min_dnlen;
1250 Entry *entry = NULL, **entryp;
1254 min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
1255 if ( min_dnlen == 0 ) {
1256 /* Catch root DSE (empty DN), it is not a referral */
1259 if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) {
1260 return LDAP_SUCCESS; /* Root DSE again */
1263 entryp = get_manageDSAit( op ) ? NULL : &entry;
1264 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1267 dnParent( &dn, &dn );
1268 dnParent( &ndn, &ndn );
1269 rc = ldif_read_entry( op, path.bv_val, &dn, &ndn,
1270 entryp, &rs->sr_text );
1271 if ( rc != LDAP_NO_SUCH_OBJECT )
1275 if ( ndn.bv_len < min_dnlen )
1277 (void) get_parent_path( &path, NULL );
1278 dir2ldif_name( path );
1282 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1283 SLAP_FREE( path.bv_val );
1285 if ( entry != NULL ) {
1286 if ( is_entry_referral( entry ) ) {
1287 Debug( LDAP_DEBUG_TRACE,
1288 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
1289 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn );
1291 ref = get_entry_referrals( op, entry );
1292 rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn,
1293 op->o_tag == LDAP_REQ_SEARCH ?
1294 op->ors_scope : LDAP_SCOPE_DEFAULT );
1295 ber_bvarray_free( ref );
1297 if ( rs->sr_ref != NULL ) {
1299 rc = rs->sr_err = LDAP_REFERRAL;
1300 rs->sr_matched = entry->e_dn;
1301 send_ldap_result( op, rs );
1302 ber_bvarray_free( rs->sr_ref );
1306 rs->sr_text = "bad referral object";
1308 rs->sr_matched = NULL;
1311 entry_free( entry );
1318 /* LDAP operations */
1321 ldif_back_bind( Operation *op, SlapReply *rs )
1323 struct ldif_info *li;
1325 AttributeDescription *password = slap_schema.si_ad_userPassword;
1327 Entry *entry = NULL;
1329 switch ( be_rootdn_bind( op, rs ) ) {
1330 case SLAP_CB_CONTINUE:
1334 /* in case of success, front end will send result;
1335 * otherwise, be_rootdn_bind() did */
1339 li = (struct ldif_info *) op->o_bd->be_private;
1340 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1341 return_val = get_entry(op, &entry, NULL, NULL);
1343 /* no object is found for them */
1344 if(return_val != LDAP_SUCCESS) {
1345 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
1349 /* they don't have userpassword */
1350 if((a = attr_find(entry->e_attrs, password)) == NULL) {
1351 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1356 /* authentication actually failed */
1357 if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
1358 &rs->sr_text) != 0) {
1359 rs->sr_err = LDAP_INVALID_CREDENTIALS;
1364 /* let the front-end send success */
1365 return_val = LDAP_SUCCESS;
1368 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1369 if(return_val != LDAP_SUCCESS)
1370 send_ldap_result( op, rs );
1377 ldif_back_search( Operation *op, SlapReply *rs )
1379 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1381 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1382 rs->sr_err = search_tree( op, rs );
1383 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1384 send_ldap_result(op, rs);
1390 ldif_back_add( Operation *op, SlapReply *rs )
1392 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1393 Entry * e = op->ora_e;
1396 char textbuf[SLAP_TEXT_BUFLEN];
1399 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
1401 rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
1402 &rs->sr_text, textbuf, sizeof( textbuf ) );
1403 if ( rc != LDAP_SUCCESS )
1406 rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
1407 if ( rc != LDAP_SUCCESS )
1410 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1412 rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
1413 if ( rc == LDAP_SUCCESS ) {
1414 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1415 rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
1416 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1418 SLAP_FREE( path.bv_val );
1419 if ( parentdir != NULL )
1420 SLAP_FREE( parentdir );
1423 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1427 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
1428 rc, rs->sr_text ? rs->sr_text : "", 0 );
1429 send_ldap_result( op, rs );
1430 slap_graduate_commit_csn( op );
1431 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1436 ldif_back_modify( Operation *op, SlapReply *rs )
1438 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1439 Modifications * modlst = op->orm_modlist;
1442 char textbuf[SLAP_TEXT_BUFLEN];
1445 slap_mods_opattrs( op, &op->orm_modlist, 1 );
1447 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1449 rc = get_entry( op, &entry, &path, &rs->sr_text );
1450 if ( rc == LDAP_SUCCESS ) {
1451 rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
1452 if ( rc == LDAP_SUCCESS ) {
1453 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1454 rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
1455 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1458 entry_free( entry );
1459 SLAP_FREE( path.bv_val );
1462 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1465 send_ldap_result( op, rs );
1466 slap_graduate_commit_csn( op );
1467 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1472 ldif_back_delete( Operation *op, SlapReply *rs )
1474 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1476 int rc = LDAP_SUCCESS;
1478 if ( BER_BVISEMPTY( &op->o_csn )) {
1480 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
1482 csn.bv_val = csnbuf;
1483 csn.bv_len = sizeof( csnbuf );
1484 slap_get_csn( op, &csn, 1 );
1487 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1488 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1489 if ( op->o_abandon ) {
1494 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
1495 if ( rc != LDAP_SUCCESS ) {
1499 ldif2dir_len( path );
1500 ldif2dir_name( path );
1501 if ( rmdir( path.bv_val ) < 0 ) {
1504 rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1507 /* is leaf, go on */
1511 rs->sr_text = "internal error (cannot delete subtree directory)";
1516 if ( rc == LDAP_SUCCESS ) {
1517 dir2ldif_name( path );
1518 if ( unlink( path.bv_val ) < 0 ) {
1519 rc = LDAP_NO_SUCH_OBJECT;
1520 if ( errno != ENOENT ) {
1522 rs->sr_text = "internal error (cannot delete entry file)";
1527 if ( rc == LDAP_OTHER ) {
1528 Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
1529 "cannot delete", path.bv_val, STRERROR( errno ) );
1532 SLAP_FREE( path.bv_val );
1534 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1535 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1537 send_ldap_result( op, rs );
1538 slap_graduate_commit_csn( op );
1548 struct berval *oldpath,
1551 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1552 struct berval newpath;
1553 char *parentdir = NULL, *trash;
1560 rc = ldif_prepare_create( op, entry, &newpath,
1561 op->orr_newSup ? &parentdir : NULL, text );
1564 if ( rc == LDAP_SUCCESS ) {
1565 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1567 rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
1568 if ( rc == LDAP_SUCCESS && !same_ndn ) {
1569 trash = oldpath->bv_val; /* will be .ldif file to delete */
1570 ldif2dir_len( newpath );
1571 ldif2dir_len( *oldpath );
1572 /* Move subdir before deleting old entry,
1573 * so .ldif always exists if subdir does.
1575 ldif2dir_name( newpath );
1576 ldif2dir_name( *oldpath );
1577 rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
1578 if ( rename_res != 0 && errno != ENOENT ) {
1580 *text = "internal error (cannot move this subtree)";
1581 trash = newpath.bv_val;
1584 /* Delete old entry, or if error undo change */
1586 dir2ldif_name( newpath );
1587 dir2ldif_name( *oldpath );
1588 if ( unlink( trash ) == 0 )
1590 if ( rc == LDAP_SUCCESS ) {
1591 /* Prepare to undo change and return failure */
1593 *text = "internal error (cannot move this entry)";
1594 trash = newpath.bv_val;
1595 if ( rename_res != 0 )
1597 /* First move subdirectory back */
1598 ldif2dir_name( newpath );
1599 ldif2dir_name( *oldpath );
1600 if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
1603 *text = "added new but couldn't delete old entry!";
1607 if ( rc != LDAP_SUCCESS ) {
1609 snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
1610 Debug( LDAP_DEBUG_ANY,
1611 "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
1612 s, op->o_req_dn.bv_val, entry->e_dn );
1616 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1618 SLAP_FREE( newpath.bv_val );
1619 if ( parentdir != NULL )
1620 SLAP_FREE( parentdir );
1627 ldif_back_modrdn( Operation *op, SlapReply *rs )
1629 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1630 struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1631 struct berval p_dn, old_path;
1633 char textbuf[SLAP_TEXT_BUFLEN];
1636 slap_mods_opattrs( op, &op->orr_modlist, 1 );
1638 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1640 rc = get_entry( op, &entry, &old_path, &rs->sr_text );
1641 if ( rc == LDAP_SUCCESS ) {
1642 /* build new dn, and new ndn for the entry */
1643 if ( op->oq_modrdn.rs_newSup != NULL ) {
1644 p_dn = *op->oq_modrdn.rs_newSup;
1646 dnParent( &entry->e_name, &p_dn );
1648 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
1649 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1650 same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
1651 ber_memfree_x( entry->e_name.bv_val, NULL );
1652 ber_memfree_x( entry->e_nname.bv_val, NULL );
1653 entry->e_name = new_dn;
1654 entry->e_nname = new_ndn;
1656 /* perform the modifications */
1657 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
1658 if ( rc == LDAP_SUCCESS )
1659 rc = ldif_move_entry( op, entry, same_ndn, &old_path,
1662 entry_free( entry );
1663 SLAP_FREE( old_path.bv_val );
1666 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1668 send_ldap_result( op, rs );
1669 slap_graduate_commit_csn( op );
1670 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1675 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1677 ldif_back_entry_get(
1681 AttributeDescription *at,
1685 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1686 struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1689 assert( ndn != NULL );
1690 assert( !BER_BVISNULL( ndn ) );
1692 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1693 op->o_req_dn = *ndn;
1694 op->o_req_ndn = *ndn;
1695 rc = get_entry( op, e, NULL, NULL );
1696 op->o_req_dn = op_dn;
1697 op->o_req_ndn = op_ndn;
1698 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1700 if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1701 rc = LDAP_NO_SUCH_ATTRIBUTE;
1713 ldif_tool_entry_open( BackendDB *be, int mode )
1715 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1722 ldif_tool_entry_close( BackendDB *be )
1724 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1725 Entry **entries = tl->entries;
1728 for ( i = tl->ecount; i--; )
1730 entry_free( entries[i] );
1731 SLAP_FREE( entries );
1733 tl->ecount = tl->elen = 0;
1738 ldif_tool_entry_next( BackendDB *be )
1740 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1743 Entry *e = tl->entries[ tl->ecurrent ];
1745 if ( tl->ecurrent >= tl->ecount ) {
1751 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1755 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter ) != LDAP_COMPARE_TRUE ) {
1762 return tl->ecurrent;
1766 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1768 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1771 tl->tl_scope = scope;
1774 if ( tl->entries == NULL ) {
1778 op.o_req_dn = *be->be_suffix;
1779 op.o_req_ndn = *be->be_nsuffix;
1780 op.ors_scope = LDAP_SCOPE_SUBTREE;
1781 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1782 tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1783 return NOID; /* fail ldif_tool_entry_get() */
1786 return ldif_tool_entry_next( be );
1790 ldif_tool_entry_get( BackendDB *be, ID id )
1792 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1796 if ( id < tl->ecount ) {
1797 e = tl->entries[id];
1798 tl->entries[id] = NULL;
1804 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1807 const char *errmsg = NULL;
1813 rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1814 if ( rc == LDAP_SUCCESS ) {
1815 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1817 SLAP_FREE( path.bv_val );
1818 if ( parentdir != NULL )
1819 SLAP_FREE( parentdir );
1820 if ( rc == LDAP_SUCCESS )
1824 if ( errmsg == NULL && rc != LDAP_OTHER )
1825 errmsg = ldap_err2string( rc );
1826 if ( errmsg != NULL )
1827 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1835 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1837 struct ldif_info *li;
1839 li = ch_calloc( 1, sizeof(struct ldif_info) );
1840 be->be_private = li;
1841 be->be_cf_ocs = ldifocs;
1842 ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1843 ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1844 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1849 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1851 struct ldif_info *li = be->be_private;
1853 ch_free( li->li_base_path.bv_val );
1854 ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1855 ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1856 free( be->be_private );
1861 ldif_back_db_open( Backend *be, ConfigReply *cr )
1863 struct ldif_info *li = (struct ldif_info *) be->be_private;
1864 if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1865 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1872 ldif_back_initialize( BackendInfo *bi )
1874 static char *controls[] = {
1875 LDAP_CONTROL_MANAGEDSAIT,
1881 SLAP_BFLAG_INCREMENT |
1882 SLAP_BFLAG_REFERRALS;
1884 bi->bi_controls = controls;
1891 bi->bi_db_init = ldif_back_db_init;
1892 bi->bi_db_config = config_generic_wrapper;
1893 bi->bi_db_open = ldif_back_db_open;
1894 bi->bi_db_close = 0;
1895 bi->bi_db_destroy = ldif_back_db_destroy;
1897 bi->bi_op_bind = ldif_back_bind;
1898 bi->bi_op_unbind = 0;
1899 bi->bi_op_search = ldif_back_search;
1900 bi->bi_op_compare = 0;
1901 bi->bi_op_modify = ldif_back_modify;
1902 bi->bi_op_modrdn = ldif_back_modrdn;
1903 bi->bi_op_add = ldif_back_add;
1904 bi->bi_op_delete = ldif_back_delete;
1905 bi->bi_op_abandon = 0;
1907 bi->bi_extended = 0;
1909 bi->bi_chk_referrals = ldif_back_referrals;
1911 bi->bi_connection_init = 0;
1912 bi->bi_connection_destroy = 0;
1914 bi->bi_entry_get_rw = ldif_back_entry_get;
1916 #if 0 /* NOTE: uncomment to completely disable access control */
1917 bi->bi_access_allowed = slap_access_always_allowed;
1920 bi->bi_tool_entry_open = ldif_tool_entry_open;
1921 bi->bi_tool_entry_close = ldif_tool_entry_close;
1922 bi->bi_tool_entry_first = backend_tool_entry_first;
1923 bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
1924 bi->bi_tool_entry_next = ldif_tool_entry_next;
1925 bi->bi_tool_entry_get = ldif_tool_entry_get;
1926 bi->bi_tool_entry_put = ldif_tool_entry_put;
1927 bi->bi_tool_entry_reindex = 0;
1928 bi->bi_tool_sync = 0;
1930 bi->bi_tool_dn2id_get = 0;
1931 bi->bi_tool_entry_modify = 0;
1933 bi->bi_cf_ocs = ldifocs;
1935 rc = config_register_schema( ldifcfg, ldifocs );
1936 if ( rc ) return rc;