1 /* ldif.c - the ldif backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2014 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;
762 e->e_id = tl->ecount;
766 else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
767 /* Send a continuation reference.
768 * (ldif_back_referrals() handles baseobject referrals.)
769 * Don't check the filter since it's only a candidate.
771 BerVarray refs = get_entry_referrals( op, e );
772 rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
774 rc = send_search_reference( op, rs );
775 ber_bvarray_free( rs->sr_ref );
776 ber_bvarray_free( refs );
781 else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
783 rs->sr_attrs = op->ors_attrs;
784 /* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
785 * but refraining lets us test unFREEable MODIFIABLE
786 * entries. Like entries built on the stack.
788 rs->sr_flags = REP_ENTRY_MODIFIABLE;
789 rc = send_search_entry( op, rs );
800 /* Read LDIF directory <path> into <listp>. Set *fname_maxlenp. */
805 const struct berval *path,
807 ber_len_t *fname_maxlenp )
809 int rc = LDAP_SUCCESS;
815 dir_of_path = opendir( path->bv_val );
816 if ( dir_of_path == NULL ) {
817 int save_errno = errno;
818 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
819 int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
821 /* Absent directory is OK (leaf entry), except the database dir */
822 if ( is_rootDSE || save_errno != ENOENT ) {
823 Debug( LDAP_DEBUG_ANY,
824 "=> ldif_search_entry: failed to opendir \"%s\": %s\n",
825 path->bv_val, STRERROR( save_errno ), 0 );
829 save_errno != ENOENT ? "internal error (bad directory)"
830 : !is_rootDSE ? "internal error (missing directory)"
831 : "internal error (database directory does not exist)";
839 while ( (dir = readdir( dir_of_path )) != NULL ) {
842 char *trunc, *idxp, *endp, *endp2;
844 fname_len = strlen( dir->d_name );
845 if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
847 if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
850 if ( *fname_maxlenp < fname_len )
851 *fname_maxlenp = fname_len;
853 bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
859 strcpy( BVL_NAME( bvl ), dir->d_name );
861 /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
862 trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
863 if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
864 (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
865 (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
867 /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
868 bvl->inum = strtol( idxp, &endp2, 10 );
869 if ( endp2 == endp ) {
877 bvl->savech = *trunc;
881 for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
882 int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
883 if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
890 if ( closedir( dir_of_path ) < 0 ) {
894 rs->sr_text = "internal error (bad directory)";
896 if ( rc != LDAP_SUCCESS ) {
897 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
898 "error reading directory", path->bv_val,
899 STRERROR( save_errno ) );
907 * Send an entry, recursively search its children, and free or save it.
908 * Return an LDAP result code. Parameters:
909 * op, rs operation and reply. rs == NULL for slap tools.
910 * e entry to search, or NULL for rootDSE.
911 * scope scope for the part of the search from this entry.
912 * path LDIF filename -- bv_len and non-directory part are overwritten.
920 struct berval *path )
922 int rc = LDAP_SUCCESS;
923 struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
925 if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
926 /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
927 * which bconfig.c seems to need. (TODO: see config_rename_one.)
929 if ( ber_dupbv( &dn, &e->e_name ) == NULL ||
930 ber_dupbv( &ndn, &e->e_nname ) == NULL )
932 Debug( LDAP_DEBUG_ANY,
933 "ldif_search_entry: out of memory\n", 0, 0, 0 );
939 /* Send the entry if appropriate, and free or save it */
941 rc = ldif_send_entry( op, rs, e, scope );
943 /* Search the children */
944 if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
946 struct berval fpath; /* becomes child pathname */
947 char *dir_end; /* will point past dirname in fpath */
949 ldif2dir_len( *path );
950 ldif2dir_name( *path );
951 rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
953 if ( list != NULL ) {
954 const char **text = rs == NULL ? NULL : &rs->sr_text;
956 if ( scope == LDAP_SCOPE_ONELEVEL )
957 scope = LDAP_SCOPE_BASE;
958 else if ( scope == LDAP_SCOPE_SUBORDINATE )
959 scope = LDAP_SCOPE_SUBTREE;
961 /* Allocate fpath and fill in directory part */
962 dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
963 if ( dir_end == NULL )
969 if ( rc == LDAP_SUCCESS ) {
970 *ptr->trunc = ptr->savech;
971 FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
973 rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
977 rc = ldif_search_entry( op, rs, e, scope, &fpath );
979 case LDAP_NO_SUCH_OBJECT:
980 /* Only the search baseDN may produce noSuchObject. */
983 rs->sr_text = "internal error "
984 "(did someone just remove an entry file?)";
985 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
986 "file listed in parent directory does not exist: "
987 "\"%s\"\n", fpath.bv_val, 0, 0 );
994 } while ( list != NULL );
996 if ( !BER_BVISNULL( &fpath ) )
997 SLAP_FREE( fpath.bv_val );
1002 if ( !BER_BVISEMPTY( &dn ) )
1003 ber_memfree( dn.bv_val );
1004 if ( !BER_BVISEMPTY( &ndn ) )
1005 ber_memfree( ndn.bv_val );
1010 search_tree( Operation *op, SlapReply *rs )
1012 int rc = LDAP_SUCCESS;
1015 struct berval pdn, pndn;
1017 (void) ndn2path( op, &op->o_req_ndn, &path, 1 );
1018 if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
1019 /* Read baseObject */
1020 dnParent( &op->o_req_dn, &pdn );
1021 dnParent( &op->o_req_ndn, &pndn );
1022 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
1023 rs == NULL ? NULL : &rs->sr_text );
1025 if ( rc == LDAP_SUCCESS )
1026 rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
1028 ch_free( path.bv_val );
1034 * Prepare to create or rename an entry:
1035 * Check that the entry does not already exist.
1036 * Check that the parent entry exists and can have subordinates,
1037 * unless need_dir is NULL or adding the suffix entry.
1039 * Return an LDAP result code. May set *text to a message on failure.
1040 * If success, set *dnpath to LDIF entry path and *need_dir to
1041 * (directory must be created ? dirname : NULL).
1044 ldif_prepare_create(
1047 struct berval *dnpath,
1051 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1052 struct berval *ndn = &e->e_nname;
1053 struct berval ppath = BER_BVNULL;
1055 Entry *parent = NULL;
1058 if ( op->o_abandon )
1059 return SLAPD_ABANDON;
1061 rc = ndn2path( op, ndn, dnpath, 0 );
1062 if ( rc != LDAP_SUCCESS ) {
1066 if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
1067 rc = LDAP_ALREADY_EXISTS;
1069 } else if ( errno != ENOENT ) {
1070 Debug( LDAP_DEBUG_ANY,
1071 "ldif_prepare_create: cannot stat \"%s\": %s\n",
1072 dnpath->bv_val, STRERROR( errno ), 0 );
1074 *text = "internal error (cannot check entry file)";
1076 } else if ( need_dir != NULL ) {
1078 rc = get_parent_path( dnpath, &ppath );
1079 /* If parent dir exists, so does parent .ldif:
1080 * The directory gets created after and removed before the .ldif.
1081 * Except with the database directory, which has no matching entry.
1083 if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
1084 rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
1085 ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
1088 case LDAP_NO_SUCH_OBJECT:
1089 /* No parent dir, check parent .ldif */
1090 dir2ldif_name( ppath );
1091 rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
1092 (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
1097 /* Check that parent is not a referral, unless
1098 * ldif_back_referrals() already checked.
1100 if ( parent != NULL ) {
1101 int is_ref = is_entry_referral( parent );
1102 entry_free( parent );
1104 rc = LDAP_AFFECTS_MULTIPLE_DSAS;
1105 *text = op->o_tag == LDAP_REQ_MODDN
1106 ? "newSuperior is a referral object"
1107 : "parent is a referral object";
1111 /* Must create parent directory. */
1112 ldif2dir_name( ppath );
1113 *need_dir = ppath.bv_val;
1115 case LDAP_NO_SUCH_OBJECT:
1116 *text = op->o_tag == LDAP_REQ_MODDN
1117 ? "newSuperior object does not exist"
1118 : "parent does not exist";
1123 Debug( LDAP_DEBUG_ANY,
1124 "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
1125 ndn->bv_val, STRERROR( errno ), 0 );
1126 *text = "internal error (cannot stat parent dir)";
1129 if ( *need_dir == NULL && ppath.bv_val != NULL )
1130 SLAP_FREE( ppath.bv_val );
1133 if ( rc != LDAP_SUCCESS ) {
1134 SLAP_FREE( dnpath->bv_val );
1135 BER_BVZERO( dnpath );
1141 apply_modify_to_entry(
1143 Modifications *modlist,
1148 int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
1152 if (!acl_check_modlist(op, entry, modlist)) {
1153 return LDAP_INSUFFICIENT_ACCESS;
1156 for (; modlist != NULL; modlist = modlist->sml_next) {
1157 mods = &modlist->sml_mod;
1159 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
1162 switch (mods->sm_op) {
1164 rc = modify_add_values(entry, mods,
1165 get_permissiveModify(op),
1166 &rs->sr_text, textbuf,
1170 case LDAP_MOD_DELETE:
1171 rc = modify_delete_values(entry, mods,
1172 get_permissiveModify(op),
1173 &rs->sr_text, textbuf,
1177 case LDAP_MOD_REPLACE:
1178 rc = modify_replace_values(entry, mods,
1179 get_permissiveModify(op),
1180 &rs->sr_text, textbuf,
1184 case LDAP_MOD_INCREMENT:
1185 rc = modify_increment_values( entry,
1186 mods, get_permissiveModify(op),
1187 &rs->sr_text, textbuf,
1191 case SLAP_MOD_SOFTADD:
1192 mods->sm_op = LDAP_MOD_ADD;
1193 rc = modify_add_values(entry, mods,
1194 get_permissiveModify(op),
1195 &rs->sr_text, textbuf,
1197 mods->sm_op = SLAP_MOD_SOFTADD;
1198 if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
1203 case SLAP_MOD_SOFTDEL:
1204 mods->sm_op = LDAP_MOD_DELETE;
1205 rc = modify_delete_values(entry, mods,
1206 get_permissiveModify(op),
1207 &rs->sr_text, textbuf,
1209 mods->sm_op = SLAP_MOD_SOFTDEL;
1210 if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
1215 case SLAP_MOD_ADD_IF_NOT_PRESENT:
1216 if ( attr_find( entry->e_attrs, mods->sm_desc ) ) {
1220 mods->sm_op = LDAP_MOD_ADD;
1221 rc = modify_add_values(entry, mods,
1222 get_permissiveModify(op),
1223 &rs->sr_text, textbuf,
1225 mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
1228 if(rc != LDAP_SUCCESS) break;
1231 if ( rc == LDAP_SUCCESS ) {
1232 rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
1234 entry->e_ocflags = 0;
1236 /* check that the entry still obeys the schema */
1237 rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
1238 &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN );
1246 ldif_back_referrals( Operation *op, SlapReply *rs )
1248 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1249 struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn;
1250 ber_len_t min_dnlen;
1251 Entry *entry = NULL, **entryp;
1255 min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
1256 if ( min_dnlen == 0 ) {
1257 /* Catch root DSE (empty DN), it is not a referral */
1260 if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) {
1261 return LDAP_SUCCESS; /* Root DSE again */
1264 entryp = get_manageDSAit( op ) ? NULL : &entry;
1265 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1268 dnParent( &dn, &dn );
1269 dnParent( &ndn, &ndn );
1270 rc = ldif_read_entry( op, path.bv_val, &dn, &ndn,
1271 entryp, &rs->sr_text );
1272 if ( rc != LDAP_NO_SUCH_OBJECT )
1276 if ( ndn.bv_len < min_dnlen )
1278 (void) get_parent_path( &path, NULL );
1279 dir2ldif_name( path );
1283 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1284 SLAP_FREE( path.bv_val );
1286 if ( entry != NULL ) {
1287 if ( is_entry_referral( entry ) ) {
1288 Debug( LDAP_DEBUG_TRACE,
1289 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
1290 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn );
1292 ref = get_entry_referrals( op, entry );
1293 rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn,
1294 op->o_tag == LDAP_REQ_SEARCH ?
1295 op->ors_scope : LDAP_SCOPE_DEFAULT );
1296 ber_bvarray_free( ref );
1298 if ( rs->sr_ref != NULL ) {
1300 rc = rs->sr_err = LDAP_REFERRAL;
1301 rs->sr_matched = entry->e_dn;
1302 send_ldap_result( op, rs );
1303 ber_bvarray_free( rs->sr_ref );
1307 rs->sr_text = "bad referral object";
1309 rs->sr_matched = NULL;
1312 entry_free( entry );
1319 /* LDAP operations */
1322 ldif_back_bind( Operation *op, SlapReply *rs )
1324 struct ldif_info *li;
1326 AttributeDescription *password = slap_schema.si_ad_userPassword;
1328 Entry *entry = NULL;
1330 switch ( be_rootdn_bind( op, rs ) ) {
1331 case SLAP_CB_CONTINUE:
1335 /* in case of success, front end will send result;
1336 * otherwise, be_rootdn_bind() did */
1340 li = (struct ldif_info *) op->o_bd->be_private;
1341 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1342 return_val = get_entry(op, &entry, NULL, NULL);
1344 /* no object is found for them */
1345 if(return_val != LDAP_SUCCESS) {
1346 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
1350 /* they don't have userpassword */
1351 if((a = attr_find(entry->e_attrs, password)) == NULL) {
1352 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1357 /* authentication actually failed */
1358 if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
1359 &rs->sr_text) != 0) {
1360 rs->sr_err = LDAP_INVALID_CREDENTIALS;
1365 /* let the front-end send success */
1366 return_val = LDAP_SUCCESS;
1369 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1370 if(return_val != LDAP_SUCCESS)
1371 send_ldap_result( op, rs );
1378 ldif_back_search( Operation *op, SlapReply *rs )
1380 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1382 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1383 rs->sr_err = search_tree( op, rs );
1384 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1385 send_ldap_result(op, rs);
1391 ldif_back_add( Operation *op, SlapReply *rs )
1393 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1394 Entry * e = op->ora_e;
1397 char textbuf[SLAP_TEXT_BUFLEN];
1400 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
1402 rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
1403 &rs->sr_text, textbuf, sizeof( textbuf ) );
1404 if ( rc != LDAP_SUCCESS )
1407 rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
1408 if ( rc != LDAP_SUCCESS )
1411 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1413 rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
1414 if ( rc == LDAP_SUCCESS ) {
1415 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1416 rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
1417 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1419 SLAP_FREE( path.bv_val );
1420 if ( parentdir != NULL )
1421 SLAP_FREE( parentdir );
1424 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1428 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
1429 rc, rs->sr_text ? rs->sr_text : "", 0 );
1430 send_ldap_result( op, rs );
1431 slap_graduate_commit_csn( op );
1432 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1437 ldif_back_modify( Operation *op, SlapReply *rs )
1439 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1440 Modifications * modlst = op->orm_modlist;
1443 char textbuf[SLAP_TEXT_BUFLEN];
1446 slap_mods_opattrs( op, &op->orm_modlist, 1 );
1448 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1450 rc = get_entry( op, &entry, &path, &rs->sr_text );
1451 if ( rc == LDAP_SUCCESS ) {
1452 rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
1453 if ( rc == LDAP_SUCCESS ) {
1454 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1455 rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
1456 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1459 entry_free( entry );
1460 SLAP_FREE( path.bv_val );
1463 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1466 send_ldap_result( op, rs );
1467 slap_graduate_commit_csn( op );
1468 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1473 ldif_back_delete( Operation *op, SlapReply *rs )
1475 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1477 int rc = LDAP_SUCCESS;
1479 if ( BER_BVISEMPTY( &op->o_csn )) {
1481 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
1483 csn.bv_val = csnbuf;
1484 csn.bv_len = sizeof( csnbuf );
1485 slap_get_csn( op, &csn, 1 );
1488 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1489 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1490 if ( op->o_abandon ) {
1495 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
1496 if ( rc != LDAP_SUCCESS ) {
1500 ldif2dir_len( path );
1501 ldif2dir_name( path );
1502 if ( rmdir( path.bv_val ) < 0 ) {
1505 rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1508 /* is leaf, go on */
1512 rs->sr_text = "internal error (cannot delete subtree directory)";
1517 if ( rc == LDAP_SUCCESS ) {
1518 dir2ldif_name( path );
1519 if ( unlink( path.bv_val ) < 0 ) {
1520 rc = LDAP_NO_SUCH_OBJECT;
1521 if ( errno != ENOENT ) {
1523 rs->sr_text = "internal error (cannot delete entry file)";
1528 if ( rc == LDAP_OTHER ) {
1529 Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
1530 "cannot delete", path.bv_val, STRERROR( errno ) );
1533 SLAP_FREE( path.bv_val );
1535 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1536 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1538 send_ldap_result( op, rs );
1539 slap_graduate_commit_csn( op );
1549 struct berval *oldpath,
1552 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1553 struct berval newpath;
1554 char *parentdir = NULL, *trash;
1561 rc = ldif_prepare_create( op, entry, &newpath,
1562 op->orr_newSup ? &parentdir : NULL, text );
1565 if ( rc == LDAP_SUCCESS ) {
1566 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1568 rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
1569 if ( rc == LDAP_SUCCESS && !same_ndn ) {
1570 trash = oldpath->bv_val; /* will be .ldif file to delete */
1571 ldif2dir_len( newpath );
1572 ldif2dir_len( *oldpath );
1573 /* Move subdir before deleting old entry,
1574 * so .ldif always exists if subdir does.
1576 ldif2dir_name( newpath );
1577 ldif2dir_name( *oldpath );
1578 rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
1579 if ( rename_res != 0 && errno != ENOENT ) {
1581 *text = "internal error (cannot move this subtree)";
1582 trash = newpath.bv_val;
1585 /* Delete old entry, or if error undo change */
1587 dir2ldif_name( newpath );
1588 dir2ldif_name( *oldpath );
1589 if ( unlink( trash ) == 0 )
1591 if ( rc == LDAP_SUCCESS ) {
1592 /* Prepare to undo change and return failure */
1594 *text = "internal error (cannot move this entry)";
1595 trash = newpath.bv_val;
1596 if ( rename_res != 0 )
1598 /* First move subdirectory back */
1599 ldif2dir_name( newpath );
1600 ldif2dir_name( *oldpath );
1601 if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
1604 *text = "added new but couldn't delete old entry!";
1608 if ( rc != LDAP_SUCCESS ) {
1610 snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
1611 Debug( LDAP_DEBUG_ANY,
1612 "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
1613 s, op->o_req_dn.bv_val, entry->e_dn );
1617 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1619 SLAP_FREE( newpath.bv_val );
1620 if ( parentdir != NULL )
1621 SLAP_FREE( parentdir );
1628 ldif_back_modrdn( Operation *op, SlapReply *rs )
1630 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1631 struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1632 struct berval p_dn, old_path;
1634 char textbuf[SLAP_TEXT_BUFLEN];
1637 slap_mods_opattrs( op, &op->orr_modlist, 1 );
1639 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1641 rc = get_entry( op, &entry, &old_path, &rs->sr_text );
1642 if ( rc == LDAP_SUCCESS ) {
1643 /* build new dn, and new ndn for the entry */
1644 if ( op->oq_modrdn.rs_newSup != NULL ) {
1645 p_dn = *op->oq_modrdn.rs_newSup;
1647 dnParent( &entry->e_name, &p_dn );
1649 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
1650 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1651 same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
1652 ber_memfree_x( entry->e_name.bv_val, NULL );
1653 ber_memfree_x( entry->e_nname.bv_val, NULL );
1654 entry->e_name = new_dn;
1655 entry->e_nname = new_ndn;
1657 /* perform the modifications */
1658 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
1659 if ( rc == LDAP_SUCCESS )
1660 rc = ldif_move_entry( op, entry, same_ndn, &old_path,
1663 entry_free( entry );
1664 SLAP_FREE( old_path.bv_val );
1667 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1669 send_ldap_result( op, rs );
1670 slap_graduate_commit_csn( op );
1671 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1676 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1678 ldif_back_entry_get(
1682 AttributeDescription *at,
1686 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1687 struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1690 assert( ndn != NULL );
1691 assert( !BER_BVISNULL( ndn ) );
1693 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1694 op->o_req_dn = *ndn;
1695 op->o_req_ndn = *ndn;
1696 rc = get_entry( op, e, NULL, NULL );
1697 op->o_req_dn = op_dn;
1698 op->o_req_ndn = op_ndn;
1699 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1701 if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1702 rc = LDAP_NO_SUCH_ATTRIBUTE;
1711 ldif_back_entry_release_rw (
1718 /* only tool mode assigns valid IDs */
1719 if ( id != 0 && id != NOID )
1721 struct ldif_tool *tl = &((struct ldif_info *) op->o_bd->be_private)->li_tool;
1725 assert( id < tl->ecount );
1726 assert( e == tl->entries[id] );
1727 tl->entries[id] = NULL;
1738 ldif_tool_entry_open( BackendDB *be, int mode )
1740 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1747 ldif_tool_entry_close( BackendDB *be )
1749 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1750 Entry **entries = tl->entries;
1753 for ( i = tl->ecount; i--; )
1755 entry_free( entries[i] );
1756 SLAP_FREE( entries );
1758 tl->ecount = tl->elen = 0;
1763 ldif_tool_entry_next( BackendDB *be )
1765 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1768 Entry *e = tl->entries[ tl->ecurrent ];
1770 if ( tl->ecurrent >= tl->ecount ) {
1776 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1780 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter ) != LDAP_COMPARE_TRUE ) {
1787 return tl->ecurrent;
1791 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1793 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1796 tl->tl_scope = scope;
1799 if ( tl->entries == NULL ) {
1803 op.o_req_dn = *be->be_suffix;
1804 op.o_req_ndn = *be->be_nsuffix;
1805 op.ors_scope = LDAP_SCOPE_SUBTREE;
1806 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1807 tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1808 return NOID; /* fail ldif_tool_entry_get() */
1811 return ldif_tool_entry_next( be );
1815 ldif_tool_dn2id_get( BackendDB *be, struct berval *dn )
1817 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1824 op.ors_scope = LDAP_SCOPE_BASE;
1825 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1832 ldif_tool_entry_get( BackendDB *be, ID id )
1834 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1838 if ( id < tl->ecount ) {
1839 e = tl->entries[id];
1845 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1848 const char *errmsg = NULL;
1854 rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1855 if ( rc == LDAP_SUCCESS ) {
1856 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1858 SLAP_FREE( path.bv_val );
1859 if ( parentdir != NULL )
1860 SLAP_FREE( parentdir );
1861 if ( rc == LDAP_SUCCESS )
1865 if ( errmsg == NULL && rc != LDAP_OTHER )
1866 errmsg = ldap_err2string( rc );
1867 if ( errmsg != NULL )
1868 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1873 ldif_tool_entry_modify( BackendDB *be, Entry *e, struct berval *text )
1876 const char *errmsg = NULL;
1881 ndn2path( &op, &e->e_nname, &path, 0 );
1882 rc = ldif_write_entry( &op, e, &path, NULL, &errmsg );
1883 SLAP_FREE( path.bv_val );
1884 if ( rc == LDAP_SUCCESS )
1887 if ( errmsg == NULL && rc != LDAP_OTHER )
1888 errmsg = ldap_err2string( rc );
1889 if ( errmsg != NULL )
1890 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1895 ldif_tool_entry_delete( BackendDB *be, ID id, struct berval *text )
1897 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1898 int rc = LDAP_SUCCESS;
1899 const char *errmsg = NULL;
1905 if ( id >= tl->ecount || tl->entries[id] == NULL )
1907 e = tl->entries[id];
1910 ndn2path( &op, &e->e_nname, &path, 0 );
1912 ldif2dir_len( path );
1913 ldif2dir_name( path );
1914 if ( rmdir( path.bv_val ) < 0 ) {
1917 rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1920 /* is leaf, go on */
1924 errmsg = "internal error (cannot delete subtree directory)";
1929 if ( rc == LDAP_SUCCESS ) {
1930 dir2ldif_name( path );
1931 if ( unlink( path.bv_val ) < 0 ) {
1932 rc = LDAP_NO_SUCH_OBJECT;
1933 if ( errno != ENOENT ) {
1935 errmsg = "internal error (cannot delete entry file)";
1940 SLAP_FREE( path.bv_val );
1942 tl->entries[id] = NULL;
1944 if ( errmsg == NULL && rc != LDAP_OTHER )
1945 errmsg = ldap_err2string( rc );
1946 if ( errmsg != NULL )
1947 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1955 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1957 struct ldif_info *li;
1959 li = ch_calloc( 1, sizeof(struct ldif_info) );
1960 be->be_private = li;
1961 be->be_cf_ocs = ldifocs;
1962 ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1963 ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1964 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1969 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1971 struct ldif_info *li = be->be_private;
1973 ch_free( li->li_base_path.bv_val );
1974 ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1975 ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1976 free( be->be_private );
1981 ldif_back_db_open( Backend *be, ConfigReply *cr )
1983 struct ldif_info *li = (struct ldif_info *) be->be_private;
1984 if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1985 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1992 ldif_back_initialize( BackendInfo *bi )
1994 static char *controls[] = {
1995 LDAP_CONTROL_MANAGEDSAIT,
2001 SLAP_BFLAG_INCREMENT |
2002 SLAP_BFLAG_REFERRALS;
2004 bi->bi_controls = controls;
2011 bi->bi_db_init = ldif_back_db_init;
2012 bi->bi_db_config = config_generic_wrapper;
2013 bi->bi_db_open = ldif_back_db_open;
2014 bi->bi_db_close = 0;
2015 bi->bi_db_destroy = ldif_back_db_destroy;
2017 bi->bi_op_bind = ldif_back_bind;
2018 bi->bi_op_unbind = 0;
2019 bi->bi_op_search = ldif_back_search;
2020 bi->bi_op_compare = 0;
2021 bi->bi_op_modify = ldif_back_modify;
2022 bi->bi_op_modrdn = ldif_back_modrdn;
2023 bi->bi_op_add = ldif_back_add;
2024 bi->bi_op_delete = ldif_back_delete;
2025 bi->bi_op_abandon = 0;
2027 bi->bi_extended = 0;
2029 bi->bi_chk_referrals = ldif_back_referrals;
2031 bi->bi_connection_init = 0;
2032 bi->bi_connection_destroy = 0;
2034 bi->bi_entry_get_rw = ldif_back_entry_get;
2035 bi->bi_entry_release_rw = ldif_back_entry_release_rw;
2037 #if 0 /* NOTE: uncomment to completely disable access control */
2038 bi->bi_access_allowed = slap_access_always_allowed;
2041 bi->bi_tool_entry_open = ldif_tool_entry_open;
2042 bi->bi_tool_entry_close = ldif_tool_entry_close;
2043 bi->bi_tool_entry_first = backend_tool_entry_first;
2044 bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
2045 bi->bi_tool_entry_next = ldif_tool_entry_next;
2046 bi->bi_tool_dn2id_get = ldif_tool_dn2id_get;
2047 bi->bi_tool_entry_get = ldif_tool_entry_get;
2048 bi->bi_tool_entry_put = ldif_tool_entry_put;
2049 bi->bi_tool_entry_modify = ldif_tool_entry_modify;
2050 bi->bi_tool_entry_delete = ldif_tool_entry_delete;
2051 bi->bi_tool_entry_reindex = 0;
2052 bi->bi_tool_sync = 0;
2054 bi->bi_cf_ocs = ldifocs;
2056 rc = config_register_schema( ldifcfg, ldifocs );
2057 if ( rc ) return rc;