1 /* ldif.c - the ldif backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2018 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 * This work was originally developed by Eric Stokes for inclusion
18 * in OpenLDAP Software.
23 #include <ac/string.h>
24 #include <sys/types.h>
26 #include <ac/dirent.h>
29 #include <ac/unistd.h>
35 Entry **entries; /* collected by bi_tool_entry_first() */
36 ID elen; /* length of entries[] array */
37 ID ecount; /* number of entries */
38 ID ecurrent; /* bi_tool_entry_next() position */
39 # define ENTRY_BUFF_INCREMENT 500 /* initial entries[] length */
40 struct berval *tl_base;
45 /* Per-database data */
47 struct berval li_base_path; /* database directory */
48 struct ldif_tool li_tool; /* for slap tools */
50 * Read-only LDAP requests readlock li_rdwr for filesystem input.
51 * Update requests first lock li_modop_mutex for filesystem I/O,
52 * and then writelock li_rdwr as well for filesystem output.
53 * This allows update requests to do callbacks that acquire
54 * read locks, e.g. access controls that inspect entries.
55 * (An alternative would be recursive read/write locks.)
57 ldap_pvt_thread_mutex_t li_modop_mutex; /* serialize update requests */
58 ldap_pvt_thread_rdwr_t li_rdwr; /* no other I/O when writing */
61 static int write_data( int fd, const char *spew, int len, int *save_errno );
64 #define mkdir(a,b) mkdir(a)
65 #define move_file(from, to) (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
67 #define move_file(from, to) rename(from, to)
69 #define move_dir(from, to) rename(from, to)
73 #define LDIF_FILETYPE_SEP '.' /* LDIF[0] */
76 * Unsafe/translated characters in the filesystem.
78 * LDIF_UNSAFE_CHAR(c) returns true if the character c is not to be used
79 * in relative filenames, except it should accept '\\', '{' and '}' even
80 * if unsafe. The value should be a constant expression.
82 * If '\\' is unsafe, #define LDIF_ESCAPE_CHAR as a safe character.
83 * If '{' and '}' are unsafe, #define IX_FSL/IX_FSR as safe characters.
84 * (Not digits, '-' or '+'. IX_FSL == IX_FSR is allowed.)
86 * Characters are escaped as LDIF_ESCAPE_CHAR followed by two hex digits,
87 * except '\\' is replaced with LDIF_ESCAPE_CHAR and {} with IX_FS[LR].
88 * Also some LDIF special chars are hex-escaped.
90 * Thus an LDIF filename is a valid normalized RDN (or suffix DN)
91 * followed by ".ldif", except with '\\' replaced with LDIF_ESCAPE_CHAR.
97 * Unix/MacOSX version. ':' vs '/' can cause confusion on MacOSX so we
98 * escape both. We escape them on Unix so both OS variants get the same
101 #define LDIF_ESCAPE_CHAR '\\'
102 #define LDIF_UNSAFE_CHAR(c) ((c) == '/' || (c) == ':')
106 /* Windows version - Microsoft's list of unsafe characters, except '\\' */
107 #define LDIF_ESCAPE_CHAR '^' /* Not '\\' (unsafe on Windows) */
108 #define LDIF_UNSAFE_CHAR(c) \
109 ((c) == '/' || (c) == ':' || \
110 (c) == '<' || (c) == '>' || (c) == '"' || \
111 (c) == '|' || (c) == '?' || (c) == '*')
116 * Left and Right "{num}" prefix to ordered RDNs ("olcDatabase={1}bdb").
117 * IX_DN* are for LDAP RDNs, IX_FS* for their .ldif filenames.
122 #define IX_FSL IX_DNL
123 #define IX_FSR IX_DNR
127 * Test for unsafe chars, as well as chars handled specially by back-ldif:
128 * - If the escape char is not '\\', it must itself be escaped. Otherwise
129 * '\\' and the escape char would map to the same character.
130 * - Escape the '.' in ".ldif", so the directory for an RDN that actually
131 * ends with ".ldif" can not conflict with a file of the same name. And
132 * since some OSes/programs choke on multiple '.'s, escape all of them.
133 * - If '{' and '}' are translated to some other characters, those
134 * characters must in turn be escaped when they occur in an RDN.
136 #ifndef LDIF_NEED_ESCAPE
137 #define LDIF_NEED_ESCAPE(c) \
138 ((LDIF_UNSAFE_CHAR(c)) || \
139 LDIF_MAYBE_UNSAFE(c, LDIF_ESCAPE_CHAR) || \
140 LDIF_MAYBE_UNSAFE(c, LDIF_FILETYPE_SEP) || \
141 LDIF_MAYBE_UNSAFE(c, IX_FSL) || \
142 (IX_FSR != IX_FSL && LDIF_MAYBE_UNSAFE(c, IX_FSR)))
145 * Helper macro for LDIF_NEED_ESCAPE(): Treat character x as unsafe if
146 * back-ldif does not already treat is specially.
148 #define LDIF_MAYBE_UNSAFE(c, x) \
149 (!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \
152 /* Collect other "safe char" tests here, until someone needs a fix. */
154 eq_unsafe = LDIF_UNSAFE_CHAR('='),
155 safe_filenames = STRLENOF("" LDAP_DIRSEP "") == 1 && !(
156 LDIF_UNSAFE_CHAR('-') || /* for "{-1}frontend" in bconfig.c */
157 LDIF_UNSAFE_CHAR(LDIF_ESCAPE_CHAR) ||
158 LDIF_UNSAFE_CHAR(IX_FSL) || LDIF_UNSAFE_CHAR(IX_FSR))
160 /* Sanity check: Try to force a compilation error if !safe_filenames */
162 int assert_safe_filenames : safe_filenames ? 2 : -2;
163 } assert_safe_filenames[safe_filenames ? 2 : -2];
166 static ConfigTable ldifcfg[] = {
167 { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
168 (void *)offsetof(struct ldif_info, li_base_path),
169 "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
170 "DESC 'Directory for database content' "
171 "EQUALITY caseIgnoreMatch "
172 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
173 { NULL, NULL, 0, 0, 0, ARG_IGNORED,
174 NULL, NULL, NULL, NULL }
177 static ConfigOCs ldifocs[] = {
179 "NAME 'olcLdifConfig' "
180 "DESC 'LDIF backend configuration' "
181 "SUP olcDatabaseConfig "
182 "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg },
188 * Handle file/directory names.
191 /* Set *res = LDIF filename path for the normalized DN */
193 ndn2path( Operation *op, struct berval *dn, struct berval *res, int empty_ok )
195 BackendDB *be = op->o_bd;
196 struct ldif_info *li = (struct ldif_info *) be->be_private;
197 struct berval *suffixdn = &be->be_nsuffix[0];
198 const char *start, *end, *next, *p;
201 static const char hex[] = "0123456789ABCDEF";
203 assert( dn != NULL );
204 assert( !BER_BVISNULL( dn ) );
205 assert( suffixdn != NULL );
206 assert( !BER_BVISNULL( suffixdn ) );
207 assert( dnIsSuffix( dn, suffixdn ) );
209 if ( dn->bv_len == 0 && !empty_ok ) {
210 return LDAP_UNWILLING_TO_PERFORM;
214 end = start + dn->bv_len;
216 /* Room for dir, dirsep, dn, LDIF, "\hexpair"-escaping of unsafe chars */
217 len = li->li_base_path.bv_len + dn->bv_len + (1 + STRLENOF( LDIF ));
218 for ( p = start; p < end; ) {
220 if ( LDIF_NEED_ESCAPE( ch ) )
223 res->bv_val = ch_malloc( len + 1 );
225 ptr = lutil_strcopy( res->bv_val, li->li_base_path.bv_val );
226 for ( next = end - suffixdn->bv_len; end > start; end = next ) {
227 /* Set p = start of DN component, next = &',' or start of DN */
228 while ( (p = next) > start ) {
230 if ( DN_SEPARATOR( *next ) )
233 /* Append <dirsep> <p..end-1: RDN or database-suffix> */
234 for ( *ptr++ = LDAP_DIRSEP[0]; p < end; *ptr++ = ch ) {
236 if ( LDIF_ESCAPE_CHAR != '\\' && ch == '\\' ) {
237 ch = LDIF_ESCAPE_CHAR;
238 } else if ( IX_FSL != IX_DNL && ch == IX_DNL ) {
240 } else if ( IX_FSR != IX_DNR && ch == IX_DNR ) {
242 } else if ( LDIF_NEED_ESCAPE( ch ) ) {
243 *ptr++ = LDIF_ESCAPE_CHAR;
244 *ptr++ = hex[(ch & 0xFFU) >> 4];
245 ch = hex[ch & 0x0FU];
249 ptr = lutil_strcopy( ptr, LDIF );
250 res->bv_len = ptr - res->bv_val;
252 assert( res->bv_len <= len );
258 * *dest = dupbv(<dir + LDAP_DIRSEP>), plus room for <more>-sized filename.
259 * Return pointer past the dirname.
262 fullpath_alloc( struct berval *dest, const struct berval *dir, ber_len_t more )
264 char *s = SLAP_MALLOC( dir->bv_len + more + 2 );
269 Debug( LDAP_DEBUG_ANY, "back-ldif: out of memory\n", 0, 0, 0 );
271 s = lutil_strcopy( dest->bv_val, dir->bv_val );
272 *s++ = LDAP_DIRSEP[0];
274 dest->bv_len = s - dest->bv_val;
280 * Append filename to fullpath_alloc() dirname or replace previous filename.
281 * dir_end = fullpath_alloc() return value.
283 #define FILL_PATH(fpath, dir_end, filename) \
284 ((fpath)->bv_len = lutil_strcopy(dir_end, filename) - (fpath)->bv_val)
287 /* .ldif entry filename length <-> subtree dirname length. */
288 #define ldif2dir_len(bv) ((bv).bv_len -= STRLENOF(LDIF))
289 #define dir2ldif_len(bv) ((bv).bv_len += STRLENOF(LDIF))
290 /* .ldif entry filename <-> subtree dirname, both with dirname length. */
291 #define ldif2dir_name(bv) ((bv).bv_val[(bv).bv_len] = '\0')
292 #define dir2ldif_name(bv) ((bv).bv_val[(bv).bv_len] = LDIF_FILETYPE_SEP)
294 /* Get the parent directory path, plus the LDIF suffix overwritten by a \0. */
296 get_parent_path( struct berval *dnpath, struct berval *res )
298 ber_len_t i = dnpath->bv_len;
300 while ( i > 0 && dnpath->bv_val[ --i ] != LDAP_DIRSEP[0] ) ;
304 res->bv_val = SLAP_MALLOC( i + 1 + STRLENOF(LDIF) );
305 if ( res->bv_val == NULL )
307 AC_MEMCPY( res->bv_val, dnpath->bv_val, i );
310 strcpy( res->bv_val + i, LDIF );
311 res->bv_val[i] = '\0';
315 /* Make temporary filename pattern for mkstemp() based on dnpath. */
317 ldif_tempname( const struct berval *dnpath )
319 static const char suffix[] = ".XXXXXX";
320 ber_len_t len = dnpath->bv_len - STRLENOF( LDIF );
321 char *name = SLAP_MALLOC( len + sizeof( suffix ) );
323 if ( name != NULL ) {
324 AC_MEMCPY( name, dnpath->bv_val, len );
325 strcpy( name + len, suffix );
330 /* CRC-32 table for the polynomial:
331 * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
336 static const ber_uint_t crctab[256] = {
337 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
338 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
339 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
340 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
341 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
342 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
343 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
344 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
345 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
346 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
347 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
348 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
349 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
350 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
351 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
352 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
353 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
354 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
355 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
356 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
357 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
358 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
359 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
360 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
361 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
362 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
363 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
364 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
365 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
366 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
367 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
368 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
369 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
370 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
371 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
372 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
373 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
374 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
375 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
376 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
377 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
378 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
379 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
380 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
381 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
382 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
383 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
384 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
385 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
386 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
387 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
391 #define CRC1 crc = crctab[(crc ^ *buf++) & 0xff] ^ (crc >> 8)
392 #define CRC8 CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1
394 crc32(const void *vbuf, int len)
396 const unsigned char *buf = vbuf;
397 ber_uint_t crc = 0xffffffff;
408 return crc ^ 0xffffffff;
412 * Read a file, or stat() it if datap == NULL. Allocate and fill *datap.
413 * Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error.
416 ldif_read_file( const char *path, char **datap )
418 int rc = LDAP_SUCCESS, fd, len;
419 int res = -1; /* 0:success, <0:error, >0:file too big/growing. */
421 char *data = NULL, *ptr = NULL;
424 if ( datap == NULL ) {
425 res = stat( path, &st );
428 fd = open( path, O_RDONLY );
430 if ( fstat( fd, &st ) == 0 ) {
431 if ( st.st_size > INT_MAX - 2 ) {
434 len = st.st_size + 1; /* +1 detects file size > st.st_size */
435 *datap = data = ptr = SLAP_MALLOC( len + 1 );
437 while ( len && (res = read( fd, ptr, len )) ) {
441 } else if ( errno != EINTR ) {
449 if ( close( fd ) < 0 )
456 msg = "entry file exists";
458 msg = "read entry file";
460 ptr = strstr( data, "\n# CRC32" );
462 msg = "read entry file without checksum";
464 unsigned int crc1 = 0, crc2 = 1;
465 if ( sscanf( ptr + 9, "%08x", &crc1) == 1) {
466 ptr = strchr(ptr+1, '\n');
470 crc2 = crc32( ptr, len );
473 if ( crc1 != crc2 ) {
474 Debug( LDAP_DEBUG_ANY, "ldif_read_file: checksum error on \"%s\"\n",
480 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n", msg, path, 0 );
481 #endif /* LDAP_DEBUG */
483 if ( res < 0 && errno == ENOENT ) {
484 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
485 "no entry file \"%s\"\n", path, 0, 0 );
486 rc = LDAP_NO_SUCH_OBJECT;
488 msg = res < 0 ? STRERROR( errno ) : "bad stat() size";
489 Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
500 * return nonnegative for success or -1 for error
501 * do not return numbers less than -1
504 spew_file( int fd, const char *spew, int len, int *save_errno )
507 #define HEADER "# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n"
508 char header[sizeof(HEADER "# CRC32 12345678\n")];
510 sprintf(header, HEADER "# CRC32 %08x\n", crc32(spew, len));
511 writeres = write_data(fd, header, sizeof(header)-1, save_errno);
512 return writeres < 0 ? writeres : write_data(fd, spew, len, save_errno);
516 write_data( int fd, const char *spew, int len, int *save_errno )
520 writeres = write(fd, spew, len);
523 if (*save_errno != EINTR)
534 /* Write an entry LDIF file. Create parentdir first if non-NULL. */
539 const struct berval *path,
540 const char *parentdir,
543 int rc = LDAP_OTHER, res, save_errno = 0;
544 int fd, entry_length;
545 char *entry_as_string, *tmpfname;
548 return SLAPD_ABANDON;
550 if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
552 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
553 "cannot create parent directory",
554 parentdir, STRERROR( save_errno ) );
555 *text = "internal error (cannot create parent directory)";
559 tmpfname = ldif_tempname( path );
560 fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
563 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
564 "cannot create file", e->e_dn, STRERROR( save_errno ) );
565 *text = "internal error (cannot create file)";
568 ber_len_t dn_len = e->e_name.bv_len;
571 /* Only save the RDN onto disk */
572 dnRdn( &e->e_name, &rdn );
573 if ( rdn.bv_len != dn_len ) {
574 e->e_name.bv_val[rdn.bv_len] = '\0';
575 e->e_name.bv_len = rdn.bv_len;
579 ldap_pvt_thread_mutex_lock( &entry2str_mutex );
580 entry_as_string = entry2str( e, &entry_length );
581 if ( entry_as_string != NULL )
582 res = spew_file( fd, entry_as_string, entry_length, &save_errno );
583 ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
585 /* Restore full DN */
586 if ( rdn.bv_len != dn_len ) {
587 e->e_name.bv_val[rdn.bv_len] = ',';
588 e->e_name.bv_len = dn_len;
591 if ( close( fd ) < 0 && res >= 0 ) {
597 if ( move_file( tmpfname, path->bv_val ) == 0 ) {
598 Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
599 "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 );
603 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
604 "could not put entry file for \"%s\" in place: %s\n",
605 e->e_name.bv_val, STRERROR( save_errno ), 0 );
606 *text = "internal error (could not put entry file in place)";
608 } else if ( res == -1 ) {
609 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
610 "write error to", tmpfname, STRERROR( save_errno ) );
611 *text = "internal error (write error to entry file)";
614 if ( rc != LDAP_SUCCESS ) {
620 SLAP_FREE( tmpfname );
625 * Read the entry at path, or if entryp==NULL just see if it exists.
626 * pdn and pndn are the parent's DN and normalized DN, or both NULL.
627 * Return an LDAP result code.
640 char *entry_as_string;
643 /* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
644 * If so we need not check for LDAP_REQ_BIND here.
646 if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND )
647 return SLAPD_ABANDON;
649 rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
653 if ( entryp == NULL )
655 *entryp = entry = str2entry( entry_as_string );
656 SLAP_FREE( entry_as_string );
657 if ( entry == NULL ) {
660 *text = "internal error (cannot parse some entry file)";
663 if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
665 /* Append parent DN to DN from LDIF file */
667 build_new_dn( &entry->e_name, pdn, &rdn, NULL );
668 SLAP_FREE( rdn.bv_val );
669 rdn = entry->e_nname;
670 build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
671 SLAP_FREE( rdn.bv_val );
677 ? "internal error (cannot read some entry file)"
678 : "internal error (cannot stat some entry file)";
686 * Read the operation's entry, or if entryp==NULL just see if it exists.
687 * Return an LDAP result code. May set *text to a message on failure.
688 * If pathp is non-NULL, set it to the entry filename on success.
694 struct berval *pathp,
698 struct berval path, pdn, pndn;
700 dnParent( &op->o_req_dn, &pdn );
701 dnParent( &op->o_req_ndn, &pndn );
702 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
703 if ( rc != LDAP_SUCCESS ) {
707 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
709 if ( rc == LDAP_SUCCESS && pathp != NULL ) {
712 SLAP_FREE( path.bv_val );
720 * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
721 * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
722 * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
723 * Does not sort escaped chars correctly, would need to un-escape them.
725 typedef struct bvlist {
727 char *trunc; /* filename was truncated here */
728 int inum; /* num from "attr={num}" in filename, or INT_MIN */
729 char savech; /* original char at *trunc */
730 /* BVL_NAME(&bvlist) is the filename, allocated after the struct: */
731 # define BVL_NAME(bvl) ((char *) ((bvl) + 1))
732 # define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1)
736 ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
738 int rc = LDAP_SUCCESS;
740 if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
742 /* Save the entry for tool mode */
743 struct ldif_tool *tl =
744 &((struct ldif_info *) op->o_bd->be_private)->li_tool;
746 if ( tl->ecount >= tl->elen ) {
747 /* Allocate/grow entries */
748 ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
749 Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
750 sizeof(Entry *) * elen );
751 if ( entries == NULL ) {
752 Debug( LDAP_DEBUG_ANY,
753 "ldif_send_entry: out of memory\n", 0, 0, 0 );
758 tl->entries = entries;
760 tl->entries[tl->ecount++] = e;
761 e->e_id = tl->ecount;
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 : "internal error (database directory does not exist)";
837 while ( (dir = readdir( dir_of_path )) != NULL ) {
840 char *trunc, *idxp, *endp, *endp2;
842 fname_len = strlen( dir->d_name );
843 if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
845 if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
848 if ( *fname_maxlenp < fname_len )
849 *fname_maxlenp = fname_len;
851 bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
857 strcpy( BVL_NAME( bvl ), dir->d_name );
859 /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
860 trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
861 if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
862 (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
863 (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
865 /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
866 bvl->inum = strtol( idxp, &endp2, 10 );
867 if ( endp2 == endp ) {
875 bvl->savech = *trunc;
879 for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
880 int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
881 if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
888 if ( closedir( dir_of_path ) < 0 ) {
892 rs->sr_text = "internal error (bad directory)";
894 if ( rc != LDAP_SUCCESS ) {
895 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
896 "error reading directory", path->bv_val,
897 STRERROR( save_errno ) );
905 * Send an entry, recursively search its children, and free or save it.
906 * Return an LDAP result code. Parameters:
907 * op, rs operation and reply. rs == NULL for slap tools.
908 * e entry to search, or NULL for rootDSE.
909 * scope scope for the part of the search from this entry.
910 * path LDIF filename -- bv_len and non-directory part are overwritten.
918 struct berval *path )
920 int rc = LDAP_SUCCESS;
921 struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
923 if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
924 /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
925 * which bconfig.c seems to need. (TODO: see config_rename_one.)
927 if ( ber_dupbv( &dn, &e->e_name ) == NULL ||
928 ber_dupbv( &ndn, &e->e_nname ) == NULL )
930 Debug( LDAP_DEBUG_ANY,
931 "ldif_search_entry: out of memory\n", 0, 0, 0 );
937 /* Send the entry if appropriate, and free or save it */
939 rc = ldif_send_entry( op, rs, e, scope );
941 /* Search the children */
942 if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
944 struct berval fpath; /* becomes child pathname */
945 char *dir_end; /* will point past dirname in fpath */
947 ldif2dir_len( *path );
948 ldif2dir_name( *path );
949 rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
951 if ( list != NULL ) {
952 const char **text = rs == NULL ? NULL : &rs->sr_text;
954 if ( scope == LDAP_SCOPE_ONELEVEL )
955 scope = LDAP_SCOPE_BASE;
956 else if ( scope == LDAP_SCOPE_SUBORDINATE )
957 scope = LDAP_SCOPE_SUBTREE;
959 /* Allocate fpath and fill in directory part */
960 dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
961 if ( dir_end == NULL )
967 if ( rc == LDAP_SUCCESS ) {
968 *ptr->trunc = ptr->savech;
969 FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
971 rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
975 rc = ldif_search_entry( op, rs, e, scope, &fpath );
977 case LDAP_NO_SUCH_OBJECT:
978 /* Only the search baseDN may produce noSuchObject. */
981 rs->sr_text = "internal error "
982 "(did someone just remove an entry file?)";
983 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
984 "file listed in parent directory does not exist: "
985 "\"%s\"\n", fpath.bv_val, 0, 0 );
992 } while ( list != NULL );
994 if ( !BER_BVISNULL( &fpath ) )
995 SLAP_FREE( fpath.bv_val );
1000 if ( !BER_BVISEMPTY( &dn ) )
1001 ber_memfree( dn.bv_val );
1002 if ( !BER_BVISEMPTY( &ndn ) )
1003 ber_memfree( ndn.bv_val );
1008 search_tree( Operation *op, SlapReply *rs )
1010 int rc = LDAP_SUCCESS;
1013 struct berval pdn, pndn;
1015 (void) ndn2path( op, &op->o_req_ndn, &path, 1 );
1016 if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
1017 /* Read baseObject */
1018 dnParent( &op->o_req_dn, &pdn );
1019 dnParent( &op->o_req_ndn, &pndn );
1020 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
1021 rs == NULL ? NULL : &rs->sr_text );
1023 if ( rc == LDAP_SUCCESS )
1024 rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
1026 ch_free( path.bv_val );
1032 * Prepare to create or rename an entry:
1033 * Check that the entry does not already exist.
1034 * Check that the parent entry exists and can have subordinates,
1035 * unless need_dir is NULL or adding the suffix entry.
1037 * Return an LDAP result code. May set *text to a message on failure.
1038 * If success, set *dnpath to LDIF entry path and *need_dir to
1039 * (directory must be created ? dirname : NULL).
1042 ldif_prepare_create(
1045 struct berval *dnpath,
1049 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1050 struct berval *ndn = &e->e_nname;
1051 struct berval ppath = BER_BVNULL;
1053 Entry *parent = NULL;
1056 if ( op->o_abandon )
1057 return SLAPD_ABANDON;
1059 rc = ndn2path( op, ndn, dnpath, 0 );
1060 if ( rc != LDAP_SUCCESS ) {
1064 if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
1065 rc = LDAP_ALREADY_EXISTS;
1067 } else if ( errno != ENOENT ) {
1068 Debug( LDAP_DEBUG_ANY,
1069 "ldif_prepare_create: cannot stat \"%s\": %s\n",
1070 dnpath->bv_val, STRERROR( errno ), 0 );
1072 *text = "internal error (cannot check entry file)";
1074 } else if ( need_dir != NULL ) {
1076 rc = get_parent_path( dnpath, &ppath );
1077 /* If parent dir exists, so does parent .ldif:
1078 * The directory gets created after and removed before the .ldif.
1079 * Except with the database directory, which has no matching entry.
1081 if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
1082 rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
1083 ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
1086 case LDAP_NO_SUCH_OBJECT:
1087 /* No parent dir, check parent .ldif */
1088 dir2ldif_name( ppath );
1089 rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
1090 (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
1095 /* Check that parent is not a referral, unless
1096 * ldif_back_referrals() already checked.
1098 if ( parent != NULL ) {
1099 int is_ref = is_entry_referral( parent );
1100 entry_free( parent );
1102 rc = LDAP_AFFECTS_MULTIPLE_DSAS;
1103 *text = op->o_tag == LDAP_REQ_MODDN
1104 ? "newSuperior is a referral object"
1105 : "parent is a referral object";
1109 /* Must create parent directory. */
1110 ldif2dir_name( ppath );
1111 *need_dir = ppath.bv_val;
1113 case LDAP_NO_SUCH_OBJECT:
1114 *text = op->o_tag == LDAP_REQ_MODDN
1115 ? "newSuperior object does not exist"
1116 : "parent does not exist";
1121 Debug( LDAP_DEBUG_ANY,
1122 "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
1123 ndn->bv_val, STRERROR( errno ), 0 );
1124 *text = "internal error (cannot stat parent dir)";
1127 if ( *need_dir == NULL && ppath.bv_val != NULL )
1128 SLAP_FREE( ppath.bv_val );
1131 if ( rc != LDAP_SUCCESS ) {
1132 SLAP_FREE( dnpath->bv_val );
1133 BER_BVZERO( dnpath );
1139 apply_modify_to_entry(
1141 Modifications *modlist,
1146 int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
1150 if (!acl_check_modlist(op, entry, modlist)) {
1151 return LDAP_INSUFFICIENT_ACCESS;
1154 for (; modlist != NULL; modlist = modlist->sml_next) {
1155 mods = &modlist->sml_mod;
1157 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
1160 switch (mods->sm_op) {
1162 rc = modify_add_values(entry, mods,
1163 get_permissiveModify(op),
1164 &rs->sr_text, textbuf,
1168 case LDAP_MOD_DELETE:
1169 rc = modify_delete_values(entry, mods,
1170 get_permissiveModify(op),
1171 &rs->sr_text, textbuf,
1175 case LDAP_MOD_REPLACE:
1176 rc = modify_replace_values(entry, mods,
1177 get_permissiveModify(op),
1178 &rs->sr_text, textbuf,
1182 case LDAP_MOD_INCREMENT:
1183 rc = modify_increment_values( entry,
1184 mods, get_permissiveModify(op),
1185 &rs->sr_text, textbuf,
1189 case SLAP_MOD_SOFTADD:
1190 mods->sm_op = LDAP_MOD_ADD;
1191 rc = modify_add_values(entry, mods,
1192 get_permissiveModify(op),
1193 &rs->sr_text, textbuf,
1195 mods->sm_op = SLAP_MOD_SOFTADD;
1196 if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
1201 case SLAP_MOD_SOFTDEL:
1202 mods->sm_op = LDAP_MOD_DELETE;
1203 rc = modify_delete_values(entry, mods,
1204 get_permissiveModify(op),
1205 &rs->sr_text, textbuf,
1207 mods->sm_op = SLAP_MOD_SOFTDEL;
1208 if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
1213 case SLAP_MOD_ADD_IF_NOT_PRESENT:
1214 if ( attr_find( entry->e_attrs, mods->sm_desc ) ) {
1218 mods->sm_op = LDAP_MOD_ADD;
1219 rc = modify_add_values(entry, mods,
1220 get_permissiveModify(op),
1221 &rs->sr_text, textbuf,
1223 mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
1226 if(rc != LDAP_SUCCESS) break;
1229 if ( rc == LDAP_SUCCESS ) {
1230 rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
1232 entry->e_ocflags = 0;
1234 /* check that the entry still obeys the schema */
1235 rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
1236 &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN );
1244 ldif_back_referrals( Operation *op, SlapReply *rs )
1246 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1247 struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn;
1248 ber_len_t min_dnlen;
1249 Entry *entry = NULL, **entryp;
1253 min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
1254 if ( min_dnlen == 0 ) {
1255 /* Catch root DSE (empty DN), it is not a referral */
1258 if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) {
1259 return LDAP_SUCCESS; /* Root DSE again */
1262 entryp = get_manageDSAit( op ) ? NULL : &entry;
1263 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1266 dnParent( &dn, &dn );
1267 dnParent( &ndn, &ndn );
1268 rc = ldif_read_entry( op, path.bv_val, &dn, &ndn,
1269 entryp, &rs->sr_text );
1270 if ( rc != LDAP_NO_SUCH_OBJECT )
1274 if ( ndn.bv_len < min_dnlen )
1276 (void) get_parent_path( &path, NULL );
1277 dir2ldif_name( path );
1281 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1282 SLAP_FREE( path.bv_val );
1284 if ( entry != NULL ) {
1285 if ( is_entry_referral( entry ) ) {
1286 Debug( LDAP_DEBUG_TRACE,
1287 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
1288 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn );
1290 ref = get_entry_referrals( op, entry );
1291 rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn,
1292 op->o_tag == LDAP_REQ_SEARCH ?
1293 op->ors_scope : LDAP_SCOPE_DEFAULT );
1294 ber_bvarray_free( ref );
1296 if ( rs->sr_ref != NULL ) {
1298 rc = rs->sr_err = LDAP_REFERRAL;
1299 rs->sr_matched = entry->e_dn;
1300 send_ldap_result( op, rs );
1301 ber_bvarray_free( rs->sr_ref );
1305 rs->sr_text = "bad referral object";
1307 rs->sr_matched = NULL;
1310 entry_free( entry );
1317 /* LDAP operations */
1320 ldif_back_bind( Operation *op, SlapReply *rs )
1322 struct ldif_info *li;
1324 AttributeDescription *password = slap_schema.si_ad_userPassword;
1326 Entry *entry = NULL;
1328 switch ( be_rootdn_bind( op, rs ) ) {
1329 case SLAP_CB_CONTINUE:
1333 /* in case of success, front end will send result;
1334 * otherwise, be_rootdn_bind() did */
1338 li = (struct ldif_info *) op->o_bd->be_private;
1339 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1340 return_val = get_entry(op, &entry, NULL, NULL);
1342 /* no object is found for them */
1343 if(return_val != LDAP_SUCCESS) {
1344 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
1348 /* they don't have userpassword */
1349 if((a = attr_find(entry->e_attrs, password)) == NULL) {
1350 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1355 /* authentication actually failed */
1356 if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
1357 &rs->sr_text) != 0) {
1358 rs->sr_err = LDAP_INVALID_CREDENTIALS;
1363 /* let the front-end send success */
1364 return_val = LDAP_SUCCESS;
1367 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1368 if(return_val != LDAP_SUCCESS)
1369 send_ldap_result( op, rs );
1376 ldif_back_search( Operation *op, SlapReply *rs )
1378 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1380 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1381 rs->sr_err = search_tree( op, rs );
1382 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1383 send_ldap_result(op, rs);
1389 ldif_back_add( Operation *op, SlapReply *rs )
1391 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1392 Entry * e = op->ora_e;
1395 char textbuf[SLAP_TEXT_BUFLEN];
1398 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
1400 rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
1401 &rs->sr_text, textbuf, sizeof( textbuf ) );
1402 if ( rc != LDAP_SUCCESS )
1405 rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
1406 if ( rc != LDAP_SUCCESS )
1409 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1411 rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
1412 if ( rc == LDAP_SUCCESS ) {
1413 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1414 rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
1415 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1417 SLAP_FREE( path.bv_val );
1418 if ( parentdir != NULL )
1419 SLAP_FREE( parentdir );
1422 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1426 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
1427 rc, rs->sr_text ? rs->sr_text : "", 0 );
1428 send_ldap_result( op, rs );
1429 slap_graduate_commit_csn( op );
1430 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1435 ldif_back_modify( Operation *op, SlapReply *rs )
1437 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1438 Modifications * modlst = op->orm_modlist;
1441 char textbuf[SLAP_TEXT_BUFLEN];
1444 slap_mods_opattrs( op, &op->orm_modlist, 1 );
1446 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1448 rc = get_entry( op, &entry, &path, &rs->sr_text );
1449 if ( rc == LDAP_SUCCESS ) {
1450 rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
1451 if ( rc == LDAP_SUCCESS ) {
1452 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1453 rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
1454 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1457 entry_free( entry );
1458 SLAP_FREE( path.bv_val );
1461 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1464 send_ldap_result( op, rs );
1465 slap_graduate_commit_csn( op );
1466 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1471 ldif_back_delete( Operation *op, SlapReply *rs )
1473 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1475 int rc = LDAP_SUCCESS;
1477 if ( BER_BVISEMPTY( &op->o_csn )) {
1479 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
1481 csn.bv_val = csnbuf;
1482 csn.bv_len = sizeof( csnbuf );
1483 slap_get_csn( op, &csn, 1 );
1486 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1487 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1488 if ( op->o_abandon ) {
1493 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
1494 if ( rc != LDAP_SUCCESS ) {
1498 ldif2dir_len( path );
1499 ldif2dir_name( path );
1500 if ( rmdir( path.bv_val ) < 0 ) {
1503 rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1506 /* is leaf, go on */
1510 rs->sr_text = "internal error (cannot delete subtree directory)";
1515 if ( rc == LDAP_SUCCESS ) {
1516 dir2ldif_name( path );
1517 if ( unlink( path.bv_val ) < 0 ) {
1518 rc = LDAP_NO_SUCH_OBJECT;
1519 if ( errno != ENOENT ) {
1521 rs->sr_text = "internal error (cannot delete entry file)";
1526 if ( rc == LDAP_OTHER ) {
1527 Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
1528 "cannot delete", path.bv_val, STRERROR( errno ) );
1531 SLAP_FREE( path.bv_val );
1533 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1534 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1536 send_ldap_result( op, rs );
1537 slap_graduate_commit_csn( op );
1547 struct berval *oldpath,
1550 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1551 struct berval newpath;
1552 char *parentdir = NULL, *trash;
1559 rc = ldif_prepare_create( op, entry, &newpath,
1560 op->orr_newSup ? &parentdir : NULL, text );
1563 if ( rc == LDAP_SUCCESS ) {
1564 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1566 rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
1567 if ( rc == LDAP_SUCCESS && !same_ndn ) {
1568 trash = oldpath->bv_val; /* will be .ldif file to delete */
1569 ldif2dir_len( newpath );
1570 ldif2dir_len( *oldpath );
1571 /* Move subdir before deleting old entry,
1572 * so .ldif always exists if subdir does.
1574 ldif2dir_name( newpath );
1575 ldif2dir_name( *oldpath );
1576 rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
1577 if ( rename_res != 0 && errno != ENOENT ) {
1579 *text = "internal error (cannot move this subtree)";
1580 trash = newpath.bv_val;
1583 /* Delete old entry, or if error undo change */
1585 dir2ldif_name( newpath );
1586 dir2ldif_name( *oldpath );
1587 if ( unlink( trash ) == 0 )
1589 if ( rc == LDAP_SUCCESS ) {
1590 /* Prepare to undo change and return failure */
1592 *text = "internal error (cannot move this entry)";
1593 trash = newpath.bv_val;
1594 if ( rename_res != 0 )
1596 /* First move subdirectory back */
1597 ldif2dir_name( newpath );
1598 ldif2dir_name( *oldpath );
1599 if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
1602 *text = "added new but couldn't delete old entry!";
1606 if ( rc != LDAP_SUCCESS ) {
1608 snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
1609 Debug( LDAP_DEBUG_ANY,
1610 "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
1611 s, op->o_req_dn.bv_val, entry->e_dn );
1615 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1617 SLAP_FREE( newpath.bv_val );
1618 if ( parentdir != NULL )
1619 SLAP_FREE( parentdir );
1626 ldif_back_modrdn( Operation *op, SlapReply *rs )
1628 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1629 struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1630 struct berval p_dn, old_path;
1632 char textbuf[SLAP_TEXT_BUFLEN];
1635 slap_mods_opattrs( op, &op->orr_modlist, 1 );
1637 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1639 rc = get_entry( op, &entry, &old_path, &rs->sr_text );
1640 if ( rc == LDAP_SUCCESS ) {
1641 /* build new dn, and new ndn for the entry */
1642 if ( op->oq_modrdn.rs_newSup != NULL ) {
1643 p_dn = *op->oq_modrdn.rs_newSup;
1645 dnParent( &entry->e_name, &p_dn );
1647 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
1648 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1649 same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
1650 ber_memfree_x( entry->e_name.bv_val, NULL );
1651 ber_memfree_x( entry->e_nname.bv_val, NULL );
1652 entry->e_name = new_dn;
1653 entry->e_nname = new_ndn;
1655 /* perform the modifications */
1656 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
1657 if ( rc == LDAP_SUCCESS )
1658 rc = ldif_move_entry( op, entry, same_ndn, &old_path,
1661 entry_free( entry );
1662 SLAP_FREE( old_path.bv_val );
1665 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1667 send_ldap_result( op, rs );
1668 slap_graduate_commit_csn( op );
1669 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1674 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1676 ldif_back_entry_get(
1680 AttributeDescription *at,
1684 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1685 struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1688 assert( ndn != NULL );
1689 assert( !BER_BVISNULL( ndn ) );
1691 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1692 op->o_req_dn = *ndn;
1693 op->o_req_ndn = *ndn;
1694 rc = get_entry( op, e, NULL, NULL );
1695 op->o_req_dn = op_dn;
1696 op->o_req_ndn = op_ndn;
1697 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1699 if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1700 rc = LDAP_NO_SUCH_ATTRIBUTE;
1709 ldif_back_entry_release_rw (
1716 /* only tool mode assigns valid IDs */
1717 if ( id != 0 && id != NOID )
1719 struct ldif_tool *tl = &((struct ldif_info *) op->o_bd->be_private)->li_tool;
1723 assert( id < tl->ecount );
1724 assert( e == tl->entries[id] );
1725 tl->entries[id] = NULL;
1736 ldif_tool_entry_open( BackendDB *be, int mode )
1738 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1745 ldif_tool_entry_close( BackendDB *be )
1747 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1748 Entry **entries = tl->entries;
1751 for ( i = tl->ecount; i--; )
1753 entry_free( entries[i] );
1754 SLAP_FREE( entries );
1756 tl->ecount = tl->elen = 0;
1761 ldif_tool_entry_next( BackendDB *be )
1763 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1766 Entry *e = tl->entries[ tl->ecurrent ];
1768 if ( tl->ecurrent >= tl->ecount ) {
1774 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1778 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter ) != LDAP_COMPARE_TRUE ) {
1785 return tl->ecurrent;
1789 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1791 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1794 tl->tl_scope = scope;
1797 if ( tl->entries == NULL ) {
1801 op.o_req_dn = *be->be_suffix;
1802 op.o_req_ndn = *be->be_nsuffix;
1803 op.ors_scope = LDAP_SCOPE_SUBTREE;
1804 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1805 tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1806 return NOID; /* fail ldif_tool_entry_get() */
1809 return ldif_tool_entry_next( be );
1813 ldif_tool_dn2id_get( BackendDB *be, struct berval *dn )
1815 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1822 op.ors_scope = LDAP_SCOPE_BASE;
1823 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1830 ldif_tool_entry_get( BackendDB *be, ID id )
1832 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1836 if ( id < tl->ecount ) {
1837 e = tl->entries[id];
1843 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1846 const char *errmsg = NULL;
1852 rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1853 if ( rc == LDAP_SUCCESS ) {
1854 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1856 SLAP_FREE( path.bv_val );
1857 if ( parentdir != NULL )
1858 SLAP_FREE( parentdir );
1859 if ( rc == LDAP_SUCCESS )
1863 if ( errmsg == NULL && rc != LDAP_OTHER )
1864 errmsg = ldap_err2string( rc );
1865 if ( errmsg != NULL )
1866 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1871 ldif_tool_entry_modify( BackendDB *be, Entry *e, struct berval *text )
1874 const char *errmsg = NULL;
1879 ndn2path( &op, &e->e_nname, &path, 0 );
1880 rc = ldif_write_entry( &op, e, &path, NULL, &errmsg );
1881 SLAP_FREE( path.bv_val );
1882 if ( rc == LDAP_SUCCESS )
1885 if ( errmsg == NULL && rc != LDAP_OTHER )
1886 errmsg = ldap_err2string( rc );
1887 if ( errmsg != NULL )
1888 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1893 ldif_tool_entry_delete( BackendDB *be, struct berval *ndn, struct berval *text )
1895 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1896 int rc = LDAP_SUCCESS;
1897 const char *errmsg = NULL;
1902 ndn2path( &op, ndn, &path, 0 );
1904 ldif2dir_len( path );
1905 ldif2dir_name( path );
1906 if ( rmdir( path.bv_val ) < 0 ) {
1909 rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1912 /* is leaf, go on */
1916 errmsg = "internal error (cannot delete subtree directory)";
1921 if ( rc == LDAP_SUCCESS ) {
1922 dir2ldif_name( path );
1923 if ( unlink( path.bv_val ) < 0 ) {
1924 rc = LDAP_NO_SUCH_OBJECT;
1925 if ( errno != ENOENT ) {
1927 errmsg = "internal error (cannot delete entry file)";
1932 SLAP_FREE( path.bv_val );
1934 if ( errmsg == NULL && rc != LDAP_OTHER )
1935 errmsg = ldap_err2string( rc );
1936 if ( errmsg != NULL )
1937 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1945 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1947 struct ldif_info *li;
1949 li = ch_calloc( 1, sizeof(struct ldif_info) );
1950 be->be_private = li;
1951 be->be_cf_ocs = ldifocs;
1952 ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1953 ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1954 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1959 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1961 struct ldif_info *li = be->be_private;
1963 ch_free( li->li_base_path.bv_val );
1964 ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1965 ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1966 free( be->be_private );
1971 ldif_back_db_open( Backend *be, ConfigReply *cr )
1973 struct ldif_info *li = (struct ldif_info *) be->be_private;
1974 if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1975 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1982 ldif_back_initialize( BackendInfo *bi )
1984 static char *controls[] = {
1985 LDAP_CONTROL_MANAGEDSAIT,
1991 SLAP_BFLAG_INCREMENT |
1992 SLAP_BFLAG_REFERRALS;
1994 bi->bi_controls = controls;
2001 bi->bi_db_init = ldif_back_db_init;
2002 bi->bi_db_config = config_generic_wrapper;
2003 bi->bi_db_open = ldif_back_db_open;
2004 bi->bi_db_close = 0;
2005 bi->bi_db_destroy = ldif_back_db_destroy;
2007 bi->bi_op_bind = ldif_back_bind;
2008 bi->bi_op_unbind = 0;
2009 bi->bi_op_search = ldif_back_search;
2010 bi->bi_op_compare = 0;
2011 bi->bi_op_modify = ldif_back_modify;
2012 bi->bi_op_modrdn = ldif_back_modrdn;
2013 bi->bi_op_add = ldif_back_add;
2014 bi->bi_op_delete = ldif_back_delete;
2015 bi->bi_op_abandon = 0;
2017 bi->bi_extended = 0;
2019 bi->bi_chk_referrals = ldif_back_referrals;
2021 bi->bi_connection_init = 0;
2022 bi->bi_connection_destroy = 0;
2024 bi->bi_entry_get_rw = ldif_back_entry_get;
2025 bi->bi_entry_release_rw = ldif_back_entry_release_rw;
2027 #if 0 /* NOTE: uncomment to completely disable access control */
2028 bi->bi_access_allowed = slap_access_always_allowed;
2031 bi->bi_tool_entry_open = ldif_tool_entry_open;
2032 bi->bi_tool_entry_close = ldif_tool_entry_close;
2033 bi->bi_tool_entry_first = backend_tool_entry_first;
2034 bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
2035 bi->bi_tool_entry_next = ldif_tool_entry_next;
2036 bi->bi_tool_dn2id_get = ldif_tool_dn2id_get;
2037 bi->bi_tool_entry_get = ldif_tool_entry_get;
2038 bi->bi_tool_entry_put = ldif_tool_entry_put;
2039 bi->bi_tool_entry_modify = ldif_tool_entry_modify;
2040 bi->bi_tool_entry_delete = ldif_tool_entry_delete;
2041 bi->bi_tool_entry_reindex = 0;
2042 bi->bi_tool_sync = 0;
2044 bi->bi_cf_ocs = ldifocs;
2046 rc = config_register_schema( ldifcfg, ldifocs );
2047 if ( rc ) return rc;