Back to index

openldap  2.4.31
ldif.c
Go to the documentation of this file.
00001 /* ldif.c - the ldif backend */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2005-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS:
00017  * This work was originally developed by Eric Stokes for inclusion
00018  * in OpenLDAP Software.
00019  */
00020 
00021 #include "portable.h"
00022 #include <stdio.h>
00023 #include <ac/string.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <ac/dirent.h>
00027 #include <fcntl.h>
00028 #include <ac/errno.h>
00029 #include <ac/unistd.h>
00030 #include "slap.h"
00031 #include "lutil.h"
00032 #include "config.h"
00033 
00034 struct ldif_tool {
00035        Entry  **entries;                  /* collected by bi_tool_entry_first() */
00036        ID            elen;                       /* length of entries[] array */
00037        ID            ecount;                            /* number of entries */
00038        ID            ecurrent;                   /* bi_tool_entry_next() position */
00039 #      define ENTRY_BUFF_INCREMENT 500 /* initial entries[] length */
00040        struct berval *tl_base;
00041        int           tl_scope;
00042        Filter        *tl_filter;
00043 };
00044 
00045 /* Per-database data */
00046 struct ldif_info {
00047        struct berval li_base_path;               /* database directory */
00048        struct ldif_tool li_tool;                 /* for slap tools */
00049        /*
00050         * Read-only LDAP requests readlock li_rdwr for filesystem input.
00051         * Update requests first lock li_modop_mutex for filesystem I/O,
00052         * and then writelock li_rdwr as well for filesystem output.
00053         * This allows update requests to do callbacks that acquire
00054         * read locks, e.g. access controls that inspect entries.
00055         * (An alternative would be recursive read/write locks.)
00056         */
00057        ldap_pvt_thread_mutex_t     li_modop_mutex; /* serialize update requests */
00058        ldap_pvt_thread_rdwr_t      li_rdwr;      /* no other I/O when writing */
00059 };
00060 
00061 static int write_data( int fd, const char *spew, int len, int *save_errno );
00062 
00063 #ifdef _WIN32
00064 #define mkdir(a,b)   mkdir(a)
00065 #define move_file(from, to) (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
00066 #else
00067 #define move_file(from, to) rename(from, to)
00068 #endif
00069 #define move_dir(from, to) rename(from, to)
00070 
00071 
00072 #define LDIF  ".ldif"
00073 #define LDIF_FILETYPE_SEP   '.'                  /* LDIF[0] */
00074 
00075 /*
00076  * Unsafe/translated characters in the filesystem.
00077  *
00078  * LDIF_UNSAFE_CHAR(c) returns true if the character c is not to be used
00079  * in relative filenames, except it should accept '\\', '{' and '}' even
00080  * if unsafe.  The value should be a constant expression.
00081  *
00082  * If '\\' is unsafe, #define LDIF_ESCAPE_CHAR as a safe character.
00083  * If '{' and '}' are unsafe, #define IX_FSL/IX_FSR as safe characters.
00084  * (Not digits, '-' or '+'.  IX_FSL == IX_FSR is allowed.)
00085  *
00086  * Characters are escaped as LDIF_ESCAPE_CHAR followed by two hex digits,
00087  * except '\\' is replaced with LDIF_ESCAPE_CHAR and {} with IX_FS[LR].
00088  * Also some LDIF special chars are hex-escaped.
00089  *
00090  * Thus an LDIF filename is a valid normalized RDN (or suffix DN)
00091  * followed by ".ldif", except with '\\' replaced with LDIF_ESCAPE_CHAR.
00092  */
00093 
00094 #ifndef _WIN32
00095 
00096 /*
00097  * Unix/MacOSX version.  ':' vs '/' can cause confusion on MacOSX so we
00098  * escape both.  We escape them on Unix so both OS variants get the same
00099  * filenames.
00100  */
00101 #define LDIF_ESCAPE_CHAR    '\\'
00102 #define LDIF_UNSAFE_CHAR(c) ((c) == '/' || (c) == ':')
00103 
00104 #else /* _WIN32 */
00105 
00106 /* Windows version - Microsoft's list of unsafe characters, except '\\' */
00107 #define LDIF_ESCAPE_CHAR    '^'                  /* Not '\\' (unsafe on Windows) */
00108 #define LDIF_UNSAFE_CHAR(c) \
00109        ((c) == '/' || (c) == ':' || \
00110         (c) == '<' || (c) == '>' || (c) == '"' || \
00111         (c) == '|' || (c) == '?' || (c) == '*')
00112 
00113 #endif /* !_WIN32 */
00114 
00115 /*
00116  * Left and Right "{num}" prefix to ordered RDNs ("olcDatabase={1}bdb").
00117  * IX_DN* are for LDAP RDNs, IX_FS* for their .ldif filenames.
00118  */
00119 #define IX_DNL       '{'
00120 #define       IX_DNR '}'
00121 #ifndef IX_FSL
00122 #define       IX_FSL IX_DNL
00123 #define IX_FSR       IX_DNR
00124 #endif
00125 
00126 /*
00127  * Test for unsafe chars, as well as chars handled specially by back-ldif:
00128  * - If the escape char is not '\\', it must itself be escaped.  Otherwise
00129  *   '\\' and the escape char would map to the same character.
00130  * - Escape the '.' in ".ldif", so the directory for an RDN that actually
00131  *   ends with ".ldif" can not conflict with a file of the same name.  And
00132  *   since some OSes/programs choke on multiple '.'s, escape all of them.
00133  * - If '{' and '}' are translated to some other characters, those
00134  *   characters must in turn be escaped when they occur in an RDN.
00135  */
00136 #ifndef LDIF_NEED_ESCAPE
00137 #define       LDIF_NEED_ESCAPE(c) \
00138        ((LDIF_UNSAFE_CHAR(c)) || \
00139         LDIF_MAYBE_UNSAFE(c, LDIF_ESCAPE_CHAR) || \
00140         LDIF_MAYBE_UNSAFE(c, LDIF_FILETYPE_SEP) || \
00141         LDIF_MAYBE_UNSAFE(c, IX_FSL) || \
00142         (IX_FSR != IX_FSL && LDIF_MAYBE_UNSAFE(c, IX_FSR)))
00143 #endif
00144 /*
00145  * Helper macro for LDIF_NEED_ESCAPE(): Treat character x as unsafe if
00146  * back-ldif does not already treat is specially.
00147  */
00148 #define LDIF_MAYBE_UNSAFE(c, x) \
00149        (!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \
00150         && (c) == (x))
00151 
00152 /* Collect other "safe char" tests here, until someone needs a fix. */
00153 enum {
00154        eq_unsafe = LDIF_UNSAFE_CHAR('='),
00155        safe_filenames = STRLENOF("" LDAP_DIRSEP "") == 1 && !(
00156               LDIF_UNSAFE_CHAR('-') || /* for "{-1}frontend" in bconfig.c */
00157               LDIF_UNSAFE_CHAR(LDIF_ESCAPE_CHAR) ||
00158               LDIF_UNSAFE_CHAR(IX_FSL) || LDIF_UNSAFE_CHAR(IX_FSR))
00159 };
00160 /* Sanity check: Try to force a compilation error if !safe_filenames */
00161 typedef struct {
00162        int assert_safe_filenames : safe_filenames ? 2 : -2;
00163 } assert_safe_filenames[safe_filenames ? 2 : -2];
00164 
00165 
00166 static ConfigTable ldifcfg[] = {
00167        { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
00168               (void *)offsetof(struct ldif_info, li_base_path),
00169               "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
00170                      "DESC 'Directory for database content' "
00171                      "EQUALITY caseIgnoreMatch "
00172                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00173        { NULL, NULL, 0, 0, 0, ARG_IGNORED,
00174               NULL, NULL, NULL, NULL }
00175 };
00176 
00177 static ConfigOCs ldifocs[] = {
00178        { "( OLcfgDbOc:2.1 "
00179               "NAME 'olcLdifConfig' "
00180               "DESC 'LDIF backend configuration' "
00181               "SUP olcDatabaseConfig "
00182               "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg },
00183        { NULL, 0, NULL }
00184 };
00185 
00186 
00187 /*
00188  * Handle file/directory names.
00189  */
00190 
00191 /* Set *res = LDIF filename path for the normalized DN */
00192 static int
00193 ndn2path( Operation *op, struct berval *dn, struct berval *res, int empty_ok )
00194 {
00195        BackendDB *be = op->o_bd;
00196        struct ldif_info *li = (struct ldif_info *) be->be_private;
00197        struct berval *suffixdn = &be->be_nsuffix[0];
00198        const char *start, *end, *next, *p;
00199        char ch, *ptr;
00200        ber_len_t len;
00201        static const char hex[] = "0123456789ABCDEF";
00202 
00203        assert( dn != NULL );
00204        assert( !BER_BVISNULL( dn ) );
00205        assert( suffixdn != NULL );
00206        assert( !BER_BVISNULL( suffixdn ) );
00207        assert( dnIsSuffix( dn, suffixdn ) );
00208 
00209        if ( dn->bv_len == 0 && !empty_ok ) {
00210               return LDAP_UNWILLING_TO_PERFORM;
00211        }
00212 
00213        start = dn->bv_val;
00214        end = start + dn->bv_len;
00215 
00216        /* Room for dir, dirsep, dn, LDIF, "\hexpair"-escaping of unsafe chars */
00217        len = li->li_base_path.bv_len + dn->bv_len + (1 + STRLENOF( LDIF ));
00218        for ( p = start; p < end; ) {
00219               ch = *p++;
00220               if ( LDIF_NEED_ESCAPE( ch ) )
00221                      len += 2;
00222        }
00223        res->bv_val = ch_malloc( len + 1 );
00224 
00225        ptr = lutil_strcopy( res->bv_val, li->li_base_path.bv_val );
00226        for ( next = end - suffixdn->bv_len; end > start; end = next ) {
00227               /* Set p = start of DN component, next = &',' or start of DN */
00228               while ( (p = next) > start ) {
00229                      --next;
00230                      if ( DN_SEPARATOR( *next ) )
00231                             break;
00232               }
00233               /* Append <dirsep> <p..end-1: RDN or database-suffix> */
00234               for ( *ptr++ = LDAP_DIRSEP[0]; p < end; *ptr++ = ch ) {
00235                      ch = *p++;
00236                      if ( LDIF_ESCAPE_CHAR != '\\' && ch == '\\' ) {
00237                             ch = LDIF_ESCAPE_CHAR;
00238                      } else if ( IX_FSL != IX_DNL && ch == IX_DNL ) {
00239                             ch = IX_FSL;
00240                      } else if ( IX_FSR != IX_DNR && ch == IX_DNR ) {
00241                             ch = IX_FSR;
00242                      } else if ( LDIF_NEED_ESCAPE( ch ) ) {
00243                             *ptr++ = LDIF_ESCAPE_CHAR;
00244                             *ptr++ = hex[(ch & 0xFFU) >> 4];
00245                             ch = hex[ch & 0x0FU];
00246                      }
00247               }
00248        }
00249        ptr = lutil_strcopy( ptr, LDIF );
00250        res->bv_len = ptr - res->bv_val;
00251 
00252        assert( res->bv_len <= len );
00253 
00254        return LDAP_SUCCESS;
00255 }
00256 
00257 /*
00258  * *dest = dupbv(<dir + LDAP_DIRSEP>), plus room for <more>-sized filename.
00259  * Return pointer past the dirname.
00260  */
00261 static char *
00262 fullpath_alloc( struct berval *dest, const struct berval *dir, ber_len_t more )
00263 {
00264        char *s = SLAP_MALLOC( dir->bv_len + more + 2 );
00265 
00266        dest->bv_val = s;
00267        if ( s == NULL ) {
00268               dest->bv_len = 0;
00269               Debug( LDAP_DEBUG_ANY, "back-ldif: out of memory\n", 0, 0, 0 );
00270        } else {
00271               s = lutil_strcopy( dest->bv_val, dir->bv_val );
00272               *s++ = LDAP_DIRSEP[0];
00273               *s = '\0';
00274               dest->bv_len = s - dest->bv_val;
00275        }
00276        return s;
00277 }
00278 
00279 /*
00280  * Append filename to fullpath_alloc() dirname or replace previous filename.
00281  * dir_end = fullpath_alloc() return value.
00282  */
00283 #define FILL_PATH(fpath, dir_end, filename) \
00284        ((fpath)->bv_len = lutil_strcopy(dir_end, filename) - (fpath)->bv_val)
00285 
00286 
00287 /* .ldif entry filename length <-> subtree dirname length. */
00288 #define ldif2dir_len(bv)  ((bv).bv_len -= STRLENOF(LDIF))
00289 #define dir2ldif_len(bv)  ((bv).bv_len += STRLENOF(LDIF))
00290 /* .ldif entry filename <-> subtree dirname, both with dirname length. */
00291 #define ldif2dir_name(bv) ((bv).bv_val[(bv).bv_len] = '\0')
00292 #define dir2ldif_name(bv) ((bv).bv_val[(bv).bv_len] = LDIF_FILETYPE_SEP)
00293 
00294 /* Get the parent directory path, plus the LDIF suffix overwritten by a \0. */
00295 static int
00296 get_parent_path( struct berval *dnpath, struct berval *res )
00297 {
00298        ber_len_t i = dnpath->bv_len;
00299 
00300        while ( i > 0 && dnpath->bv_val[ --i ] != LDAP_DIRSEP[0] ) ;
00301        if ( res == NULL ) {
00302               res = dnpath;
00303        } else {
00304               res->bv_val = SLAP_MALLOC( i + 1 + STRLENOF(LDIF) );
00305               if ( res->bv_val == NULL )
00306                      return LDAP_OTHER;
00307               AC_MEMCPY( res->bv_val, dnpath->bv_val, i );
00308        }
00309        res->bv_len = i;
00310        strcpy( res->bv_val + i, LDIF );
00311        res->bv_val[i] = '\0';
00312        return LDAP_SUCCESS;
00313 }
00314 
00315 /* Make temporary filename pattern for mkstemp() based on dnpath. */
00316 static char *
00317 ldif_tempname( const struct berval *dnpath )
00318 {
00319        static const char suffix[] = ".XXXXXX";
00320        ber_len_t len = dnpath->bv_len - STRLENOF( LDIF );
00321        char *name = SLAP_MALLOC( len + sizeof( suffix ) );
00322 
00323        if ( name != NULL ) {
00324               AC_MEMCPY( name, dnpath->bv_val, len );
00325               strcpy( name + len, suffix );
00326        }
00327        return name;
00328 }
00329 
00330 /* CRC-32 table for the polynomial:
00331  * 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.
00332  *
00333  * As used by zlib
00334  */
00335 
00336 static const ber_uint_t crctab[256] = {
00337        0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
00338        0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
00339        0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
00340        0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
00341        0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
00342        0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
00343        0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
00344        0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
00345        0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
00346        0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
00347        0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
00348        0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
00349        0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
00350        0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
00351        0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
00352        0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
00353        0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
00354        0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
00355        0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
00356        0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
00357        0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
00358        0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
00359        0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
00360        0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
00361        0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
00362        0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
00363        0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
00364        0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
00365        0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
00366        0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
00367        0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
00368        0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
00369        0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
00370        0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
00371        0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
00372        0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
00373        0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
00374        0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
00375        0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
00376        0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
00377        0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
00378        0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
00379        0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
00380        0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
00381        0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
00382        0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
00383        0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
00384        0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
00385        0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
00386        0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
00387        0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
00388        0x2d02ef8dL
00389 };
00390 
00391 #define CRC1  crc = crctab[(crc ^ *buf++) & 0xff] ^ (crc >> 8)
00392 #define CRC8  CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1
00393 unsigned int
00394 crc32(const void *vbuf, int len)
00395 {
00396        const unsigned char  *buf = vbuf;
00397        ber_uint_t           crc = 0xffffffff;
00398        int                         i;
00399 
00400        while (len > 7) {
00401               CRC8;
00402               len -= 8;
00403        }
00404        while (len) {
00405               CRC1;
00406               len--;
00407        }
00408 
00409        return crc ^ 0xffffffff;
00410 }
00411 
00412 /*
00413  * Read a file, or stat() it if datap == NULL.  Allocate and fill *datap.
00414  * Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error.
00415  */
00416 static int
00417 ldif_read_file( const char *path, char **datap )
00418 {
00419        int rc = LDAP_SUCCESS, fd, len;
00420        int res = -1; /* 0:success, <0:error, >0:file too big/growing. */
00421        struct stat st;
00422        char *data = NULL, *ptr = NULL;
00423        const char *msg;
00424 
00425        if ( datap == NULL ) {
00426               res = stat( path, &st );
00427               goto done;
00428        }
00429        fd = open( path, O_RDONLY );
00430        if ( fd >= 0 ) {
00431               if ( fstat( fd, &st ) == 0 ) {
00432                      if ( st.st_size > INT_MAX - 2 ) {
00433                             res = 1;
00434                      } else {
00435                             len = st.st_size + 1; /* +1 detects file size > st.st_size */
00436                             *datap = data = ptr = SLAP_MALLOC( len + 1 );
00437                             if ( ptr != NULL ) {
00438                                    while ( len && (res = read( fd, ptr, len )) ) {
00439                                           if ( res > 0 ) {
00440                                                  len -= res;
00441                                                  ptr += res;
00442                                           } else if ( errno != EINTR ) {
00443                                                  break;
00444                                           }
00445                                    }
00446                                    *ptr = '\0';
00447                             }
00448                      }
00449               }
00450               if ( close( fd ) < 0 )
00451                      res = -1;
00452        }
00453 
00454  done:
00455        if ( res == 0 ) {
00456 #ifdef LDAP_DEBUG
00457               msg = "entry file exists";
00458               if ( datap ) {
00459                      msg = "read entry file";
00460                      len = ptr - data;
00461                      ptr = strstr( data, "\n# CRC32" );
00462                      if (!ptr) {
00463                             msg = "read entry file without checksum";
00464                      } else {
00465                             unsigned int crc1 = 0, crc2 = 1;
00466                             if ( sscanf( ptr + 9, "%08x", &crc1) == 1) {
00467                                    ptr = strchr(ptr+1, '\n');
00468                                    if ( ptr ) {
00469                                           ptr++;
00470                                           len -= (ptr - data);
00471                                           crc2 = crc32( ptr, len );
00472                                    }
00473                             }
00474                             if ( crc1 != crc2 ) {
00475                                    Debug( LDAP_DEBUG_ANY, "ldif_read_file: checksum error on \"%s\"\n",
00476                                           path, 0, 0 );
00477                                    return rc;
00478                             }
00479                      }
00480               }
00481               Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n", msg, path, 0 );
00482 #endif /* LDAP_DEBUG */
00483        } else {
00484               if ( res < 0 && errno == ENOENT ) {
00485                      Debug( LDAP_DEBUG_TRACE, "ldif_read_file: "
00486                             "no entry file \"%s\"\n", path, 0, 0 );
00487                      rc = LDAP_NO_SUCH_OBJECT;
00488               } else {
00489                      msg = res < 0 ? STRERROR( errno ) : "bad stat() size";
00490                      Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n",
00491                             msg, path, 0 );
00492                      rc = LDAP_OTHER;
00493               }
00494               if ( data != NULL )
00495                      SLAP_FREE( data );
00496        }
00497        return rc;
00498 }
00499 
00500 /*
00501  * return nonnegative for success or -1 for error
00502  * do not return numbers less than -1
00503  */
00504 static int
00505 spew_file( int fd, const char *spew, int len, int *save_errno )
00506 {
00507        int writeres;
00508 #define HEADER       "# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n"
00509        char header[sizeof(HEADER "# CRC32 12345678\n")];
00510 
00511        sprintf(header, HEADER "# CRC32 %08x\n", crc32(spew, len));
00512        writeres = write_data(fd, header, sizeof(header)-1, save_errno);
00513        return writeres < 0 ? writeres : write_data(fd, spew, len, save_errno);
00514 }
00515 
00516 static int
00517 write_data( int fd, const char *spew, int len, int *save_errno )
00518 {
00519        int writeres = 0;
00520        while(len > 0) {
00521               writeres = write(fd, spew, len);
00522               if(writeres == -1) {
00523                      *save_errno = errno;
00524                      if (*save_errno != EINTR)
00525                             break;
00526               }
00527               else {
00528                      spew += writeres;
00529                      len -= writeres;
00530               }
00531        }
00532        return writeres;
00533 }
00534 
00535 /* Write an entry LDIF file.  Create parentdir first if non-NULL. */
00536 static int
00537 ldif_write_entry(
00538        Operation *op,
00539        Entry *e,
00540        const struct berval *path,
00541        const char *parentdir,
00542        const char **text )
00543 {
00544        int rc = LDAP_OTHER, res, save_errno = 0;
00545        int fd, entry_length;
00546        char *entry_as_string, *tmpfname;
00547 
00548        if ( op->o_abandon )
00549               return SLAPD_ABANDON;
00550 
00551        if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) {
00552               save_errno = errno;
00553               Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
00554                      "cannot create parent directory",
00555                      parentdir, STRERROR( save_errno ) );
00556               *text = "internal error (cannot create parent directory)";
00557               return rc;
00558        }
00559 
00560        tmpfname = ldif_tempname( path );
00561        fd = tmpfname == NULL ? -1 : mkstemp( tmpfname );
00562        if ( fd < 0 ) {
00563               save_errno = errno;
00564               Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n",
00565                      "cannot create file", e->e_dn, STRERROR( save_errno ) );
00566               *text = "internal error (cannot create file)";
00567 
00568        } else {
00569               ber_len_t dn_len = e->e_name.bv_len;
00570               struct berval rdn;
00571 
00572               /* Only save the RDN onto disk */
00573               dnRdn( &e->e_name, &rdn );
00574               if ( rdn.bv_len != dn_len ) {
00575                      e->e_name.bv_val[rdn.bv_len] = '\0';
00576                      e->e_name.bv_len = rdn.bv_len;
00577               }
00578 
00579               res = -2;
00580               ldap_pvt_thread_mutex_lock( &entry2str_mutex );
00581               entry_as_string = entry2str( e, &entry_length );
00582               if ( entry_as_string != NULL )
00583                      res = spew_file( fd, entry_as_string, entry_length, &save_errno );
00584               ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
00585 
00586               /* Restore full DN */
00587               if ( rdn.bv_len != dn_len ) {
00588                      e->e_name.bv_val[rdn.bv_len] = ',';
00589                      e->e_name.bv_len = dn_len;
00590               }
00591 
00592               if ( close( fd ) < 0 && res >= 0 ) {
00593                      res = -1;
00594                      save_errno = errno;
00595               }
00596 
00597               if ( res >= 0 ) {
00598                      if ( move_file( tmpfname, path->bv_val ) == 0 ) {
00599                             Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: "
00600                                    "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 );
00601                             rc = LDAP_SUCCESS;
00602                      } else {
00603                             save_errno = errno;
00604                             Debug( LDAP_DEBUG_ANY, "ldif_write_entry: "
00605                                    "could not put entry file for \"%s\" in place: %s\n",
00606                                    e->e_name.bv_val, STRERROR( save_errno ), 0 );
00607                             *text = "internal error (could not put entry file in place)";
00608                      }
00609               } else if ( res == -1 ) {
00610                      Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n",
00611                             "write error to", tmpfname, STRERROR( save_errno ) );
00612                      *text = "internal error (write error to entry file)";
00613               }
00614 
00615               if ( rc != LDAP_SUCCESS ) {
00616                      unlink( tmpfname );
00617               }
00618        }
00619 
00620        if ( tmpfname )
00621               SLAP_FREE( tmpfname );
00622        return rc;
00623 }
00624 
00625 /*
00626  * Read the entry at path, or if entryp==NULL just see if it exists.
00627  * pdn and pndn are the parent's DN and normalized DN, or both NULL.
00628  * Return an LDAP result code.
00629  */
00630 static int
00631 ldif_read_entry(
00632        Operation *op,
00633        const char *path,
00634        struct berval *pdn,
00635        struct berval *pndn,
00636        Entry **entryp,
00637        const char **text )
00638 {
00639        int rc;
00640        Entry *entry;
00641        char *entry_as_string;
00642        struct berval rdn;
00643 
00644        /* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
00645         * If so we need not check for LDAP_REQ_BIND here.
00646         */
00647        if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND )
00648               return SLAPD_ABANDON;
00649 
00650        rc = ldif_read_file( path, entryp ? &entry_as_string : NULL );
00651 
00652        switch ( rc ) {
00653        case LDAP_SUCCESS:
00654               if ( entryp == NULL )
00655                      break;
00656               *entryp = entry = str2entry( entry_as_string );
00657               SLAP_FREE( entry_as_string );
00658               if ( entry == NULL ) {
00659                      rc = LDAP_OTHER;
00660                      if ( text != NULL )
00661                             *text = "internal error (cannot parse some entry file)";
00662                      break;
00663               }
00664               if ( pdn == NULL || BER_BVISEMPTY( pdn ) )
00665                      break;
00666               /* Append parent DN to DN from LDIF file */
00667               rdn = entry->e_name;
00668               build_new_dn( &entry->e_name, pdn, &rdn, NULL );
00669               SLAP_FREE( rdn.bv_val );
00670               rdn = entry->e_nname;
00671               build_new_dn( &entry->e_nname, pndn, &rdn, NULL );
00672               SLAP_FREE( rdn.bv_val );
00673               break;
00674 
00675        case LDAP_OTHER:
00676               if ( text != NULL )
00677                      *text = entryp
00678                             ? "internal error (cannot read some entry file)"
00679                             : "internal error (cannot stat some entry file)";
00680               break;
00681        }
00682 
00683        return rc;
00684 }
00685 
00686 /*
00687  * Read the operation's entry, or if entryp==NULL just see if it exists.
00688  * Return an LDAP result code.  May set *text to a message on failure.
00689  * If pathp is non-NULL, set it to the entry filename on success.
00690  */
00691 static int
00692 get_entry(
00693        Operation *op,
00694        Entry **entryp,
00695        struct berval *pathp,
00696        const char **text )
00697 {
00698        int rc;
00699        struct berval path, pdn, pndn;
00700 
00701        dnParent( &op->o_req_dn, &pdn );
00702        dnParent( &op->o_req_ndn, &pndn );
00703        rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
00704        if ( rc != LDAP_SUCCESS ) {
00705               goto done;
00706        }
00707 
00708        rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text );
00709 
00710        if ( rc == LDAP_SUCCESS && pathp != NULL ) {
00711               *pathp = path;
00712        } else {
00713               SLAP_FREE( path.bv_val );
00714        }
00715  done:
00716        return rc;
00717 }
00718 
00719 
00720 /*
00721  * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
00722  * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
00723  * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
00724  * Does not sort escaped chars correctly, would need to un-escape them.
00725  */
00726 typedef struct bvlist {
00727        struct bvlist *next;
00728        char *trunc;  /* filename was truncated here */
00729        int  inum;           /* num from "attr={num}" in filename, or INT_MIN */
00730        char savech;  /* original char at *trunc */
00731        /* BVL_NAME(&bvlist) is the filename, allocated after the struct: */
00732 #      define BVL_NAME(bvl)     ((char *) ((bvl) + 1))
00733 #      define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1)
00734 } bvlist;
00735 
00736 static int
00737 ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope )
00738 {
00739        int rc = LDAP_SUCCESS;
00740 
00741        if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) {
00742               if ( rs == NULL ) {
00743                      /* Save the entry for tool mode */
00744                      struct ldif_tool *tl =
00745                             &((struct ldif_info *) op->o_bd->be_private)->li_tool;
00746 
00747                      if ( tl->ecount >= tl->elen ) {
00748                             /* Allocate/grow entries */
00749                             ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT;
00750                             Entry **entries = (Entry **) SLAP_REALLOC( tl->entries,
00751                                    sizeof(Entry *) * elen );
00752                             if ( entries == NULL ) {
00753                                    Debug( LDAP_DEBUG_ANY,
00754                                           "ldif_send_entry: out of memory\n", 0, 0, 0 );
00755                                    rc = LDAP_OTHER;
00756                                    goto done;
00757                             }
00758                             tl->elen = elen;
00759                             tl->entries = entries;
00760                      }
00761                      tl->entries[tl->ecount++] = e;
00762                      return rc;
00763               }
00764 
00765               else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) {
00766                      /* Send a continuation reference.
00767                       * (ldif_back_referrals() handles baseobject referrals.)
00768                       * Don't check the filter since it's only a candidate.
00769                       */
00770                      BerVarray refs = get_entry_referrals( op, e );
00771                      rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope );
00772                      rs->sr_entry = e;
00773                      rc = send_search_reference( op, rs );
00774                      ber_bvarray_free( rs->sr_ref );
00775                      ber_bvarray_free( refs );
00776                      rs->sr_ref = NULL;
00777                      rs->sr_entry = NULL;
00778               }
00779 
00780               else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
00781                      rs->sr_entry = e;
00782                      rs->sr_attrs = op->ors_attrs;
00783                      /* Could set REP_ENTRY_MUSTBEFREED too for efficiency,
00784                       * but refraining lets us test unFREEable MODIFIABLE
00785                       * entries.  Like entries built on the stack.
00786                       */
00787                      rs->sr_flags = REP_ENTRY_MODIFIABLE;
00788                      rc = send_search_entry( op, rs );
00789                      rs->sr_entry = NULL;
00790                      rs->sr_attrs = NULL;
00791               }
00792        }
00793 
00794  done:
00795        entry_free( e );
00796        return rc;
00797 }
00798 
00799 /* Read LDIF directory <path> into <listp>.  Set *fname_maxlenp. */
00800 static int
00801 ldif_readdir(
00802        Operation *op,
00803        SlapReply *rs,
00804        const struct berval *path,
00805        bvlist **listp,
00806        ber_len_t *fname_maxlenp )
00807 {
00808        int rc = LDAP_SUCCESS;
00809        DIR *dir_of_path;
00810 
00811        *listp = NULL;
00812        *fname_maxlenp = 0;
00813 
00814        dir_of_path = opendir( path->bv_val );
00815        if ( dir_of_path == NULL ) {
00816               int save_errno = errno;
00817               struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
00818               int is_rootDSE = (path->bv_len == li->li_base_path.bv_len);
00819 
00820               /* Absent directory is OK (leaf entry), except the database dir */
00821               if ( is_rootDSE || save_errno != ENOENT ) {
00822                      Debug( LDAP_DEBUG_ANY,
00823                             "=> ldif_search_entry: failed to opendir \"%s\": %s\n",
00824                             path->bv_val, STRERROR( save_errno ), 0 );
00825                      rc = LDAP_OTHER;
00826                      if ( rs != NULL )
00827                             rs->sr_text =
00828                                    save_errno != ENOENT ? "internal error (bad directory)"
00829                                    : !is_rootDSE ? "internal error (missing directory)"
00830                                    : "internal error (database directory does not exist)";
00831               }
00832 
00833        } else {
00834               bvlist *ptr;
00835               struct dirent *dir;
00836               int save_errno = 0;
00837 
00838               while ( (dir = readdir( dir_of_path )) != NULL ) {
00839                      size_t fname_len;
00840                      bvlist *bvl, **prev;
00841                      char *trunc, *idxp, *endp, *endp2;
00842 
00843                      fname_len = strlen( dir->d_name );
00844                      if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
00845                             continue;
00846                      if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
00847                             continue;
00848 
00849                      if ( *fname_maxlenp < fname_len )
00850                             *fname_maxlenp = fname_len;
00851 
00852                      bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) );
00853                      if ( bvl == NULL ) {
00854                             rc = LDAP_OTHER;
00855                             save_errno = errno;
00856                             break;
00857                      }
00858                      strcpy( BVL_NAME( bvl ), dir->d_name );
00859 
00860                      /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
00861                      trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
00862                      if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
00863                              (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
00864                              (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
00865                      {
00866                             /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
00867                             bvl->inum = strtol( idxp, &endp2, 10 );
00868                             if ( endp2 == endp ) {
00869                                    trunc = idxp;
00870                                    goto truncate;
00871                             }
00872                      }
00873                      bvl->inum = INT_MIN;
00874               truncate:
00875                      bvl->trunc = trunc;
00876                      bvl->savech = *trunc;
00877                      *trunc = '\0';
00878 
00879                      /* Insertion sort */
00880                      for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
00881                             int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
00882                             if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
00883                                    break;
00884                      }
00885                      *prev = bvl;
00886                      bvl->next = ptr;
00887               }
00888 
00889               if ( closedir( dir_of_path ) < 0 ) {
00890                      save_errno = errno;
00891                      rc = LDAP_OTHER;
00892                      if ( rs != NULL )
00893                             rs->sr_text = "internal error (bad directory)";
00894               }
00895               if ( rc != LDAP_SUCCESS ) {
00896                      Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n",
00897                             "error reading directory", path->bv_val,
00898                             STRERROR( save_errno ) );
00899               }
00900        }
00901 
00902        return rc;
00903 }
00904 
00905 /*
00906  * Send an entry, recursively search its children, and free or save it.
00907  * Return an LDAP result code.  Parameters:
00908  *  op, rs  operation and reply.  rs == NULL for slap tools.
00909  *  e       entry to search, or NULL for rootDSE.
00910  *  scope   scope for the part of the search from this entry.
00911  *  path    LDIF filename -- bv_len and non-directory part are overwritten.
00912  */
00913 static int
00914 ldif_search_entry(
00915        Operation *op,
00916        SlapReply *rs,
00917        Entry *e,
00918        int scope,
00919        struct berval *path )
00920 {
00921        int rc = LDAP_SUCCESS;
00922        struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" );
00923 
00924        if ( scope != LDAP_SCOPE_BASE && e != NULL ) {
00925               /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
00926                * which bconfig.c seems to need.  (TODO: see config_rename_one.)
00927                */
00928               if ( ber_dupbv( &dn,  &e->e_name  ) == NULL ||
00929                       ber_dupbv( &ndn, &e->e_nname ) == NULL )
00930               {
00931                      Debug( LDAP_DEBUG_ANY,
00932                             "ldif_search_entry: out of memory\n", 0, 0, 0 );
00933                      rc = LDAP_OTHER;
00934                      goto done;
00935               }
00936        }
00937 
00938        /* Send the entry if appropriate, and free or save it */
00939        if ( e != NULL )
00940               rc = ldif_send_entry( op, rs, e, scope );
00941 
00942        /* Search the children */
00943        if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) {
00944               bvlist *list, *ptr;
00945               struct berval fpath; /* becomes child pathname */
00946               char *dir_end;       /* will point past dirname in fpath */
00947 
00948               ldif2dir_len( *path );
00949               ldif2dir_name( *path );
00950               rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len );
00951 
00952               if ( list != NULL ) {
00953                      const char **text = rs == NULL ? NULL : &rs->sr_text;
00954 
00955                      if ( scope == LDAP_SCOPE_ONELEVEL )
00956                             scope = LDAP_SCOPE_BASE;
00957                      else if ( scope == LDAP_SCOPE_SUBORDINATE )
00958                             scope = LDAP_SCOPE_SUBTREE;
00959 
00960                      /* Allocate fpath and fill in directory part */
00961                      dir_end = fullpath_alloc( &fpath, path, fpath.bv_len );
00962                      if ( dir_end == NULL )
00963                             rc = LDAP_OTHER;
00964 
00965                      do {
00966                             ptr = list;
00967 
00968                             if ( rc == LDAP_SUCCESS ) {
00969                                    *ptr->trunc = ptr->savech;
00970                                    FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));
00971 
00972                                    rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn,
00973                                           &e, text );
00974                                    switch ( rc ) {
00975                                    case LDAP_SUCCESS:
00976                                           rc = ldif_search_entry( op, rs, e, scope, &fpath );
00977                                           break;
00978                                    case LDAP_NO_SUCH_OBJECT:
00979                                           /* Only the search baseDN may produce noSuchObject. */
00980                                           rc = LDAP_OTHER;
00981                                           if ( rs != NULL )
00982                                                  rs->sr_text = "internal error "
00983                                                         "(did someone just remove an entry file?)";
00984                                           Debug( LDAP_DEBUG_ANY, "ldif_search_entry: "
00985                                                  "file listed in parent directory does not exist: "
00986                                                  "\"%s\"\n", fpath.bv_val, 0, 0 );
00987                                           break;
00988                                    }
00989                             }
00990 
00991                             list = ptr->next;
00992                             SLAP_FREE( ptr );
00993                      } while ( list != NULL );
00994 
00995                      if ( !BER_BVISNULL( &fpath ) )
00996                             SLAP_FREE( fpath.bv_val );
00997               }
00998        }
00999 
01000  done:
01001        if ( !BER_BVISEMPTY( &dn ) )
01002               ber_memfree( dn.bv_val );
01003        if ( !BER_BVISEMPTY( &ndn ) )
01004               ber_memfree( ndn.bv_val );
01005        return rc;
01006 }
01007 
01008 static int
01009 search_tree( Operation *op, SlapReply *rs )
01010 {
01011        int rc = LDAP_SUCCESS;
01012        Entry *e = NULL;
01013        struct berval path;
01014        struct berval pdn, pndn;
01015 
01016        (void) ndn2path( op, &op->o_req_ndn, &path, 1 );
01017        if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) {
01018               /* Read baseObject */
01019               dnParent( &op->o_req_dn, &pdn );
01020               dnParent( &op->o_req_ndn, &pndn );
01021               rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e,
01022                      rs == NULL ? NULL : &rs->sr_text );
01023        }
01024        if ( rc == LDAP_SUCCESS )
01025               rc = ldif_search_entry( op, rs, e, op->ors_scope, &path );
01026 
01027        ch_free( path.bv_val );
01028        return rc;
01029 }
01030 
01031 
01032 /*
01033  * Prepare to create or rename an entry:
01034  * Check that the entry does not already exist.
01035  * Check that the parent entry exists and can have subordinates,
01036  * unless need_dir is NULL or adding the suffix entry.
01037  *
01038  * Return an LDAP result code.  May set *text to a message on failure.
01039  * If success, set *dnpath to LDIF entry path and *need_dir to
01040  * (directory must be created ? dirname : NULL).
01041  */
01042 static int
01043 ldif_prepare_create(
01044        Operation *op,
01045        Entry *e,
01046        struct berval *dnpath,
01047        char **need_dir,
01048        const char **text )
01049 {
01050        struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
01051        struct berval *ndn = &e->e_nname;
01052        struct berval ppath = BER_BVNULL;
01053        struct stat st;
01054        Entry *parent = NULL;
01055        int rc;
01056 
01057        if ( op->o_abandon )
01058               return SLAPD_ABANDON;
01059 
01060        rc = ndn2path( op, ndn, dnpath, 0 );
01061        if ( rc != LDAP_SUCCESS ) {
01062               return rc;
01063        }
01064 
01065        if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */
01066               rc = LDAP_ALREADY_EXISTS;
01067 
01068        } else if ( errno != ENOENT ) {
01069               Debug( LDAP_DEBUG_ANY,
01070                      "ldif_prepare_create: cannot stat \"%s\": %s\n",
01071                      dnpath->bv_val, STRERROR( errno ), 0 );
01072               rc = LDAP_OTHER;
01073               *text = "internal error (cannot check entry file)";
01074 
01075        } else if ( need_dir != NULL ) {
01076               *need_dir = NULL;
01077               rc = get_parent_path( dnpath, &ppath );
01078               /* If parent dir exists, so does parent .ldif:
01079                * The directory gets created after and removed before the .ldif.
01080                * Except with the database directory, which has no matching entry.
01081                */
01082               if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) {
01083                      rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len
01084                             ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER;
01085               }
01086               switch ( rc ) {
01087               case LDAP_NO_SUCH_OBJECT:
01088                      /* No parent dir, check parent .ldif */
01089                      dir2ldif_name( ppath );
01090                      rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL,
01091                             (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op )
01092                              ? &parent : NULL),
01093                             text );
01094                      switch ( rc ) {
01095                      case LDAP_SUCCESS:
01096                             /* Check that parent is not a referral, unless
01097                              * ldif_back_referrals() already checked.
01098                              */
01099                             if ( parent != NULL ) {
01100                                    int is_ref = is_entry_referral( parent );
01101                                    entry_free( parent );
01102                                    if ( is_ref ) {
01103                                           rc = LDAP_AFFECTS_MULTIPLE_DSAS;
01104                                           *text = op->o_tag == LDAP_REQ_MODDN
01105                                                  ? "newSuperior is a referral object"
01106                                                  : "parent is a referral object";
01107                                           break;
01108                                    }
01109                             }
01110                             /* Must create parent directory. */
01111                             ldif2dir_name( ppath );
01112                             *need_dir = ppath.bv_val;
01113                             break;
01114                      case LDAP_NO_SUCH_OBJECT:
01115                             *text = op->o_tag == LDAP_REQ_MODDN
01116                                    ? "newSuperior object does not exist"
01117                                    : "parent does not exist";
01118                             break;
01119                      }
01120                      break;
01121               case LDAP_OTHER:
01122                      Debug( LDAP_DEBUG_ANY,
01123                             "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n",
01124                             ndn->bv_val, STRERROR( errno ), 0 );
01125                      *text = "internal error (cannot stat parent dir)";
01126                      break;
01127               }
01128               if ( *need_dir == NULL && ppath.bv_val != NULL )
01129                      SLAP_FREE( ppath.bv_val );
01130        }
01131 
01132        if ( rc != LDAP_SUCCESS ) {
01133               SLAP_FREE( dnpath->bv_val );
01134               BER_BVZERO( dnpath );
01135        }
01136        return rc;
01137 }
01138 
01139 static int
01140 apply_modify_to_entry(
01141        Entry *entry,
01142        Modifications *modlist,
01143        Operation *op,
01144        SlapReply *rs,
01145        char *textbuf )
01146 {
01147        int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
01148        int is_oc = 0;
01149        Modification *mods;
01150 
01151        if (!acl_check_modlist(op, entry, modlist)) {
01152               return LDAP_INSUFFICIENT_ACCESS;
01153        }
01154 
01155        for (; modlist != NULL; modlist = modlist->sml_next) {
01156               mods = &modlist->sml_mod;
01157 
01158               if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
01159                      is_oc = 1;
01160               }
01161               switch (mods->sm_op) {
01162               case LDAP_MOD_ADD:
01163                      rc = modify_add_values(entry, mods,
01164                                get_permissiveModify(op),
01165                                &rs->sr_text, textbuf,
01166                                SLAP_TEXT_BUFLEN );
01167                      break;
01168 
01169               case LDAP_MOD_DELETE:
01170                      rc = modify_delete_values(entry, mods,
01171                             get_permissiveModify(op),
01172                             &rs->sr_text, textbuf,
01173                             SLAP_TEXT_BUFLEN );
01174                      break;
01175 
01176               case LDAP_MOD_REPLACE:
01177                      rc = modify_replace_values(entry, mods,
01178                              get_permissiveModify(op),
01179                              &rs->sr_text, textbuf,
01180                              SLAP_TEXT_BUFLEN );
01181                      break;
01182 
01183               case LDAP_MOD_INCREMENT:
01184                      rc = modify_increment_values( entry,
01185                             mods, get_permissiveModify(op),
01186                             &rs->sr_text, textbuf,
01187                             SLAP_TEXT_BUFLEN );
01188                      break;
01189 
01190               case SLAP_MOD_SOFTADD:
01191                      mods->sm_op = LDAP_MOD_ADD;
01192                      rc = modify_add_values(entry, mods,
01193                                get_permissiveModify(op),
01194                                &rs->sr_text, textbuf,
01195                                SLAP_TEXT_BUFLEN );
01196                      mods->sm_op = SLAP_MOD_SOFTADD;
01197                      if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
01198                             rc = LDAP_SUCCESS;
01199                      }
01200                      break;
01201 
01202               case SLAP_MOD_SOFTDEL:
01203                      mods->sm_op = LDAP_MOD_DELETE;
01204                      rc = modify_delete_values(entry, mods,
01205                                get_permissiveModify(op),
01206                                &rs->sr_text, textbuf,
01207                                SLAP_TEXT_BUFLEN );
01208                      mods->sm_op = SLAP_MOD_SOFTDEL;
01209                      if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
01210                             rc = LDAP_SUCCESS;
01211                      }
01212                      break;
01213 
01214               case SLAP_MOD_ADD_IF_NOT_PRESENT:
01215                      if ( attr_find( entry->e_attrs, mods->sm_desc ) ) {
01216                             rc = LDAP_SUCCESS;
01217                             break;
01218                      }
01219                      mods->sm_op = LDAP_MOD_ADD;
01220                      rc = modify_add_values(entry, mods,
01221                                get_permissiveModify(op),
01222                                &rs->sr_text, textbuf,
01223                                SLAP_TEXT_BUFLEN );
01224                      mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
01225                      break;
01226               }
01227               if(rc != LDAP_SUCCESS) break;
01228        }
01229 
01230        if ( rc == LDAP_SUCCESS ) {
01231               rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */
01232               if ( is_oc ) {
01233                      entry->e_ocflags = 0;
01234               }
01235               /* check that the entry still obeys the schema */
01236               rc = entry_schema_check( op, entry, NULL, 0, 0, NULL,
01237                        &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN );
01238        }
01239 
01240        return rc;
01241 }
01242 
01243 
01244 static int
01245 ldif_back_referrals( Operation *op, SlapReply *rs )
01246 {
01247        struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
01248        struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn;
01249        ber_len_t min_dnlen;
01250        Entry *entry = NULL, **entryp;
01251        BerVarray ref;
01252        int rc;
01253 
01254        min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
01255        if ( min_dnlen == 0 ) {
01256               /* Catch root DSE (empty DN), it is not a referral */
01257               min_dnlen = 1;
01258        }
01259        if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) {
01260               return LDAP_SUCCESS; /* Root DSE again */
01261        }
01262 
01263        entryp = get_manageDSAit( op ) ? NULL : &entry;
01264        ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
01265 
01266        for (;;) {
01267               dnParent( &dn, &dn );
01268               dnParent( &ndn, &ndn );
01269               rc = ldif_read_entry( op, path.bv_val, &dn, &ndn,
01270                      entryp, &rs->sr_text );
01271               if ( rc != LDAP_NO_SUCH_OBJECT )
01272                      break;
01273 
01274               rc = LDAP_SUCCESS;
01275               if ( ndn.bv_len < min_dnlen )
01276                      break;
01277               (void) get_parent_path( &path, NULL );
01278               dir2ldif_name( path );
01279               entryp = &entry;
01280        }
01281 
01282        ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
01283        SLAP_FREE( path.bv_val );
01284 
01285        if ( entry != NULL ) {
01286               if ( is_entry_referral( entry ) ) {
01287                      Debug( LDAP_DEBUG_TRACE,
01288                             "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
01289                             (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn );
01290 
01291                      ref = get_entry_referrals( op, entry );
01292                      rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn,
01293                             op->o_tag == LDAP_REQ_SEARCH ?
01294                             op->ors_scope : LDAP_SCOPE_DEFAULT );
01295                      ber_bvarray_free( ref );
01296 
01297                      if ( rs->sr_ref != NULL ) {
01298                             /* send referral */
01299                             rc = rs->sr_err = LDAP_REFERRAL;
01300                             rs->sr_matched = entry->e_dn;
01301                             send_ldap_result( op, rs );
01302                             ber_bvarray_free( rs->sr_ref );
01303                             rs->sr_ref = NULL;
01304                      } else {
01305                             rc = LDAP_OTHER;
01306                             rs->sr_text = "bad referral object";
01307                      }
01308                      rs->sr_matched = NULL;
01309               }
01310 
01311               entry_free( entry );
01312        }
01313 
01314        return rc;
01315 }
01316 
01317 
01318 /* LDAP operations */
01319 
01320 static int
01321 ldif_back_bind( Operation *op, SlapReply *rs )
01322 {
01323        struct ldif_info *li;
01324        Attribute *a;
01325        AttributeDescription *password = slap_schema.si_ad_userPassword;
01326        int return_val;
01327        Entry *entry = NULL;
01328 
01329        switch ( be_rootdn_bind( op, rs ) ) {
01330        case SLAP_CB_CONTINUE:
01331               break;
01332 
01333        default:
01334               /* in case of success, front end will send result;
01335                * otherwise, be_rootdn_bind() did */
01336               return rs->sr_err;
01337        }
01338 
01339        li = (struct ldif_info *) op->o_bd->be_private;
01340        ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
01341        return_val = get_entry(op, &entry, NULL, NULL);
01342 
01343        /* no object is found for them */
01344        if(return_val != LDAP_SUCCESS) {
01345               rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
01346               goto return_result;
01347        }
01348 
01349        /* they don't have userpassword */
01350        if((a = attr_find(entry->e_attrs, password)) == NULL) {
01351               rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
01352               return_val = 1;
01353               goto return_result;
01354        }
01355 
01356        /* authentication actually failed */
01357        if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
01358                           &rs->sr_text) != 0) {
01359               rs->sr_err = LDAP_INVALID_CREDENTIALS;
01360               return_val = 1;
01361               goto return_result;
01362        }
01363 
01364        /* let the front-end send success */
01365        return_val = LDAP_SUCCESS;
01366 
01367  return_result:
01368        ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
01369        if(return_val != LDAP_SUCCESS)
01370               send_ldap_result( op, rs );
01371        if(entry != NULL)
01372               entry_free(entry);
01373        return return_val;
01374 }
01375 
01376 static int
01377 ldif_back_search( Operation *op, SlapReply *rs )
01378 {
01379        struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
01380 
01381        ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
01382        rs->sr_err = search_tree( op, rs );
01383        ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
01384        send_ldap_result(op, rs);
01385 
01386        return rs->sr_err;
01387 }
01388 
01389 static int
01390 ldif_back_add( Operation *op, SlapReply *rs )
01391 {
01392        struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
01393        Entry * e = op->ora_e;
01394        struct berval path;
01395        char *parentdir;
01396        char textbuf[SLAP_TEXT_BUFLEN];
01397        int rc;
01398 
01399        Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 );
01400 
01401        rc = entry_schema_check( op, e, NULL, 0, 1, NULL,
01402               &rs->sr_text, textbuf, sizeof( textbuf ) );
01403        if ( rc != LDAP_SUCCESS )
01404               goto send_res;
01405 
01406        rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
01407        if ( rc != LDAP_SUCCESS )
01408               goto send_res;
01409 
01410        ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
01411 
01412        rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text );
01413        if ( rc == LDAP_SUCCESS ) {
01414               ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
01415               rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text );
01416               ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
01417 
01418               SLAP_FREE( path.bv_val );
01419               if ( parentdir != NULL )
01420                      SLAP_FREE( parentdir );
01421        }
01422 
01423        ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
01424 
01425  send_res:
01426        rs->sr_err = rc;
01427        Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n",
01428               rc, rs->sr_text ? rs->sr_text : "", 0 );
01429        send_ldap_result( op, rs );
01430        slap_graduate_commit_csn( op );
01431        rs->sr_text = NULL;  /* remove possible pointer to textbuf */
01432        return rs->sr_err;
01433 }
01434 
01435 static int
01436 ldif_back_modify( Operation *op, SlapReply *rs )
01437 {
01438        struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
01439        Modifications * modlst = op->orm_modlist;
01440        struct berval path;
01441        Entry *entry;
01442        char textbuf[SLAP_TEXT_BUFLEN];
01443        int rc;
01444 
01445        slap_mods_opattrs( op, &op->orm_modlist, 1 );
01446 
01447        ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
01448 
01449        rc = get_entry( op, &entry, &path, &rs->sr_text );
01450        if ( rc == LDAP_SUCCESS ) {
01451               rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf );
01452               if ( rc == LDAP_SUCCESS ) {
01453                      ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
01454                      rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text );
01455                      ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
01456               }
01457 
01458               entry_free( entry );
01459               SLAP_FREE( path.bv_val );
01460        }
01461 
01462        ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
01463 
01464        rs->sr_err = rc;
01465        send_ldap_result( op, rs );
01466        slap_graduate_commit_csn( op );
01467        rs->sr_text = NULL;  /* remove possible pointer to textbuf */
01468        return rs->sr_err;
01469 }
01470 
01471 static int
01472 ldif_back_delete( Operation *op, SlapReply *rs )
01473 {
01474        struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
01475        struct berval path;
01476        int rc = LDAP_SUCCESS;
01477 
01478        if ( BER_BVISEMPTY( &op->o_csn )) {
01479               struct berval csn;
01480               char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
01481 
01482               csn.bv_val = csnbuf;
01483               csn.bv_len = sizeof( csnbuf );
01484               slap_get_csn( op, &csn, 1 );
01485        }
01486 
01487        ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
01488        ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
01489        if ( op->o_abandon ) {
01490               rc = SLAPD_ABANDON;
01491               goto done;
01492        }
01493 
01494        rc = ndn2path( op, &op->o_req_ndn, &path, 0 );
01495        if ( rc != LDAP_SUCCESS ) {
01496               goto done;
01497        }
01498 
01499        ldif2dir_len( path );
01500        ldif2dir_name( path );
01501        if ( rmdir( path.bv_val ) < 0 ) {
01502               switch ( errno ) {
01503               case ENOTEMPTY:
01504                      rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
01505                      break;
01506               case ENOENT:
01507                      /* is leaf, go on */
01508                      break;
01509               default:
01510                      rc = LDAP_OTHER;
01511                      rs->sr_text = "internal error (cannot delete subtree directory)";
01512                      break;
01513               }
01514        }
01515 
01516        if ( rc == LDAP_SUCCESS ) {
01517               dir2ldif_name( path );
01518               if ( unlink( path.bv_val ) < 0 ) {
01519                      rc = LDAP_NO_SUCH_OBJECT;
01520                      if ( errno != ENOENT ) {
01521                             rc = LDAP_OTHER;
01522                             rs->sr_text = "internal error (cannot delete entry file)";
01523                      }
01524               }
01525        }
01526 
01527        if ( rc == LDAP_OTHER ) {
01528               Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n",
01529                      "cannot delete", path.bv_val, STRERROR( errno ) );
01530        }
01531 
01532        SLAP_FREE( path.bv_val );
01533  done:
01534        ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
01535        ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
01536        rs->sr_err = rc;
01537        send_ldap_result( op, rs );
01538        slap_graduate_commit_csn( op );
01539        return rs->sr_err;
01540 }
01541 
01542 
01543 static int
01544 ldif_move_entry(
01545        Operation *op,
01546        Entry *entry,
01547        int same_ndn,
01548        struct berval *oldpath,
01549        const char **text )
01550 {
01551        struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
01552        struct berval newpath;
01553        char *parentdir = NULL, *trash;
01554        int rc, rename_res;
01555 
01556        if ( same_ndn ) {
01557               rc = LDAP_SUCCESS;
01558               newpath = *oldpath;
01559        } else {
01560               rc = ldif_prepare_create( op, entry, &newpath,
01561                      op->orr_newSup ? &parentdir : NULL, text );
01562        }
01563 
01564        if ( rc == LDAP_SUCCESS ) {
01565               ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
01566 
01567               rc = ldif_write_entry( op, entry, &newpath, parentdir, text );
01568               if ( rc == LDAP_SUCCESS && !same_ndn ) {
01569                      trash = oldpath->bv_val; /* will be .ldif file to delete */
01570                      ldif2dir_len( newpath );
01571                      ldif2dir_len( *oldpath );
01572                      /* Move subdir before deleting old entry,
01573                       * so .ldif always exists if subdir does.
01574                       */
01575                      ldif2dir_name( newpath );
01576                      ldif2dir_name( *oldpath );
01577                      rename_res = move_dir( oldpath->bv_val, newpath.bv_val );
01578                      if ( rename_res != 0 && errno != ENOENT ) {
01579                             rc = LDAP_OTHER;
01580                             *text = "internal error (cannot move this subtree)";
01581                             trash = newpath.bv_val;
01582                      }
01583 
01584                      /* Delete old entry, or if error undo change */
01585                      for (;;) {
01586                             dir2ldif_name( newpath );
01587                             dir2ldif_name( *oldpath );
01588                             if ( unlink( trash ) == 0 )
01589                                    break;
01590                             if ( rc == LDAP_SUCCESS ) {
01591                                    /* Prepare to undo change and return failure */
01592                                    rc = LDAP_OTHER;
01593                                    *text = "internal error (cannot move this entry)";
01594                                    trash = newpath.bv_val;
01595                                    if ( rename_res != 0 )
01596                                           continue;
01597                                    /* First move subdirectory back */
01598                                    ldif2dir_name( newpath );
01599                                    ldif2dir_name( *oldpath );
01600                                    if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 )
01601                                           continue;
01602                             }
01603                             *text = "added new but couldn't delete old entry!";
01604                             break;
01605                      }
01606 
01607                      if ( rc != LDAP_SUCCESS ) {
01608                             char s[128];
01609                             snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno ));
01610                             Debug( LDAP_DEBUG_ANY,
01611                                    "ldif_move_entry: %s: \"%s\" -> \"%s\"\n",
01612                                    s, op->o_req_dn.bv_val, entry->e_dn );
01613                      }
01614               }
01615 
01616               ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
01617               if ( !same_ndn )
01618                      SLAP_FREE( newpath.bv_val );
01619               if ( parentdir != NULL )
01620                      SLAP_FREE( parentdir );
01621        }
01622 
01623        return rc;
01624 }
01625 
01626 static int
01627 ldif_back_modrdn( Operation *op, SlapReply *rs )
01628 {
01629        struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
01630        struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
01631        struct berval p_dn, old_path;
01632        Entry *entry;
01633        char textbuf[SLAP_TEXT_BUFLEN];
01634        int rc, same_ndn;
01635 
01636        slap_mods_opattrs( op, &op->orr_modlist, 1 );
01637 
01638        ldap_pvt_thread_mutex_lock( &li->li_modop_mutex );
01639 
01640        rc = get_entry( op, &entry, &old_path, &rs->sr_text );
01641        if ( rc == LDAP_SUCCESS ) {
01642               /* build new dn, and new ndn for the entry */
01643               if ( op->oq_modrdn.rs_newSup != NULL ) {
01644                      p_dn = *op->oq_modrdn.rs_newSup;
01645               } else {
01646                      dnParent( &entry->e_name, &p_dn );
01647               }
01648               build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL );
01649               dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
01650               same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn );
01651               ber_memfree_x( entry->e_name.bv_val, NULL );
01652               ber_memfree_x( entry->e_nname.bv_val, NULL );
01653               entry->e_name = new_dn;
01654               entry->e_nname = new_ndn;
01655 
01656               /* perform the modifications */
01657               rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf );
01658               if ( rc == LDAP_SUCCESS )
01659                      rc = ldif_move_entry( op, entry, same_ndn, &old_path,
01660                             &rs->sr_text );
01661 
01662               entry_free( entry );
01663               SLAP_FREE( old_path.bv_val );
01664        }
01665 
01666        ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex );
01667        rs->sr_err = rc;
01668        send_ldap_result( op, rs );
01669        slap_graduate_commit_csn( op );
01670        rs->sr_text = NULL;  /* remove possible pointer to textbuf */
01671        return rs->sr_err;
01672 }
01673 
01674 
01675 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
01676 static int
01677 ldif_back_entry_get(
01678        Operation *op,
01679        struct berval *ndn,
01680        ObjectClass *oc,
01681        AttributeDescription *at,
01682        int rw,
01683        Entry **e )
01684 {
01685        struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
01686        struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
01687        int rc;
01688 
01689        assert( ndn != NULL );
01690        assert( !BER_BVISNULL( ndn ) );
01691 
01692        ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
01693        op->o_req_dn = *ndn;
01694        op->o_req_ndn = *ndn;
01695        rc = get_entry( op, e, NULL, NULL );
01696        op->o_req_dn = op_dn;
01697        op->o_req_ndn = op_ndn;
01698        ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
01699 
01700        if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
01701               rc = LDAP_NO_SUCH_ATTRIBUTE;
01702               entry_free( *e );
01703               *e = NULL;
01704        }
01705 
01706        return rc;
01707 }
01708 
01709 
01710 /* Slap tools */
01711 
01712 static int
01713 ldif_tool_entry_open( BackendDB *be, int mode )
01714 {
01715        struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
01716 
01717        tl->ecurrent = 0;
01718        return 0;
01719 }
01720 
01721 static int
01722 ldif_tool_entry_close( BackendDB *be )
01723 {
01724        struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
01725        Entry **entries = tl->entries;
01726        ID i;
01727 
01728        for ( i = tl->ecount; i--; )
01729               if ( entries[i] )
01730                      entry_free( entries[i] );
01731        SLAP_FREE( entries );
01732        tl->entries = NULL;
01733        tl->ecount = tl->elen = 0;
01734        return 0;
01735 }
01736 
01737 static ID
01738 ldif_tool_entry_next( BackendDB *be )
01739 {
01740        struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
01741 
01742        do {
01743               Entry *e = tl->entries[ tl->ecurrent ];
01744 
01745               if ( tl->ecurrent >= tl->ecount ) {
01746                      return NOID;
01747               }
01748 
01749               ++tl->ecurrent;
01750 
01751               if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
01752                      continue;
01753               }
01754 
01755               if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter  ) != LDAP_COMPARE_TRUE ) {
01756                      continue;
01757               }
01758 
01759               break;
01760        } while ( 1 );
01761 
01762        return tl->ecurrent;
01763 }
01764 
01765 static ID
01766 ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
01767 {
01768        struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
01769 
01770        tl->tl_base = base;
01771        tl->tl_scope = scope;
01772        tl->tl_filter = f;
01773 
01774        if ( tl->entries == NULL ) {
01775               Operation op = {0};
01776 
01777               op.o_bd = be;
01778               op.o_req_dn = *be->be_suffix;
01779               op.o_req_ndn = *be->be_nsuffix;
01780               op.ors_scope = LDAP_SCOPE_SUBTREE;
01781               if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) {
01782                      tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */
01783                      return 0; /* fail ldif_tool_entry_get() */
01784               }
01785        }
01786        return ldif_tool_entry_next( be );
01787 }
01788 
01789 static Entry *
01790 ldif_tool_entry_get( BackendDB *be, ID id )
01791 {
01792        struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
01793        Entry *e = NULL;
01794 
01795        --id;
01796        if ( id < tl->ecount ) {
01797               e = tl->entries[id];
01798               tl->entries[id] = NULL;
01799        }
01800        return e;
01801 }
01802 
01803 static ID
01804 ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
01805 {
01806        int rc;
01807        const char *errmsg = NULL;
01808        struct berval path;
01809        char *parentdir;
01810        Operation op = {0};
01811 
01812        op.o_bd = be;
01813        rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg );
01814        if ( rc == LDAP_SUCCESS ) {
01815               rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg );
01816 
01817               SLAP_FREE( path.bv_val );
01818               if ( parentdir != NULL )
01819                      SLAP_FREE( parentdir );
01820               if ( rc == LDAP_SUCCESS )
01821                      return 1;
01822        }
01823 
01824        if ( errmsg == NULL && rc != LDAP_OTHER )
01825               errmsg = ldap_err2string( rc );
01826        if ( errmsg != NULL )
01827               snprintf( text->bv_val, text->bv_len, "%s", errmsg );
01828        return NOID;
01829 }
01830 
01831 
01832 /* Setup */
01833 
01834 static int
01835 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
01836 {
01837        struct ldif_info *li;
01838 
01839        li = ch_calloc( 1, sizeof(struct ldif_info) );
01840        be->be_private = li;
01841        be->be_cf_ocs = ldifocs;
01842        ldap_pvt_thread_mutex_init( &li->li_modop_mutex );
01843        ldap_pvt_thread_rdwr_init( &li->li_rdwr );
01844        SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
01845        return 0;
01846 }
01847 
01848 static int
01849 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
01850 {
01851        struct ldif_info *li = be->be_private;
01852 
01853        ch_free( li->li_base_path.bv_val );
01854        ldap_pvt_thread_rdwr_destroy( &li->li_rdwr );
01855        ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex );
01856        free( be->be_private );
01857        return 0;
01858 }
01859 
01860 static int
01861 ldif_back_db_open( Backend *be, ConfigReply *cr )
01862 {
01863        struct ldif_info *li = (struct ldif_info *) be->be_private;
01864        if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
01865               Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
01866               return 1;
01867        }
01868        return 0;
01869 }
01870 
01871 int
01872 ldif_back_initialize( BackendInfo *bi )
01873 {
01874        static char *controls[] = {
01875               LDAP_CONTROL_MANAGEDSAIT,
01876               NULL
01877        };
01878        int rc;
01879 
01880        bi->bi_flags |=
01881               SLAP_BFLAG_INCREMENT |
01882               SLAP_BFLAG_REFERRALS;
01883 
01884        bi->bi_controls = controls;
01885 
01886        bi->bi_open = 0;
01887        bi->bi_close = 0;
01888        bi->bi_config = 0;
01889        bi->bi_destroy = 0;
01890 
01891        bi->bi_db_init = ldif_back_db_init;
01892        bi->bi_db_config = config_generic_wrapper;
01893        bi->bi_db_open = ldif_back_db_open;
01894        bi->bi_db_close = 0;
01895        bi->bi_db_destroy = ldif_back_db_destroy;
01896 
01897        bi->bi_op_bind = ldif_back_bind;
01898        bi->bi_op_unbind = 0;
01899        bi->bi_op_search = ldif_back_search;
01900        bi->bi_op_compare = 0;
01901        bi->bi_op_modify = ldif_back_modify;
01902        bi->bi_op_modrdn = ldif_back_modrdn;
01903        bi->bi_op_add = ldif_back_add;
01904        bi->bi_op_delete = ldif_back_delete;
01905        bi->bi_op_abandon = 0;
01906 
01907        bi->bi_extended = 0;
01908 
01909        bi->bi_chk_referrals = ldif_back_referrals;
01910 
01911        bi->bi_connection_init = 0;
01912        bi->bi_connection_destroy = 0;
01913 
01914        bi->bi_entry_get_rw = ldif_back_entry_get;
01915 
01916 #if 0  /* NOTE: uncomment to completely disable access control */
01917        bi->bi_access_allowed = slap_access_always_allowed;
01918 #endif
01919 
01920        bi->bi_tool_entry_open = ldif_tool_entry_open;
01921        bi->bi_tool_entry_close = ldif_tool_entry_close;
01922        bi->bi_tool_entry_first = backend_tool_entry_first;
01923        bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
01924        bi->bi_tool_entry_next = ldif_tool_entry_next;
01925        bi->bi_tool_entry_get = ldif_tool_entry_get;
01926        bi->bi_tool_entry_put = ldif_tool_entry_put;
01927        bi->bi_tool_entry_reindex = 0;
01928        bi->bi_tool_sync = 0;
01929 
01930        bi->bi_tool_dn2id_get = 0;
01931        bi->bi_tool_entry_modify = 0;
01932 
01933        bi->bi_cf_ocs = ldifocs;
01934 
01935        rc = config_register_schema( ldifcfg, ldifocs );
01936        if ( rc ) return rc;
01937        return 0;
01938 }