1 /* ldif.c - the ldif backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2011 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 */
62 #define mkdir(a,b) mkdir(a)
63 #define move_file(from, to) (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
65 #define move_file(from, to) rename(from, to)
67 #define move_dir(from, to) rename(from, to)
71 #define LDIF_FILETYPE_SEP '.' /* LDIF[0] */
74 * Unsafe/translated characters in the filesystem.
76 * LDIF_UNSAFE_CHAR(c) returns true if the character c is not to be used
77 * in relative filenames, except it should accept '\\', '{' and '}' even
78 * if unsafe. The value should be a constant expression.
80 * If '\\' is unsafe, #define LDIF_ESCAPE_CHAR as a safe character.
81 * If '{' and '}' are unsafe, #define IX_FSL/IX_FSR as safe characters.
82 * (Not digits, '-' or '+'. IX_FSL == IX_FSR is allowed.)
84 * Characters are escaped as LDIF_ESCAPE_CHAR followed by two hex digits,
85 * except '\\' is replaced with LDIF_ESCAPE_CHAR and {} with IX_FS[LR].
86 * Also some LDIF special chars are hex-escaped.
88 * Thus an LDIF filename is a valid normalized RDN (or suffix DN)
89 * followed by ".ldif", except with '\\' replaced with LDIF_ESCAPE_CHAR.
95 * Unix/MacOSX version. ':' vs '/' can cause confusion on MacOSX so we
96 * escape both. We escape them on Unix so both OS variants get the same
99 #define LDIF_ESCAPE_CHAR '\\'
100 #define LDIF_UNSAFE_CHAR(c) ((c) == '/' || (c) == ':')
104 /* Windows version - Microsoft's list of unsafe characters, except '\\' */
105 #define LDIF_ESCAPE_CHAR '^' /* Not '\\' (unsafe on Windows) */
106 #define LDIF_UNSAFE_CHAR(c) \
107 ((c) == '/' || (c) == ':' || \
108 (c) == '<' || (c) == '>' || (c) == '"' || \
109 (c) == '|' || (c) == '?' || (c) == '*')
114 * Left and Right "{num}" prefix to ordered RDNs ("olcDatabase={1}bdb").
115 * IX_DN* are for LDAP RDNs, IX_FS* for their .ldif filenames.
120 #define IX_FSL IX_DNL
121 #define IX_FSR IX_DNR
125 * Test for unsafe chars, as well as chars handled specially by back-ldif:
126 * - If the escape char is not '\\', it must itself be escaped. Otherwise
127 * '\\' and the escape char would map to the same character.
128 * - Escape the '.' in ".ldif", so the directory for an RDN that actually
129 * ends with ".ldif" can not conflict with a file of the same name. And
130 * since some OSes/programs choke on multiple '.'s, escape all of them.
131 * - If '{' and '}' are translated to some other characters, those
132 * characters must in turn be escaped when they occur in an RDN.
134 #ifndef LDIF_NEED_ESCAPE
135 #define LDIF_NEED_ESCAPE(c) \
136 ((LDIF_UNSAFE_CHAR(c)) || \
137 LDIF_MAYBE_UNSAFE(c, LDIF_ESCAPE_CHAR) || \
138 LDIF_MAYBE_UNSAFE(c, LDIF_FILETYPE_SEP) || \
139 LDIF_MAYBE_UNSAFE(c, IX_FSL) || \
140 (IX_FSR != IX_FSL && LDIF_MAYBE_UNSAFE(c, IX_FSR)))
143 * Helper macro for LDIF_NEED_ESCAPE(): Treat character x as unsafe if
144 * back-ldif does not already treat is specially.
146 #define LDIF_MAYBE_UNSAFE(c, x) \
147 (!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \
150 /* Collect other "safe char" tests here, until someone needs a fix. */
152 eq_unsafe = LDIF_UNSAFE_CHAR('='),
153 safe_filenames = STRLENOF("" LDAP_DIRSEP "") == 1 && !(
154 LDIF_UNSAFE_CHAR('-') || /* for "{-1}frontend" in bconfig.c */
155 LDIF_UNSAFE_CHAR(LDIF_ESCAPE_CHAR) ||
156 LDIF_UNSAFE_CHAR(IX_FSL) || LDIF_UNSAFE_CHAR(IX_FSR))
158 /* Sanity check: Try to force a compilation error if !safe_filenames */
160 int assert_safe_filenames : safe_filenames ? 2 : -2;
161 } assert_safe_filenames[safe_filenames ? 2 : -2];
164 static ConfigTable ldifcfg[] = {
165 { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
166 (void *)offsetof(struct ldif_info, li_base_path),
167 "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
168 "DESC 'Directory for database content' "
169 "EQUALITY caseIgnoreMatch "
170 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
171 { NULL, NULL, 0, 0, 0, ARG_IGNORED,
172 NULL, NULL, NULL, NULL }
175 static ConfigOCs ldifocs[] = {
177 "NAME 'olcLdifConfig' "
178 "DESC 'LDIF backend configuration' "
179 "SUP olcDatabaseConfig "
180 "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg },
186 * Handle file/directory names.
189 /* Set *res = LDIF filename path for the normalized DN */
191 ndn2path( Operation *op, struct berval *dn, struct berval *res, int empty_ok )
193 BackendDB *be = op->o_bd;
194 struct ldif_info *li = (struct ldif_info *) be->be_private;
195 struct berval *suffixdn = &be->be_nsuffix[0];
196 const char *start, *end, *next, *p;
199 static const char hex[] = "0123456789ABCDEF";
201 assert( dn != NULL );
202 assert( !BER_BVISNULL( dn ) );
203 assert( suffixdn != NULL );
204 assert( !BER_BVISNULL( suffixdn ) );
205 assert( dnIsSuffix( dn, suffixdn ) );
207 if ( dn->bv_len == 0 && !empty_ok ) {
208 return LDAP_UNWILLING_TO_PERFORM;
212 end = start + dn->bv_len;
214 /* Room for dir, dirsep, dn, LDIF, "\hexpair"-escaping of unsafe chars */
215 len = li->li_base_path.bv_len + dn->bv_len + (1 + STRLENOF( LDIF ));
216 for ( p = start; p < end; ) {
218 if ( LDIF_NEED_ESCAPE( ch ) )
221 res->bv_val = ch_malloc( len + 1 );
223 ptr = lutil_strcopy( res->bv_val, li->li_base_path.bv_val );
224 for ( next = end - suffixdn->bv_len; end > start; end = next ) {
225 /* Set p = start of DN component, next = &',' or start of DN */
226 while ( (p = next) > start ) {
228 if ( DN_SEPARATOR( *next ) )
231 /* Append <dirsep> <p..end-1: RDN or database-suffix> */
232 for ( *ptr++ = LDAP_DIRSEP[0]; p < end; *ptr++ = ch ) {
234 if ( LDIF_ESCAPE_CHAR != '\\' && ch == '\\' ) {
235 ch = LDIF_ESCAPE_CHAR;
236 } else if ( IX_FSL != IX_DNL && ch == IX_DNL ) {
238 } else if ( IX_FSR != IX_DNR && ch == IX_DNR ) {
240 } else if ( LDIF_NEED_ESCAPE( ch ) ) {
241 *ptr++ = LDIF_ESCAPE_CHAR;
242 *ptr++ = hex[(ch & 0xFFU) >> 4];
243 ch = hex[ch & 0x0FU];
247 ptr = lutil_strcopy( ptr, LDIF );
248 res->bv_len = ptr - res->bv_val;
250 assert( res->bv_len <= len );
256 * *dest = dupbv(<dir + LDAP_DIRSEP>), plus room for <more>-sized filename.
257 * Return pointer past the dirname.
260 fullpath_alloc( struct berval *dest, const struct berval *dir, ber_len_t more )
262 char *s = SLAP_MALLOC( dir->bv_len + more + 2 );
267 Debug( LDAP_DEBUG_ANY, "back-ldif: out of memory\n", 0, 0, 0 );
269 s = lutil_strcopy( dest->bv_val, dir->bv_val );
270 *s++ = LDAP_DIRSEP[0];
272 dest->bv_len = s - dest->bv_val;
278 * Append filename to fullpath_alloc() dirname or replace previous filename.
279 * dir_end = fullpath_alloc() return value.
281 #define FILL_PATH(fpath, dir_end, filename) \
282 ((fpath)->bv_len = lutil_strcopy(dir_end, filename) - (fpath)->bv_val)
285 /* .ldif entry filename length <-> subtree dirname length. */
286 #define ldif2dir_len(bv) ((bv).bv_len -= STRLENOF(LDIF))
287 #define dir2ldif_len(bv) ((bv).bv_len += STRLENOF(LDIF))
288 /* .ldif entry filename <-> subtree dirname, both with dirname length. */
289 #define ldif2dir_name(bv) ((bv).bv_val[(bv).bv_len] = '\0')
290 #define dir2ldif_name(bv) ((bv).bv_val[(bv).bv_len] = LDIF_FILETYPE_SEP)
292 /* Get the parent directory path, plus the LDIF suffix overwritten by a \0. */
294 get_parent_path( struct berval *dnpath, struct berval *res )
296 ber_len_t i = dnpath->bv_len;
298 while ( i > 0 && dnpath->bv_val[ --i ] != LDAP_DIRSEP[0] ) ;
302 res->bv_val = SLAP_MALLOC( i + 1 + STRLENOF(LDIF) );
303 if ( res->bv_val == NULL )
305 AC_MEMCPY( res->bv_val, dnpath->bv_val, i );
308 strcpy( res->bv_val + i, LDIF );
309 res->bv_val[i] = '\0';
313 /* Make temporary filename pattern for mkstemp() based on dnpath. */
315 ldif_tempname( const struct berval *dnpath )
317 static const char suffix[] = ".XXXXXX";
318 ber_len_t len = dnpath->bv_len - STRLENOF( LDIF );
319 char *name = SLAP_MALLOC( len + sizeof( suffix ) );
321 if ( name != NULL ) {
322 AC_MEMCPY( name, dnpath->bv_val, len );
323 strcpy( name + len, suffix );
328 /* CRC-32 table for the polynomial:
329 * 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.
334 static const unsigned int crctab[256] = {
335 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
336 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
337 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
338 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
339 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
340 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
341 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
342 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
343 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
344 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
345 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
346 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
347 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
348 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
349 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
350 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
351 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
352 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
353 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
354 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
355 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
356 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
357 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
358 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
359 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
360 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
361 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
362 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
363 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
364 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
365 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
366 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
367 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
368 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
369 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
370 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
371 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
372 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
373 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
374 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
375 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
376 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
377 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
378 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
379 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
380 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
381 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
382 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
383 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
384 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
385 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
389 #define CRC1 crc = crctab[(crc ^ *buf++) & 0xff] ^ (crc >> 8)
390 #define CRC8 CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1
391 unsigned int crc32(unsigned char *buf, int len)
393 unsigned int crc = 0xffffffff;
405 return crc ^ 0xffffffff;
409 * Read a file, or stat() it if datap == NULL. Allocate and fill *datap.
410 * Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error.
413 ldif_read_file( const char *path, char **datap )
416 int res = -1; /* 0:success, <0:error, >0:file too big/growing. */
418 char *data = NULL, *ptr;
420 if ( datap == NULL ) {
421 res = stat( path, &st );
424 fd = open( path, O_RDONLY );
426 if ( fstat( fd, &st ) == 0 ) {
427 if ( st.st_size > INT_MAX - 2 ) {
430 len = st.st_size + 1; /* +1 detects file size > st.st_size */
431 *datap = data = ptr = SLAP_MALLOC( len + 1 );
433 while ( len && (res = read( fd, ptr, len )) ) {
437 } else if ( errno != EINTR ) {
445 if ( close( fd ) < 0 )
451 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n",
452 datap ? "read entry file" : "entry file exists", path, 0 );
456 ptr = strstr( data, "\n# CRC32" );
458 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: no checksum \"%s\"\n",
461 unsigned int crc1 = 0, crc2 = 1;
462 if ( sscanf( ptr + 9, "%08x", &crc1) == 1) {
463 ptr = strchr(ptr+1, '\n');
467 crc2 = crc32( ptr, len );
470 if ( crc1 != crc2 ) {
471 Debug( LDAP_DEBUG_ANY, "ldif_read_file: checksum error on \"%s\"\n",
477 if ( res < 0 && errno == ENOENT ) {
478 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
479 "no entry file \"%s\"\n", path, 0, 0 );
480 rc = LDAP_NO_SUCH_OBJECT;
482 const char *msg = res < 0 ? STRERROR( errno ) : "bad stat() size";
483 Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
494 * return nonnegative for success or -1 for error
495 * do not return numbers less than -1
498 spew_file( int fd, const char *spew, int len, int *save_errno )
501 #define HEADER "# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n"
502 char header[sizeof(HEADER "# CRC32 12345678\n")];
504 sprintf(header, HEADER "# CRC32 %08x\n", crc32(spew, len));
505 writeres = write(fd, header, sizeof(header)-1);
507 writeres = write(fd, spew, len);
510 if (*save_errno != EINTR)
521 /* Write an entry LDIF file. Create parentdir first if non-NULL. */
526 const struct berval *path,
527 const char *parentdir,
530 int rc = LDAP_OTHER, res, save_errno = 0;
531 int fd, entry_length;
532 char *entry_as_string, *tmpfname;
535 return SLAPD_ABANDON;
537 if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
539 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
540 "cannot create parent directory",
541 parentdir, STRERROR( save_errno ) );
542 *text = "internal error (cannot create parent directory)";
546 tmpfname = ldif_tempname( path );
547 fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
550 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
551 "cannot create file", e->e_dn, STRERROR( save_errno ) );
552 *text = "internal error (cannot create file)";
555 ber_len_t dn_len = e->e_name.bv_len;
558 /* Only save the RDN onto disk */
559 dnRdn( &e->e_name, &rdn );
560 if ( rdn.bv_len != dn_len ) {
561 e->e_name.bv_val[rdn.bv_len] = '\0';
562 e->e_name.bv_len = rdn.bv_len;
566 ldap_pvt_thread_mutex_lock( &entry2str_mutex );
567 entry_as_string = entry2str( e, &entry_length );
568 if ( entry_as_string != NULL )
569 res = spew_file( fd, entry_as_string, entry_length, &save_errno );
570 ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
572 /* Restore full DN */
573 if ( rdn.bv_len != dn_len ) {
574 e->e_name.bv_val[rdn.bv_len] = ',';
575 e->e_name.bv_len = dn_len;
578 if ( close( fd ) < 0 && res >= 0 ) {
584 if ( move_file( tmpfname, path->bv_val ) == 0 ) {
585 Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
586 "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 );
590 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
591 "could not put entry file for \"%s\" in place: %s\n",
592 e->e_name.bv_val, STRERROR( save_errno ), 0 );
593 *text = "internal error (could not put entry file in place)";
595 } else if ( res == -1 ) {
596 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
597 "write error to", tmpfname, STRERROR( save_errno ) );
598 *text = "internal error (write error to entry file)";
601 if ( rc != LDAP_SUCCESS ) {
607 SLAP_FREE( tmpfname );
612 * Read the entry at path, or if entryp==NULL just see if it exists.
613 * pdn and pndn are the parent's DN and normalized DN, or both NULL.
614 * Return an LDAP result code.
627 char *entry_as_string;
630 /* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
631 * If so we need not check for LDAP_REQ_BIND here.
633 if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND )
634 return SLAPD_ABANDON;
636 rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
640 if ( entryp == NULL )
642 *entryp = entry = str2entry( entry_as_string );
643 SLAP_FREE( entry_as_string );
644 if ( entry == NULL ) {
647 *text = "internal error (cannot parse some entry file)";
650 if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
652 /* Append parent DN to DN from LDIF file */
654 build_new_dn( &entry->e_name, pdn, &rdn, NULL );
655 SLAP_FREE( rdn.bv_val );
656 rdn = entry->e_nname;
657 build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
658 SLAP_FREE( rdn.bv_val );
664 ? "internal error (cannot read some entry file)"
665 : "internal error (cannot stat some entry file)";
673 * Read the operation's entry, or if entryp==NULL just see if it exists.
674 * Return an LDAP result code. May set *text to a message on failure.
675 * If pathp is non-NULL, set it to the entry filename on success.
681 struct berval *pathp,
685 struct berval path, pdn, pndn;
687 dnParent( &op->o_req_dn, &pdn );
688 dnParent( &op->o_req_ndn, &pndn );
689 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
690 if ( rc != LDAP_SUCCESS ) {
694 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
696 if ( rc == LDAP_SUCCESS && pathp != NULL ) {
699 SLAP_FREE( path.bv_val );
707 * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
708 * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
709 * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
710 * Does not sort escaped chars correctly, would need to un-escape them.
712 typedef struct bvlist {
714 char *trunc; /* filename was truncated here */
715 int inum; /* num from "attr={num}" in filename, or INT_MIN */
716 char savech; /* original char at *trunc */
717 /* BVL_NAME(&bvlist) is the filename, allocated after the struct: */
718 # define BVL_NAME(bvl) ((char *) ((bvl) + 1))
719 # define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1)
723 ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
725 int rc = LDAP_SUCCESS;
727 if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
729 /* Save the entry for tool mode */
730 struct ldif_tool *tl =
731 &((struct ldif_info *) op->o_bd->be_private)->li_tool;
733 if ( tl->ecount >= tl->elen ) {
734 /* Allocate/grow entries */
735 ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
736 Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
737 sizeof(Entry *) * elen );
738 if ( entries == NULL ) {
739 Debug( LDAP_DEBUG_ANY,
740 "ldif_send_entry: out of memory\n", 0, 0, 0 );
745 tl->entries = entries;
747 tl->entries[tl->ecount++] = e;
751 else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
752 /* Send a continuation reference.
753 * (ldif_back_referrals() handles baseobject referrals.)
754 * Don't check the filter since it's only a candidate.
756 BerVarray refs = get_entry_referrals( op, e );
757 rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
759 rc = send_search_reference( op, rs );
760 ber_bvarray_free( rs->sr_ref );
761 ber_bvarray_free( refs );
766 else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
768 rs->sr_attrs = op->ors_attrs;
769 /* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
770 * but refraining lets us test unFREEable MODIFIABLE
771 * entries. Like entries built on the stack.
773 rs->sr_flags = REP_ENTRY_MODIFIABLE;
774 rc = send_search_entry( op, rs );
785 /* Read LDIF directory <path> into <listp>. Set *fname_maxlenp. */
790 const struct berval *path,
792 ber_len_t *fname_maxlenp )
794 int rc = LDAP_SUCCESS;
800 dir_of_path = opendir( path->bv_val );
801 if ( dir_of_path == NULL ) {
802 int save_errno = errno;
803 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
804 int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
806 /* Absent directory is OK (leaf entry), except the database dir */
807 if ( is_rootDSE || save_errno != ENOENT ) {
808 Debug( LDAP_DEBUG_ANY,
809 "=> ldif_search_entry: failed to opendir \"%s\": %s\n",
810 path->bv_val, STRERROR( save_errno ), 0 );
814 save_errno != ENOENT ? "internal error (bad directory)"
815 : !is_rootDSE ? "internal error (missing directory)"
816 : "internal error (database directory does not exist)";
824 while ( (dir = readdir( dir_of_path )) != NULL ) {
827 char *trunc, *idxp, *endp, *endp2;
829 fname_len = strlen( dir->d_name );
830 if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
832 if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
835 if ( *fname_maxlenp < fname_len )
836 *fname_maxlenp = fname_len;
838 bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
844 strcpy( BVL_NAME( bvl ), dir->d_name );
846 /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
847 trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
848 if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
849 (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
850 (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
852 /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
853 bvl->inum = strtol( idxp, &endp2, 10 );
854 if ( endp2 == endp ) {
862 bvl->savech = *trunc;
866 for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
867 int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
868 if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
875 if ( closedir( dir_of_path ) < 0 ) {
879 rs->sr_text = "internal error (bad directory)";
881 if ( rc != LDAP_SUCCESS ) {
882 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
883 "error reading directory", path->bv_val,
884 STRERROR( save_errno ) );
892 * Send an entry, recursively search its children, and free or save it.
893 * Return an LDAP result code. Parameters:
894 * op, rs operation and reply. rs == NULL for slap tools.
895 * e entry to search, or NULL for rootDSE.
896 * scope scope for the part of the search from this entry.
897 * path LDIF filename -- bv_len and non-directory part are overwritten.
905 struct berval *path )
907 int rc = LDAP_SUCCESS;
908 struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
910 if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
911 /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
912 * which bconfig.c seems to need. (TODO: see config_rename_one.)
914 if ( ber_dupbv( &dn, &e->e_name ) == NULL ||
915 ber_dupbv( &ndn, &e->e_nname ) == NULL )
917 Debug( LDAP_DEBUG_ANY,
918 "ldif_search_entry: out of memory\n", 0, 0, 0 );
924 /* Send the entry if appropriate, and free or save it */
926 rc = ldif_send_entry( op, rs, e, scope );
928 /* Search the children */
929 if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
931 struct berval fpath; /* becomes child pathname */
932 char *dir_end; /* will point past dirname in fpath */
934 ldif2dir_len( *path );
935 ldif2dir_name( *path );
936 rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
938 if ( list != NULL ) {
939 const char **text = rs == NULL ? NULL : &rs->sr_text;
941 if ( scope == LDAP_SCOPE_ONELEVEL )
942 scope = LDAP_SCOPE_BASE;
943 else if ( scope == LDAP_SCOPE_SUBORDINATE )
944 scope = LDAP_SCOPE_SUBTREE;
946 /* Allocate fpath and fill in directory part */
947 dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
948 if ( dir_end == NULL )
954 if ( rc == LDAP_SUCCESS ) {
955 *ptr->trunc = ptr->savech;
956 FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
958 rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
962 rc = ldif_search_entry( op, rs, e, scope, &fpath );
964 case LDAP_NO_SUCH_OBJECT:
965 /* Only the search baseDN may produce noSuchObject. */
968 rs->sr_text = "internal error "
969 "(did someone just remove an entry file?)";
970 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
971 "file listed in parent directory does not exist: "
972 "\"%s\"\n", fpath.bv_val, 0, 0 );
979 } while ( list != NULL );
981 if ( !BER_BVISNULL( &fpath ) )
982 SLAP_FREE( fpath.bv_val );
987 if ( !BER_BVISEMPTY( &dn ) )
988 ber_memfree( dn.bv_val );
989 if ( !BER_BVISEMPTY( &ndn ) )
990 ber_memfree( ndn.bv_val );
995 search_tree( Operation *op, SlapReply *rs )
997 int rc = LDAP_SUCCESS;
1000 struct berval pdn, pndn;
1002 (void) ndn2path( op, &op->o_req_ndn, &path, 1 );
1003 if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
1004 /* Read baseObject */
1005 dnParent( &op->o_req_dn, &pdn );
1006 dnParent( &op->o_req_ndn, &pndn );
1007 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
1008 rs == NULL ? NULL : &rs->sr_text );
1010 if ( rc == LDAP_SUCCESS )
1011 rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
1013 ch_free( path.bv_val );
1019 * Prepare to create or rename an entry:
1020 * Check that the entry does not already exist.
1021 * Check that the parent entry exists and can have subordinates,
1022 * unless need_dir is NULL or adding the suffix entry.
1024 * Return an LDAP result code. May set *text to a message on failure.
1025 * If success, set *dnpath to LDIF entry path and *need_dir to
1026 * (directory must be created ? dirname : NULL).
1029 ldif_prepare_create(
1032 struct berval *dnpath,
1036 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1037 struct berval *ndn = &e->e_nname;
1038 struct berval ppath = BER_BVNULL;
1040 Entry *parent = NULL;
1043 if ( op->o_abandon )
1044 return SLAPD_ABANDON;
1046 rc = ndn2path( op, ndn, dnpath, 0 );
1047 if ( rc != LDAP_SUCCESS ) {
1051 if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
1052 rc = LDAP_ALREADY_EXISTS;
1054 } else if ( errno != ENOENT ) {
1055 Debug( LDAP_DEBUG_ANY,
1056 "ldif_prepare_create: cannot stat \"%s\": %s\n",
1057 dnpath->bv_val, STRERROR( errno ), 0 );
1059 *text = "internal error (cannot check entry file)";
1061 } else if ( need_dir != NULL ) {
1063 rc = get_parent_path( dnpath, &ppath );
1064 /* If parent dir exists, so does parent .ldif:
1065 * The directory gets created after and removed before the .ldif.
1066 * Except with the database directory, which has no matching entry.
1068 if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
1069 rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
1070 ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
1073 case LDAP_NO_SUCH_OBJECT:
1074 /* No parent dir, check parent .ldif */
1075 dir2ldif_name( ppath );
1076 rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
1077 (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
1082 /* Check that parent is not a referral, unless
1083 * ldif_back_referrals() already checked.
1085 if ( parent != NULL ) {
1086 int is_ref = is_entry_referral( parent );
1087 entry_free( parent );
1089 rc = LDAP_AFFECTS_MULTIPLE_DSAS;
1090 *text = op->o_tag == LDAP_REQ_MODDN
1091 ? "newSuperior is a referral object"
1092 : "parent is a referral object";
1096 /* Must create parent directory. */
1097 ldif2dir_name( ppath );
1098 *need_dir = ppath.bv_val;
1100 case LDAP_NO_SUCH_OBJECT:
1101 *text = op->o_tag == LDAP_REQ_MODDN
1102 ? "newSuperior object does not exist"
1103 : "parent does not exist";
1108 Debug( LDAP_DEBUG_ANY,
1109 "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
1110 ndn->bv_val, STRERROR( errno ), 0 );
1111 *text = "internal error (cannot stat parent dir)";
1114 if ( *need_dir == NULL && ppath.bv_val != NULL )
1115 SLAP_FREE( ppath.bv_val );
1118 if ( rc != LDAP_SUCCESS ) {
1119 SLAP_FREE( dnpath->bv_val );
1120 BER_BVZERO( dnpath );
1126 apply_modify_to_entry(
1128 Modifications *modlist,
1133 int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
1137 if (!acl_check_modlist(op, entry, modlist)) {
1138 return LDAP_INSUFFICIENT_ACCESS;
1141 for (; modlist != NULL; modlist = modlist->sml_next) {
1142 mods = &modlist->sml_mod;
1144 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
1147 switch (mods->sm_op) {
1149 rc = modify_add_values(entry, mods,
1150 get_permissiveModify(op),
1151 &rs->sr_text, textbuf,
1155 case LDAP_MOD_DELETE:
1156 rc = modify_delete_values(entry, mods,
1157 get_permissiveModify(op),
1158 &rs->sr_text, textbuf,
1162 case LDAP_MOD_REPLACE:
1163 rc = modify_replace_values(entry, mods,
1164 get_permissiveModify(op),
1165 &rs->sr_text, textbuf,
1169 case LDAP_MOD_INCREMENT:
1170 rc = modify_increment_values( entry,
1171 mods, get_permissiveModify(op),
1172 &rs->sr_text, textbuf,
1176 case SLAP_MOD_SOFTADD:
1177 mods->sm_op = LDAP_MOD_ADD;
1178 rc = modify_add_values(entry, mods,
1179 get_permissiveModify(op),
1180 &rs->sr_text, textbuf,
1182 mods->sm_op = SLAP_MOD_SOFTADD;
1183 if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
1188 case SLAP_MOD_SOFTDEL:
1189 mods->sm_op = LDAP_MOD_DELETE;
1190 rc = modify_delete_values(entry, mods,
1191 get_permissiveModify(op),
1192 &rs->sr_text, textbuf,
1194 mods->sm_op = SLAP_MOD_SOFTDEL;
1195 if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
1200 case SLAP_MOD_ADD_IF_NOT_PRESENT:
1201 if ( attr_find( entry->e_attrs, mods->sm_desc ) ) {
1205 mods->sm_op = LDAP_MOD_ADD;
1206 rc = modify_add_values(entry, mods,
1207 get_permissiveModify(op),
1208 &rs->sr_text, textbuf,
1210 mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
1213 if(rc != LDAP_SUCCESS) break;
1216 if ( rc == LDAP_SUCCESS ) {
1217 rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
1219 entry->e_ocflags = 0;
1221 /* check that the entry still obeys the schema */
1222 rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
1223 &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN );
1231 ldif_back_referrals( Operation *op, SlapReply *rs )
1233 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1234 struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn;
1235 ber_len_t min_dnlen;
1236 Entry *entry = NULL, **entryp;
1240 min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
1241 if ( min_dnlen == 0 ) {
1242 /* Catch root DSE (empty DN), it is not a referral */
1245 if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) {
1246 return LDAP_SUCCESS; /* Root DSE again */
1249 entryp = get_manageDSAit( op ) ? NULL : &entry;
1250 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1253 dnParent( &dn, &dn );
1254 dnParent( &ndn, &ndn );
1255 rc = ldif_read_entry( op, path.bv_val, &dn, &ndn,
1256 entryp, &rs->sr_text );
1257 if ( rc != LDAP_NO_SUCH_OBJECT )
1261 if ( ndn.bv_len < min_dnlen )
1263 (void) get_parent_path( &path, NULL );
1264 dir2ldif_name( path );
1268 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1269 SLAP_FREE( path.bv_val );
1271 if ( entry != NULL ) {
1272 if ( is_entry_referral( entry ) ) {
1273 Debug( LDAP_DEBUG_TRACE,
1274 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
1275 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn );
1277 ref = get_entry_referrals( op, entry );
1278 rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn,
1279 op->o_tag == LDAP_REQ_SEARCH ?
1280 op->ors_scope : LDAP_SCOPE_DEFAULT );
1281 ber_bvarray_free( ref );
1283 if ( rs->sr_ref != NULL ) {
1285 rc = rs->sr_err = LDAP_REFERRAL;
1286 rs->sr_matched = entry->e_dn;
1287 send_ldap_result( op, rs );
1288 ber_bvarray_free( rs->sr_ref );
1292 rs->sr_text = "bad referral object";
1294 rs->sr_matched = NULL;
1297 entry_free( entry );
1304 /* LDAP operations */
1307 ldif_back_bind( Operation *op, SlapReply *rs )
1309 struct ldif_info *li;
1311 AttributeDescription *password = slap_schema.si_ad_userPassword;
1313 Entry *entry = NULL;
1315 switch ( be_rootdn_bind( op, rs ) ) {
1316 case SLAP_CB_CONTINUE:
1320 /* in case of success, front end will send result;
1321 * otherwise, be_rootdn_bind() did */
1325 li = (struct ldif_info *) op->o_bd->be_private;
1326 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1327 return_val = get_entry(op, &entry, NULL, NULL);
1329 /* no object is found for them */
1330 if(return_val != LDAP_SUCCESS) {
1331 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
1335 /* they don't have userpassword */
1336 if((a = attr_find(entry->e_attrs, password)) == NULL) {
1337 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1342 /* authentication actually failed */
1343 if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
1344 &rs->sr_text) != 0) {
1345 rs->sr_err = LDAP_INVALID_CREDENTIALS;
1350 /* let the front-end send success */
1351 return_val = LDAP_SUCCESS;
1354 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1355 if(return_val != LDAP_SUCCESS)
1356 send_ldap_result( op, rs );
1363 ldif_back_search( Operation *op, SlapReply *rs )
1365 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1367 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
1368 rs->sr_err = search_tree( op, rs );
1369 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
1370 send_ldap_result(op, rs);
1376 ldif_back_add( Operation *op, SlapReply *rs )
1378 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1379 Entry * e = op->ora_e;
1382 char textbuf[SLAP_TEXT_BUFLEN];
1385 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
1387 rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
1388 &rs->sr_text, textbuf, sizeof( textbuf ) );
1389 if ( rc != LDAP_SUCCESS )
1392 rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
1393 if ( rc != LDAP_SUCCESS )
1396 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1398 rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
1399 if ( rc == LDAP_SUCCESS ) {
1400 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1401 rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
1402 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1404 SLAP_FREE( path.bv_val );
1405 if ( parentdir != NULL )
1406 SLAP_FREE( parentdir );
1409 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1413 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
1414 rc, rs->sr_text ? rs->sr_text : "", 0 );
1415 send_ldap_result( op, rs );
1416 slap_graduate_commit_csn( op );
1417 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1422 ldif_back_modify( Operation *op, SlapReply *rs )
1424 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1425 Modifications * modlst = op->orm_modlist;
1428 char textbuf[SLAP_TEXT_BUFLEN];
1431 slap_mods_opattrs( op, &op->orm_modlist, 1 );
1433 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1435 rc = get_entry( op, &entry, &path, &rs->sr_text );
1436 if ( rc == LDAP_SUCCESS ) {
1437 rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
1438 if ( rc == LDAP_SUCCESS ) {
1439 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1440 rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
1441 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1444 entry_free( entry );
1445 SLAP_FREE( path.bv_val );
1448 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1451 send_ldap_result( op, rs );
1452 slap_graduate_commit_csn( op );
1453 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1458 ldif_back_delete( Operation *op, SlapReply *rs )
1460 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1462 int rc = LDAP_SUCCESS;
1464 if ( BER_BVISEMPTY( &op->o_csn )) {
1466 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
1468 csn.bv_val = csnbuf;
1469 csn.bv_len = sizeof( csnbuf );
1470 slap_get_csn( op, &csn, 1 );
1473 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1474 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1475 if ( op->o_abandon ) {
1480 rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
1481 if ( rc != LDAP_SUCCESS ) {
1485 ldif2dir_len( path );
1486 ldif2dir_name( path );
1487 if ( rmdir( path.bv_val ) < 0 ) {
1490 rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
1493 /* is leaf, go on */
1497 rs->sr_text = "internal error (cannot delete subtree directory)";
1502 if ( rc == LDAP_SUCCESS ) {
1503 dir2ldif_name( path );
1504 if ( unlink( path.bv_val ) < 0 ) {
1505 rc = LDAP_NO_SUCH_OBJECT;
1506 if ( errno != ENOENT ) {
1508 rs->sr_text = "internal error (cannot delete entry file)";
1513 if ( rc == LDAP_OTHER ) {
1514 Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
1515 "cannot delete", path.bv_val, STRERROR( errno ) );
1518 SLAP_FREE( path.bv_val );
1520 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1521 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1523 send_ldap_result( op, rs );
1524 slap_graduate_commit_csn( op );
1534 struct berval *oldpath,
1537 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1538 struct berval newpath;
1539 char *parentdir = NULL, *trash;
1546 rc = ldif_prepare_create( op, entry, &newpath,
1547 op->orr_newSup ? &parentdir : NULL, text );
1550 if ( rc == LDAP_SUCCESS ) {
1551 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1553 rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
1554 if ( rc == LDAP_SUCCESS && !same_ndn ) {
1555 trash = oldpath->bv_val; /* will be .ldif file to delete */
1556 ldif2dir_len( newpath );
1557 ldif2dir_len( *oldpath );
1558 /* Move subdir before deleting old entry,
1559 * so .ldif always exists if subdir does.
1561 ldif2dir_name( newpath );
1562 ldif2dir_name( *oldpath );
1563 rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
1564 if ( rename_res != 0 && errno != ENOENT ) {
1566 *text = "internal error (cannot move this subtree)";
1567 trash = newpath.bv_val;
1570 /* Delete old entry, or if error undo change */
1572 dir2ldif_name( newpath );
1573 dir2ldif_name( *oldpath );
1574 if ( unlink( trash ) == 0 )
1576 if ( rc == LDAP_SUCCESS ) {
1577 /* Prepare to undo change and return failure */
1579 *text = "internal error (cannot move this entry)";
1580 trash = newpath.bv_val;
1581 if ( rename_res != 0 )
1583 /* First move subdirectory back */
1584 ldif2dir_name( newpath );
1585 ldif2dir_name( *oldpath );
1586 if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
1589 *text = "added new but couldn't delete old entry!";
1593 if ( rc != LDAP_SUCCESS ) {
1595 snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
1596 Debug( LDAP_DEBUG_ANY,
1597 "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
1598 s, op->o_req_dn.bv_val, entry->e_dn );
1602 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1604 SLAP_FREE( newpath.bv_val );
1605 if ( parentdir != NULL )
1606 SLAP_FREE( parentdir );
1613 ldif_back_modrdn( Operation *op, SlapReply *rs )
1615 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1616 struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1617 struct berval p_dn, old_path;
1619 char textbuf[SLAP_TEXT_BUFLEN];
1622 slap_mods_opattrs( op, &op->orr_modlist, 1 );
1624 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
1626 rc = get_entry( op, &entry, &old_path, &rs->sr_text );
1627 if ( rc == LDAP_SUCCESS ) {
1628 /* build new dn, and new ndn for the entry */
1629 if ( op->oq_modrdn.rs_newSup != NULL ) {
1630 p_dn = *op->oq_modrdn.rs_newSup;
1632 dnParent( &entry->e_name, &p_dn );
1634 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
1635 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1636 same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
1637 ber_memfree_x( entry->e_name.bv_val, NULL );
1638 ber_memfree_x( entry->e_nname.bv_val, NULL );
1639 entry->e_name = new_dn;
1640 entry->e_nname = new_ndn;
1642 /* perform the modifications */
1643 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
1644 if ( rc == LDAP_SUCCESS )
1645 rc = ldif_move_entry( op, entry, same_ndn, &old_path,
1648 entry_free( entry );
1649 SLAP_FREE( old_path.bv_val );
1652 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
1654 send_ldap_result( op, rs );
1655 slap_graduate_commit_csn( op );
1656 rs->sr_text = NULL; /* remove possible pointer to textbuf */
1661 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1663 ldif_back_entry_get(
1667 AttributeDescription *at,
1671 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1672 struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1675 assert( ndn != NULL );
1676 assert( !BER_BVISNULL( ndn ) );
1678 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1679 op->o_req_dn = *ndn;
1680 op->o_req_ndn = *ndn;
1681 rc = get_entry( op, e, NULL, NULL );
1682 op->o_req_dn = op_dn;
1683 op->o_req_ndn = op_ndn;
1684 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1686 if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1687 rc = LDAP_NO_SUCH_ATTRIBUTE;
1699 ldif_tool_entry_open( BackendDB *be, int mode )
1701 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1708 ldif_tool_entry_close( BackendDB *be )
1710 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1711 Entry **entries = tl->entries;
1714 for ( i = tl->ecount; i--; )
1716 entry_free( entries[i] );
1717 SLAP_FREE( entries );
1719 tl->ecount = tl->elen = 0;
1724 ldif_tool_entry_next( BackendDB *be )
1726 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1729 Entry *e = tl->entries[ tl->ecurrent ];
1731 if ( tl->ecurrent >= tl->ecount ) {
1737 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
1741 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter ) != LDAP_COMPARE_TRUE ) {
1748 return tl->ecurrent;
1752 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
1754 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1757 tl->tl_scope = scope;
1760 if ( tl->entries == NULL ) {
1764 op.o_req_dn = *be->be_suffix;
1765 op.o_req_ndn = *be->be_nsuffix;
1766 op.ors_scope = LDAP_SCOPE_SUBTREE;
1767 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
1768 tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
1769 return 0; /* fail ldif_tool_entry_get() */
1772 return ldif_tool_entry_next( be );
1776 ldif_tool_entry_get( BackendDB *be, ID id )
1778 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
1782 if ( id < tl->ecount ) {
1783 e = tl->entries[id];
1784 tl->entries[id] = NULL;
1790 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
1793 const char *errmsg = NULL;
1799 rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
1800 if ( rc == LDAP_SUCCESS ) {
1801 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
1803 SLAP_FREE( path.bv_val );
1804 if ( parentdir != NULL )
1805 SLAP_FREE( parentdir );
1806 if ( rc == LDAP_SUCCESS )
1810 if ( errmsg == NULL && rc != LDAP_OTHER )
1811 errmsg = ldap_err2string( rc );
1812 if ( errmsg != NULL )
1813 snprintf( text->bv_val, text->bv_len, "%s", errmsg );
1821 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1823 struct ldif_info *li;
1825 li = ch_calloc( 1, sizeof(struct ldif_info) );
1826 be->be_private = li;
1827 be->be_cf_ocs = ldifocs;
1828 ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
1829 ldap_pvt_thread_rdwr_init( &li->li_rdwr );
1830 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1835 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1837 struct ldif_info *li = be->be_private;
1839 ch_free( li->li_base_path.bv_val );
1840 ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
1841 ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
1842 free( be->be_private );
1847 ldif_back_db_open( Backend *be, ConfigReply *cr )
1849 struct ldif_info *li = (struct ldif_info *) be->be_private;
1850 if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1851 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1858 ldif_back_initialize( BackendInfo *bi )
1860 static char *controls[] = {
1861 LDAP_CONTROL_MANAGEDSAIT,
1867 SLAP_BFLAG_INCREMENT |
1868 SLAP_BFLAG_REFERRALS;
1870 bi->bi_controls = controls;
1877 bi->bi_db_init = ldif_back_db_init;
1878 bi->bi_db_config = config_generic_wrapper;
1879 bi->bi_db_open = ldif_back_db_open;
1880 bi->bi_db_close = 0;
1881 bi->bi_db_destroy = ldif_back_db_destroy;
1883 bi->bi_op_bind = ldif_back_bind;
1884 bi->bi_op_unbind = 0;
1885 bi->bi_op_search = ldif_back_search;
1886 bi->bi_op_compare = 0;
1887 bi->bi_op_modify = ldif_back_modify;
1888 bi->bi_op_modrdn = ldif_back_modrdn;
1889 bi->bi_op_add = ldif_back_add;
1890 bi->bi_op_delete = ldif_back_delete;
1891 bi->bi_op_abandon = 0;
1893 bi->bi_extended = 0;
1895 bi->bi_chk_referrals = ldif_back_referrals;
1897 bi->bi_connection_init = 0;
1898 bi->bi_connection_destroy = 0;
1900 bi->bi_entry_get_rw = ldif_back_entry_get;
1902 #if 0 /* NOTE: uncomment to completely disable access control */
1903 bi->bi_access_allowed = slap_access_always_allowed;
1906 bi->bi_tool_entry_open = ldif_tool_entry_open;
1907 bi->bi_tool_entry_close = ldif_tool_entry_close;
1908 bi->bi_tool_entry_first = backend_tool_entry_first;
1909 bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
1910 bi->bi_tool_entry_next = ldif_tool_entry_next;
1911 bi->bi_tool_entry_get = ldif_tool_entry_get;
1912 bi->bi_tool_entry_put = ldif_tool_entry_put;
1913 bi->bi_tool_entry_reindex = 0;
1914 bi->bi_tool_sync = 0;
1916 bi->bi_tool_dn2id_get = 0;
1917 bi->bi_tool_entry_modify = 0;
1919 bi->bi_cf_ocs = ldifocs;
1921 rc = config_register_schema( ldifcfg, ldifocs );
1922 if ( rc ) return rc;