]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldif/ldif.c
Warning cleanup: signed meets unsigned.
[openldap] / servers / slapd / back-ldif / ldif.c
1 /* ldif.c - the ldif backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2005-2008 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
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>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was originally developed by Eric Stokes for inclusion
18  * in OpenLDAP Software.
19  */
20
21 #include "portable.h"
22 #include <stdio.h>
23 #include <ac/string.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <ac/dirent.h>
27 #include <fcntl.h>
28 #include <ac/errno.h>
29 #include <ac/unistd.h>
30 #include "slap.h"
31 #include "lutil.h"
32 #include "config.h"
33
34 typedef struct enumCookie {
35         Operation *op;
36         SlapReply *rs;
37         Entry **entries;
38         ID elen;
39         ID eind;
40 } enumCookie;
41
42 struct ldif_info {
43         struct berval li_base_path;
44         enumCookie li_tool_cookie;
45         ID li_tool_current;
46         ldap_pvt_thread_rdwr_t  li_rdwr;
47 };
48
49 #ifdef _WIN32
50 #define mkdir(a,b)      mkdir(a)
51 #endif
52
53
54 #define LDIF    ".ldif"
55 #define LDIF_FILETYPE_SEP       '.'                     /* LDIF[0] */
56
57 /*
58  * Unsafe/translated characters in the filesystem.
59  *
60  * LDIF_UNSAFE_CHAR(c) returns true if the character c is not to be used
61  * in relative filenames, except it should accept '\\' even if unsafe and
62  * need not reject '{' and '}'.  The value should be a constant expression.
63  *
64  * If '\\' is unsafe, #define LDIF_ESCAPE_CHAR as a safe character.
65  *
66  * If '{' and '}' are unsafe, #define IX_FSL/IX_FSR as safe characters.
67  * (Not digits, '-' or '+'.  IX_FSL == IX_FSR is allowed.)
68  *
69  * Characters are escaped as LDIF_ESCAPE_CHAR followed by two hex digits,
70  * except '\\' is replaced with LDIF_ESCAPE_CHAR and {} with IX_FS[LR].
71  * Also some LDIF special chars are hex-escaped.
72  *
73  * Thus an LDIF filename is a valid normalized RDN (or suffix DN)
74  * followed by ".ldif", except with '\\' replaced with LDIF_ESCAPE_CHAR.
75  */
76
77 #ifndef _WIN32
78
79 /*
80  * Unix/MacOSX version.  ':' vs '/' can cause confusion on MacOSX so we
81  * escape both.  We escape them on Unix so both OS variants get the same
82  * filenames.
83  */
84 #define LDIF_ESCAPE_CHAR        '\\'
85 #define LDIF_UNSAFE_CHAR(c)     ((c) == '/' || (c) == ':')
86
87 #else /* _WIN32 */
88
89 /* Windows version - Microsoft's list of unsafe characters, except '\\' */
90 #define LDIF_ESCAPE_CHAR        '^'
91 #define LDIF_UNSAFE_CHAR(c)     \
92         ((c) == '/' || (c) == ':' || \
93          (c) == '<' || (c) == '>' || (c) == '"' || \
94          (c) == '|' || (c) == '?' || (c) == '*')
95
96 #endif /* !_WIN32 */
97
98 /*
99  * Left and Right "{num}" prefix to ordered RDNs ("olcDatabase={1}bdb").
100  * IX_DN* are for LDAP RDNs, IX_FS* for their .ldif filenames.
101  */
102 #define IX_DNL  '{'
103 #define IX_DNR  '}'
104 #ifndef IX_FSL
105 #define IX_FSL  IX_DNL
106 #define IX_FSR  IX_DNR
107 #endif
108
109 /*
110  * Test for unsafe chars, as well as chars handled specially by back-ldif:
111  * - If the escape char is not '\\', it must itself be escaped.  Otherwise
112  *   '\\' and the escape char would map to the same character.
113  * - Escape the '.' in ".ldif", so the directory for an RDN that actually
114  *   ends with ".ldif" can not conflict with a file of the same name.  And
115  *   since some OSes/programs choke on multiple '.'s, escape all of them.
116  * - If '{' and '}' are translated to some other characters, those
117  *   characters must in turn be escaped when they occur in an RDN.
118  */
119 #ifndef LDIF_NEED_ESCAPE
120 #define LDIF_NEED_ESCAPE(c) \
121         ((LDIF_UNSAFE_CHAR(c)) || \
122          LDIF_MAYBE_UNSAFE(c, LDIF_ESCAPE_CHAR) || \
123          LDIF_MAYBE_UNSAFE(c, LDIF_FILETYPE_SEP) || \
124          LDIF_MAYBE_UNSAFE(c, IX_FSL) || \
125          (IX_FSR != IX_FSL && LDIF_MAYBE_UNSAFE(c, IX_FSR)))
126 #endif
127 /*
128  * Helper macro for LDIF_NEED_ESCAPE(): Treat character x as unsafe if
129  * back-ldif does not already treat is specially.
130  */
131 #define LDIF_MAYBE_UNSAFE(c, x) \
132         (!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \
133          && (c) == (x))
134
135
136 #define ENTRY_BUFF_INCREMENT 500
137
138 static ConfigTable ldifcfg[] = {
139         { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
140                 (void *)offsetof(struct ldif_info, li_base_path),
141                 "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
142                         "DESC 'Directory for database content' "
143                         "EQUALITY caseIgnoreMatch "
144                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
145         { NULL, NULL, 0, 0, 0, ARG_IGNORED,
146                 NULL, NULL, NULL, NULL }
147 };
148
149 static ConfigOCs ldifocs[] = {
150         { "( OLcfgDbOc:2.1 "
151                 "NAME 'olcLdifConfig' "
152                 "DESC 'LDIF backend configuration' "
153                 "SUP olcDatabaseConfig "
154                 "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg },
155         { NULL, 0, NULL }
156 };
157
158
159 /* Set *res = LDIF filename path for the normalized DN */
160 static void
161 dn2path( BackendDB *be, struct berval *dn, struct berval *res )
162 {
163         struct ldif_info *li = (struct ldif_info *) be->be_private;
164         struct berval *suffixdn = &be->be_nsuffix[0];
165         const char *start, *end, *next, *p;
166         char ch, *ptr;
167         ber_len_t len;
168         static const char hex[] = "0123456789ABCDEF";
169
170         assert( dn != NULL );
171         assert( !BER_BVISNULL( dn ) );
172         assert( suffixdn != NULL );
173         assert( !BER_BVISNULL( suffixdn ) );
174         assert( dnIsSuffix( dn, suffixdn ) );
175
176         start = dn->bv_val;
177         end = start + dn->bv_len;
178
179         /* Room for dir, dirsep, dn, LDIF, "\hexpair"-escaping of unsafe chars */
180         len = li->li_base_path.bv_len + dn->bv_len + (1 + STRLENOF( LDIF ));
181         for ( p = start; p < end; ) {
182                 ch = *p++;
183                 if ( LDIF_NEED_ESCAPE( ch ) )
184                         len += 2;
185         }
186         res->bv_val = ch_malloc( len + 1 );
187
188         ptr = lutil_strcopy( res->bv_val, li->li_base_path.bv_val );
189         for ( next = end - suffixdn->bv_len; end > start; end = next ) {
190                 /* Set p = start of DN component, next = &',' or start of DN */
191                 while ( (p = next) > start ) {
192                         --next;
193                         if ( DN_SEPARATOR( *next ) )
194                                 break;
195                 }
196                 /* Append <dirsep> <p..end-1: RDN or database-suffix> */
197                 for ( *ptr++ = LDAP_DIRSEP[0]; p < end; *ptr++ = ch ) {
198                         ch = *p++;
199                         if ( LDIF_ESCAPE_CHAR != '\\' && ch == '\\' ) {
200                                 ch = LDIF_ESCAPE_CHAR;
201                         } else if ( IX_FSL != IX_DNL && ch == IX_DNL ) {
202                                 ch = IX_FSL;
203                         } else if ( IX_FSR != IX_DNR && ch == IX_DNR ) {
204                                 ch = IX_FSR;
205                         } else if ( LDIF_NEED_ESCAPE( ch ) ) {
206                                 *ptr++ = LDIF_ESCAPE_CHAR;
207                                 *ptr++ = hex[(ch & 0xFFU) >> 4];
208                                 ch = hex[ch & 0x0FU];
209                         }
210                 }
211         }
212         ptr = lutil_strcopy( ptr, LDIF );
213         res->bv_len = ptr - res->bv_val;
214
215         assert( res->bv_len <= len );
216 }
217
218 static char * slurp_file(int fd) {
219         int read_chars_total = 0;
220         int read_chars = 0;
221         int entry_size;
222         char * entry;
223         char * entry_pos;
224         struct stat st;
225
226         fstat(fd, &st);
227         entry_size = st.st_size;
228         entry = ch_malloc( entry_size+1 );
229         entry_pos = entry;
230         
231         while(1) {
232                 read_chars = read(fd, (void *) entry_pos, entry_size - read_chars_total);
233                 if(read_chars == -1) {
234                         SLAP_FREE(entry);
235                         return NULL;
236                 }
237                 if(read_chars == 0) {
238                         entry[read_chars_total] = '\0';
239                         break;
240                 }
241                 else {
242                         read_chars_total += read_chars;
243                         entry_pos += read_chars;
244                 }
245         }
246         return entry;
247 }
248
249 /*
250  * return nonnegative for success or -1 for error
251  * do not return numbers less than -1
252  */
253 static int spew_file(int fd, char * spew, int len) {
254         int writeres = 0;
255         
256         while(len > 0) {
257                 writeres = write(fd, spew, len);
258                 if(writeres == -1) {
259                         return -1;
260                 }
261                 else {
262                         spew += writeres;
263                         len -= writeres;
264                 }
265         }
266         return writeres;
267 }
268
269 static int
270 spew_entry( Entry * e, struct berval * path, int dolock, int *save_errnop )
271 {
272         int rs, save_errno = 0;
273         int openres;
274         int res, spew_res;
275         int entry_length;
276         char * entry_as_string;
277         char *tmpfname = NULL;
278
279         tmpfname = ch_malloc( path->bv_len + STRLENOF( "XXXXXX" ) + 1 );
280         AC_MEMCPY( tmpfname, path->bv_val, path->bv_len );
281         AC_MEMCPY( &tmpfname[ path->bv_len ], "XXXXXX", STRLENOF( "XXXXXX" ) + 1 );
282
283         openres = mkstemp( tmpfname );
284         if ( openres == -1 ) {
285                 save_errno = errno;
286                 rs = LDAP_UNWILLING_TO_PERFORM;
287                 Debug( LDAP_DEBUG_ANY, "could not create tmpfile \"%s\": %s\n",
288                         tmpfname, STRERROR( save_errno ), 0 );
289
290         } else {
291                 struct berval rdn;
292                 int tmp;
293
294                 /* Only save the RDN onto disk */
295                 dnRdn( &e->e_name, &rdn );
296                 if ( rdn.bv_len != e->e_name.bv_len ) {
297                         e->e_name.bv_val[rdn.bv_len] = '\0';
298                         tmp = e->e_name.bv_len;
299                         e->e_name.bv_len = rdn.bv_len;
300                         rdn.bv_len = tmp;
301                 }
302
303                 spew_res = -2;
304                 if ( dolock ) {
305                         ldap_pvt_thread_mutex_lock(&entry2str_mutex);
306                 }
307
308                 entry_as_string = entry2str(e, &entry_length);
309                 if ( entry_as_string != NULL ) {
310                         spew_res = spew_file( openres,
311                                 entry_as_string, entry_length );
312                         if ( spew_res == -1 ) {
313                                 save_errno = errno;
314                         }
315                 }
316
317                 if ( dolock ) {
318                         ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
319                 }
320
321                 /* Restore full DN */
322                 if ( rdn.bv_len != e->e_name.bv_len ) {
323                         e->e_name.bv_val[e->e_name.bv_len] = ',';
324                         e->e_name.bv_len = rdn.bv_len;
325                 }
326
327                 res = close( openres );
328                 rs = LDAP_UNWILLING_TO_PERFORM;
329
330                 if ( spew_res > -2 ) {
331                         if ( res == -1 || spew_res == -1 ) {
332                                 if ( save_errno == 0 ) {
333                                         save_errno = errno;
334                                 }
335                                 Debug( LDAP_DEBUG_ANY, "write error to tmpfile \"%s\": %s\n",
336                                         tmpfname, STRERROR( save_errno ), 0 );
337
338                         } else {
339                                 res = rename( tmpfname, path->bv_val );
340                                 if ( res == 0 ) {
341                                         rs = LDAP_SUCCESS;
342
343                                 } else {
344                                         save_errno = errno;
345                                         switch ( save_errno ) {
346                                         case ENOENT:
347                                                 rs = LDAP_NO_SUCH_OBJECT;
348                                                 break;
349
350                                         default:
351                                                 break;
352                                         }
353                                 }
354                         }
355                 }
356
357                 if ( rs != LDAP_SUCCESS ) {
358                         unlink( tmpfname );
359                 }
360         }
361
362         ch_free( tmpfname );
363
364         if ( rs != LDAP_SUCCESS && save_errnop != NULL ) {
365                 *save_errnop = save_errno;
366         }
367
368         return rs;
369 }
370
371 static Entry * get_entry_for_fd(int fd,
372         struct berval *pdn,
373         struct berval *pndn)
374 {
375         char * entry = (char *) slurp_file(fd);
376         Entry * ldentry = NULL;
377         
378         /* error reading file */
379         if(entry == NULL) {
380                 goto return_value;
381         }
382
383         ldentry = str2entry(entry);
384         if ( ldentry ) {
385                 struct berval rdn;
386                 rdn = ldentry->e_name;
387                 build_new_dn( &ldentry->e_name, pdn, &rdn, NULL );
388                 ch_free( rdn.bv_val );
389                 rdn = ldentry->e_nname;
390                 build_new_dn( &ldentry->e_nname, pndn, &rdn, NULL );
391                 ch_free( rdn.bv_val );
392         }
393
394  return_value:
395         if(fd != -1) {
396                 if(close(fd) != 0) {
397                         /* log error */
398                 }
399         }
400         if(entry != NULL)
401                 SLAP_FREE(entry);
402         return ldentry;
403 }
404
405 static int
406 get_entry(
407         Operation *op,
408         Entry **entryp,
409         struct berval *pathp )
410 {
411         int rc;
412         struct berval path, pdn, pndn;
413         int fd;
414
415         dnParent(&op->o_req_dn, &pdn);
416         dnParent(&op->o_req_ndn, &pndn);
417         dn2path( op->o_bd, &op->o_req_ndn, &path );
418         fd = open(path.bv_val, O_RDONLY);
419         /* error opening file (mebbe should log error) */
420         if ( fd == -1 && ( errno != ENOENT || op->o_tag != LDAP_REQ_ADD ) ) {
421                 Debug( LDAP_DEBUG_ANY, "failed to open file \"%s\": %s\n",
422                         path.bv_val, STRERROR(errno), 0 );
423         }
424         *entryp = fd < 0 ? NULL : get_entry_for_fd( fd, &pdn, &pndn );
425         rc = *entryp ? LDAP_SUCCESS : LDAP_NO_SUCH_OBJECT;
426
427         if ( rc == LDAP_SUCCESS && pathp != NULL ) {
428                 *pathp = path;
429         } else {
430                 SLAP_FREE(path.bv_val);
431         }
432         return rc;
433 }
434
435 static void fullpath(struct berval *base, struct berval *name, struct berval *res) {
436         char *ptr;
437         res->bv_len = name->bv_len + base->bv_len + 1;
438         res->bv_val = ch_malloc( res->bv_len + 1 );
439         strcpy(res->bv_val, base->bv_val);
440         ptr = res->bv_val + base->bv_len;
441         *ptr++ = LDAP_DIRSEP[0];
442         strcpy(ptr, name->bv_val);
443 }
444
445 typedef struct bvlist {
446         struct bvlist *next;
447         struct berval bv;
448         struct berval num;
449         int inum;
450         int off;
451 } bvlist;
452
453
454 static int r_enum_tree(enumCookie *ck, struct berval *path, int base,
455         struct berval *pdn, struct berval *pndn)
456 {
457         Entry *e = NULL;
458         int fd = 0, rc = LDAP_SUCCESS;
459
460         if ( !base ) {
461                 fd = open( path->bv_val, O_RDONLY );
462                 if ( fd < 0 ) {
463                         Debug( LDAP_DEBUG_TRACE,
464                                 "=> ldif_enum_tree: failed to open %s: %s\n",
465                                 path->bv_val, STRERROR(errno), 0 );
466                         return LDAP_NO_SUCH_OBJECT;
467                 }
468
469                 e = get_entry_for_fd(fd, pdn, pndn);
470                 if ( !e ) {
471                         Debug( LDAP_DEBUG_ANY,
472                                 "=> ldif_enum_tree: failed to read entry for %s\n",
473                                 path->bv_val, 0, 0 );
474                         return LDAP_BUSY;
475                 }
476
477                 if ( ck->op->ors_scope == LDAP_SCOPE_BASE ||
478                         ck->op->ors_scope == LDAP_SCOPE_SUBTREE ) {
479                         /* Send right away? */
480                         if ( ck->rs ) {
481                                 /*
482                                  * if it's a referral, add it to the list of referrals. only do
483                                  * this for non-base searches, and don't check the filter
484                                  * explicitly here since it's only a candidate anyway.
485                                  */
486                                 if ( !get_manageDSAit( ck->op )
487                                                 && ck->op->ors_scope != LDAP_SCOPE_BASE
488                                                 && is_entry_referral( e ) )
489                                 {
490                                         BerVarray erefs = get_entry_referrals( ck->op, e );
491                                         ck->rs->sr_ref = referral_rewrite( erefs,
492                                                         &e->e_name, NULL,
493                                                         ck->op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL
494                                                                 ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );
495         
496                                         ck->rs->sr_entry = e;
497                                         rc = send_search_reference( ck->op, ck->rs );
498                                         ber_bvarray_free( ck->rs->sr_ref );
499                                         ber_bvarray_free( erefs );
500                                         ck->rs->sr_ref = NULL;
501                                         ck->rs->sr_entry = NULL;
502         
503                                 } else if ( test_filter( ck->op, e, ck->op->ors_filter ) == LDAP_COMPARE_TRUE )
504                                 {
505                                         ck->rs->sr_entry = e;
506                                         ck->rs->sr_attrs = ck->op->ors_attrs;
507                                         ck->rs->sr_flags = REP_ENTRY_MODIFIABLE;
508                                         rc = send_search_entry(ck->op, ck->rs);
509                                         ck->rs->sr_entry = NULL;
510                                 }
511                                 fd = 1;
512                                 if ( rc )
513                                         goto done;
514                         } else {
515                         /* Queueing up for tool mode */
516                                 if(ck->entries == NULL) {
517                                         ck->entries = (Entry **) ch_malloc(sizeof(Entry *) * ENTRY_BUFF_INCREMENT);
518                                         ck->elen = ENTRY_BUFF_INCREMENT;
519                                 }
520                                 if(ck->eind >= ck->elen) { /* grow entries if necessary */      
521                                         ck->entries = (Entry **) ch_realloc(ck->entries, sizeof(Entry *) * (ck->elen) * 2);
522                                         ck->elen *= 2;
523                                 }
524         
525                                 ck->entries[ck->eind++] = e;
526                                 fd = 0;
527                         }
528                 } else {
529                         fd = 1;
530                 }
531         }
532
533         if ( ck->op->ors_scope != LDAP_SCOPE_BASE ) {
534                 DIR * dir_of_path;
535                 bvlist *list = NULL, *ptr;
536
537                 path->bv_len -= STRLENOF( LDIF );
538                 path->bv_val[path->bv_len] = '\0';
539
540                 dir_of_path = opendir(path->bv_val);
541                 if(dir_of_path == NULL) { /* can't open directory */
542                         if ( errno != ENOENT ) {
543                                 /* it shouldn't be treated as an error
544                                  * only if the directory doesn't exist */
545                                 rc = LDAP_BUSY;
546                                 Debug( LDAP_DEBUG_ANY,
547                                         "=> ldif_enum_tree: failed to opendir %s (%d)\n",
548                                         path->bv_val, errno, 0 );
549                         }
550                         goto done;
551                 }
552         
553                 while(1) {
554                         struct berval fname, itmp;
555                         struct dirent * dir;
556                         bvlist *bvl, **prev;
557
558                         dir = readdir(dir_of_path);
559                         if(dir == NULL) break; /* end of the directory */
560                         fname.bv_len = strlen( dir->d_name );
561                         if ( fname.bv_len <= STRLENOF( LDIF ))
562                                 continue;
563                         if ( strcmp( dir->d_name + (fname.bv_len - STRLENOF(LDIF)), LDIF))
564                                 continue;
565                         fname.bv_val = dir->d_name;
566
567                         bvl = ch_malloc( sizeof(bvlist) );
568                         ber_dupbv( &bvl->bv, &fname );
569                         BER_BVZERO( &bvl->num );
570                         itmp.bv_val = ber_bvchr( &bvl->bv, IX_FSL );
571                         if ( itmp.bv_val ) {
572                                 char *ptr;
573                                 itmp.bv_val++;
574                                 itmp.bv_len = bvl->bv.bv_len
575                                         - ( itmp.bv_val - bvl->bv.bv_val );
576                                 ptr = ber_bvchr( &itmp, IX_FSR );
577                                 if ( ptr ) {
578                                         itmp.bv_len = ptr - itmp.bv_val;
579                                         ber_dupbv( &bvl->num, &itmp );
580                                         bvl->inum = strtol( itmp.bv_val, NULL, 0 );
581                                         itmp.bv_val[0] = '\0';
582                                         bvl->off = itmp.bv_val - bvl->bv.bv_val;
583                                 }
584                         }
585
586                         for (prev = &list; (ptr = *prev) != NULL; prev = &ptr->next) {
587                                 int cmp = strcmp( bvl->bv.bv_val, ptr->bv.bv_val );
588                                 if ( !cmp && bvl->num.bv_val )
589                                         cmp = bvl->inum - ptr->inum;
590                                 if ( cmp < 0 )
591                                         break;
592                         }
593                         *prev = bvl;
594                         bvl->next = ptr;
595                                 
596                 }
597                 closedir(dir_of_path);
598
599                 if (ck->op->ors_scope == LDAP_SCOPE_ONELEVEL)
600                         ck->op->ors_scope = LDAP_SCOPE_BASE;
601                 else if ( ck->op->ors_scope == LDAP_SCOPE_SUBORDINATE)
602                         ck->op->ors_scope = LDAP_SCOPE_SUBTREE;
603
604                 while ( ( ptr = list ) ) {
605                         struct berval fpath;
606
607                         list = ptr->next;
608
609                         if ( rc == LDAP_SUCCESS ) {
610                                 if ( ptr->num.bv_val )
611                                         AC_MEMCPY( ptr->bv.bv_val + ptr->off, ptr->num.bv_val,
612                                                 ptr->num.bv_len );
613                                 fullpath( path, &ptr->bv, &fpath );
614                                 rc = r_enum_tree(ck, &fpath, 0,
615                                         e != NULL ? &e->e_name : pdn,
616                                         e != NULL ? &e->e_nname : pndn );
617                                 free(fpath.bv_val);
618                         }
619                         if ( ptr->num.bv_val )
620                                 free( ptr->num.bv_val );
621                         free(ptr->bv.bv_val);
622                         free(ptr);
623                 }
624         }
625 done:
626         if ( fd ) entry_free( e );
627         return rc;
628 }
629
630 static int
631 enum_tree(
632         enumCookie *ck
633 )
634 {
635         struct berval path;
636         struct berval pdn, pndn;
637         int rc;
638
639         dnParent( &ck->op->o_req_dn, &pdn );
640         dnParent( &ck->op->o_req_ndn, &pndn );
641         dn2path( ck->op->o_bd, &ck->op->o_req_ndn, &path );
642         rc = r_enum_tree(ck, &path, BER_BVISEMPTY( &ck->op->o_req_ndn ) ? 1 : 0, &pdn, &pndn);
643         ch_free( path.bv_val );
644         return rc;
645 }
646
647
648 /* Get the parent directory path, plus the LDIF suffix overwritten by a \0 */
649 static void
650 get_parent_path( struct berval *dnpath, struct berval *res )
651 {
652         int dnpathlen = dnpath->bv_len;
653         int i;
654         
655         for(i = dnpathlen;i>0;i--) /* find the first path seperator */
656                 if(dnpath->bv_val[i] == LDAP_DIRSEP[0])
657                         break;
658         res->bv_len = i;
659         res->bv_val = ch_malloc( res->bv_len + 1 + STRLENOF(LDIF) );
660         strncpy(res->bv_val, dnpath->bv_val, i);
661         strcpy(res->bv_val+i, LDIF);
662         res->bv_val[i] = '\0';
663 }
664
665 static int apply_modify_to_entry(Entry * entry,
666                                 Modifications * modlist,
667                                 Operation * op,
668                                 SlapReply * rs)
669 {
670         char textbuf[SLAP_TEXT_BUFLEN];
671         int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS;
672         int is_oc = 0;
673         Modification *mods;
674
675         if (!acl_check_modlist(op, entry, modlist)) {
676                 return LDAP_INSUFFICIENT_ACCESS;
677         }
678
679         for (; modlist != NULL; modlist = modlist->sml_next) {
680                 mods = &modlist->sml_mod;
681
682                 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
683                         is_oc = 1;
684                 }
685                 switch (mods->sm_op) {
686                 case LDAP_MOD_ADD:
687                         rc = modify_add_values(entry, mods,
688                                    get_permissiveModify(op),
689                                    &rs->sr_text, textbuf,
690                                    sizeof( textbuf ) );
691                         break;
692                                 
693                 case LDAP_MOD_DELETE:
694                         rc = modify_delete_values(entry, mods,
695                                 get_permissiveModify(op),
696                                 &rs->sr_text, textbuf,
697                                 sizeof( textbuf ) );
698                         break;
699                                 
700                 case LDAP_MOD_REPLACE:
701                         rc = modify_replace_values(entry, mods,
702                                  get_permissiveModify(op),
703                                  &rs->sr_text, textbuf,
704                                  sizeof( textbuf ) );
705                         break;
706
707                 case LDAP_MOD_INCREMENT:
708                         rc = modify_increment_values( entry,
709                                 mods, get_permissiveModify(op),
710                                 &rs->sr_text, textbuf,
711                                 sizeof( textbuf ) );
712                         break;
713
714                 case SLAP_MOD_SOFTADD:
715                         mods->sm_op = LDAP_MOD_ADD;
716                         rc = modify_add_values(entry, mods,
717                                    get_permissiveModify(op),
718                                    &rs->sr_text, textbuf,
719                                    sizeof( textbuf ) );
720                         mods->sm_op = SLAP_MOD_SOFTADD;
721                         if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
722                                 rc = LDAP_SUCCESS;
723                         }
724                         break;
725                 }
726                 if(rc != LDAP_SUCCESS) break;
727         }
728
729         if(rc == LDAP_SUCCESS) {
730                 if ( is_oc ) {
731                         entry->e_ocflags = 0;
732                 }
733                 /* check that the entry still obeys the schema */
734                 rc = entry_schema_check( op, entry, NULL, 0, 0,
735                           &rs->sr_text, textbuf, sizeof( textbuf ) );
736         }
737
738         return rc;
739 }
740
741 int
742 ldif_back_referrals( Operation *op, SlapReply *rs )
743 {
744         struct ldif_info        *li = NULL;
745         Entry                   *entry;
746         int                     rc = LDAP_SUCCESS;
747
748 #if 0
749         if ( op->o_tag == LDAP_REQ_SEARCH ) {
750                 /* let search take care of itself */
751                 return rc;
752         }
753 #endif
754
755         if ( get_manageDSAit( op ) ) {
756                 /* let op take care of DSA management */
757                 return rc;
758         }
759
760         if ( BER_BVISEMPTY( &op->o_req_ndn ) ) {
761                 /* the empty DN cannot be a referral */
762                 return rc;
763         }
764
765         li = (struct ldif_info *)op->o_bd->be_private;
766         ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
767         get_entry( op, &entry, NULL );
768
769         /* no object is found for them */
770         if ( entry == NULL ) {
771                 struct berval   odn = op->o_req_dn;
772                 struct berval   ondn = op->o_req_ndn;
773                 struct berval   pndn = ondn;
774                 ber_len_t               min_dnlen = op->o_bd->be_nsuffix[0].bv_len;
775
776                 if ( min_dnlen == 0 )
777                         min_dnlen = 1;     /* catch empty DN */
778
779                 for ( ; entry == NULL; ) {
780                         dnParent( &pndn, &pndn );
781                         if ( pndn.bv_len < min_dnlen ) {
782                                 break;
783                         }
784
785                         op->o_req_dn = pndn;
786                         op->o_req_ndn = pndn;
787
788                         get_entry( op, &entry, NULL );
789                 }
790
791                 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
792
793                 op->o_req_dn = odn;
794                 op->o_req_ndn = ondn;
795
796                 rc = LDAP_SUCCESS;
797                 rs->sr_matched = NULL;
798                 if ( entry != NULL ) {
799                         Debug( LDAP_DEBUG_TRACE,
800                                 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
801                                 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val );
802
803                         if ( is_entry_referral( entry ) ) {
804                                 rc = LDAP_OTHER;
805                                 rs->sr_ref = get_entry_referrals( op, entry );
806                                 if ( rs->sr_ref ) {
807                                         rs->sr_matched = ber_strdup_x(
808                                         entry->e_name.bv_val, op->o_tmpmemctx );
809                                 }
810                         }
811
812                         entry_free(entry);
813
814                 } else if ( default_referral != NULL ) {
815                         rc = LDAP_OTHER;
816                         rs->sr_ref = referral_rewrite( default_referral,
817                                 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
818                 }
819
820                 if ( rs->sr_ref != NULL ) {
821                         /* send referrals */
822                         rc = rs->sr_err = LDAP_REFERRAL;
823                         send_ldap_result( op, rs );
824                         ber_bvarray_free( rs->sr_ref );
825                         rs->sr_ref = NULL;
826
827                 } else if ( rc != LDAP_SUCCESS ) {
828                         rs->sr_text = rs->sr_matched ? "bad referral object" : NULL;
829                 }
830
831                 if ( rs->sr_matched ) {
832                         op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
833                         rs->sr_matched = NULL;
834                 }
835
836                 return rc;
837         }
838
839         ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
840
841         if ( is_entry_referral( entry ) ) {
842                 /* entry is a referral */
843                 BerVarray refs = get_entry_referrals( op, entry );
844                 rs->sr_ref = referral_rewrite(
845                         refs, &entry->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
846
847                 Debug( LDAP_DEBUG_TRACE,
848                         "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
849                         (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val );
850
851                 rs->sr_matched = entry->e_name.bv_val;
852                 if ( rs->sr_ref != NULL ) {
853                         rc = rs->sr_err = LDAP_REFERRAL;
854                         send_ldap_result( op, rs );
855                         ber_bvarray_free( rs->sr_ref );
856                         rs->sr_ref = NULL;
857
858                 } else {
859                         rc = LDAP_OTHER;
860                         rs->sr_text = "bad referral object";
861                 }
862
863                 rs->sr_matched = NULL;
864                 ber_bvarray_free( refs );
865         }
866
867         entry_free( entry );
868
869         return rc;
870 }
871
872
873 /* LDAP operations */
874
875 static int
876 ldif_back_bind( Operation *op, SlapReply *rs )
877 {
878         struct ldif_info *li;
879         Attribute *a;
880         AttributeDescription *password = slap_schema.si_ad_userPassword;
881         int return_val;
882         Entry *entry;
883
884         switch ( be_rootdn_bind( op, rs ) ) {
885         case SLAP_CB_CONTINUE:
886                 break;
887
888         default:
889                 /* in case of success, front end will send result;
890                  * otherwise, be_rootdn_bind() did */
891                 return rs->sr_err;
892         }
893
894         li = (struct ldif_info *) op->o_bd->be_private;
895         ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
896         return_val = get_entry(op, &entry, NULL);
897
898         /* no object is found for them */
899         if(return_val != LDAP_SUCCESS) {
900                 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
901                 goto return_result;
902         }
903
904         /* they don't have userpassword */
905         if((a = attr_find(entry->e_attrs, password)) == NULL) {
906                 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
907                 return_val = 1;
908                 goto return_result;
909         }
910
911         /* authentication actually failed */
912         if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
913                              &rs->sr_text) != 0) {
914                 rs->sr_err = LDAP_INVALID_CREDENTIALS;
915                 return_val = 1;
916                 goto return_result;
917         }
918
919         /* let the front-end send success */
920         return_val = 0;
921         goto return_result;
922
923  return_result:
924         ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
925         if(return_val != 0)
926                 send_ldap_result( op, rs );
927         if(entry != NULL)
928                 entry_free(entry);
929         return return_val;
930 }
931
932 static int ldif_back_search(Operation *op, SlapReply *rs)
933 {
934         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
935         enumCookie ck = { NULL, NULL, NULL, 0, 0 };
936
937         ck.op = op;
938         ck.rs = rs;
939         ldap_pvt_thread_rdwr_rlock(&li->li_rdwr);
940         rs->sr_err = enum_tree( &ck );
941         ldap_pvt_thread_rdwr_runlock(&li->li_rdwr);
942         send_ldap_result(op, rs);
943
944         return rs->sr_err;
945 }
946
947 static int ldif_back_add(Operation *op, SlapReply *rs) {
948         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
949         Entry * e = op->ora_e;
950         struct berval dn = e->e_nname;
951         struct berval leaf_path = BER_BVNULL;
952         struct stat stats;
953         int statres;
954         char textbuf[SLAP_TEXT_BUFLEN];
955
956         Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", dn.bv_val, 0, 0);
957
958         rs->sr_err = entry_schema_check(op, e, NULL, 0, 1,
959                 &rs->sr_text, textbuf, sizeof( textbuf ) );
960         if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
961
962         rs->sr_err = slap_add_opattrs( op,
963                 &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
964         if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
965
966         ldap_pvt_thread_rdwr_wlock(&li->li_rdwr);
967
968         dn2path( op->o_bd, &dn, &leaf_path );
969
970         if(leaf_path.bv_val != NULL) {
971                 struct berval base = BER_BVNULL;
972                 /* build path to container and ldif of container */
973                 get_parent_path(&leaf_path, &base);
974
975                 statres = stat(base.bv_val, &stats); /* check if container exists */
976                 if(statres == -1 && errno == ENOENT) { /* container missing */
977                         base.bv_val[base.bv_len] = LDIF_FILETYPE_SEP;
978                         statres = stat(base.bv_val, &stats); /* check for leaf node */
979                         base.bv_val[base.bv_len] = '\0';
980                         if(statres == -1 && errno == ENOENT) {
981                                 rs->sr_err = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
982                                 rs->sr_text = "Parent does not exist";
983                         }
984                         else if(statres != -1) { /* create parent */
985                                 int mkdirres = mkdir(base.bv_val, 0750);
986                                 if(mkdirres == -1) {
987                                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
988                                         rs->sr_text = "Could not create parent folder";
989                                         Debug( LDAP_DEBUG_ANY, "could not create folder \"%s\": %s\n",
990                                                 base.bv_val, STRERROR( errno ), 0 );
991                                 }
992                         }
993                         else
994                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
995                 }/* container was possibly created, move on to add the entry */
996                 if(rs->sr_err == LDAP_SUCCESS) {
997                         statres = stat(leaf_path.bv_val, &stats);
998                         if(statres == -1 && errno == ENOENT) {
999                                 rs->sr_err = spew_entry(e, &leaf_path, 1, NULL);
1000                         }
1001                         else if ( statres == -1 ) {
1002                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1003                                 Debug( LDAP_DEBUG_ANY, "could not stat file \"%s\": %s\n",
1004                                         leaf_path.bv_val, STRERROR( errno ), 0 );
1005                         }
1006                         else /* it already exists */
1007                                 rs->sr_err = LDAP_ALREADY_EXISTS;
1008                 }
1009                 SLAP_FREE(base.bv_val);
1010                 SLAP_FREE(leaf_path.bv_val);
1011         }
1012
1013         ldap_pvt_thread_rdwr_wunlock(&li->li_rdwr);
1014
1015 send_res:
1016         Debug( LDAP_DEBUG_TRACE, 
1017                         "ldif_back_add: err: %d text: %s\n", rs->sr_err, rs->sr_text ?
1018                                 rs->sr_text : "", 0);
1019         send_ldap_result(op, rs);
1020         slap_graduate_commit_csn( op );
1021         return rs->sr_err;
1022 }
1023
1024 static int ldif_back_modify(Operation *op, SlapReply *rs) {
1025         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1026         Modifications * modlst = op->orm_modlist;
1027         struct berval path;
1028         Entry *entry;
1029         int spew_res;
1030
1031         slap_mods_opattrs( op, &op->orm_modlist, 1 );
1032
1033         ldap_pvt_thread_rdwr_wlock(&li->li_rdwr);
1034
1035         rs->sr_err = get_entry( op, &entry, &path );
1036         if(entry != NULL) {
1037                 rs->sr_err = apply_modify_to_entry(entry, modlst, op, rs);
1038                 if(rs->sr_err == LDAP_SUCCESS) {
1039                         int save_errno;
1040                         spew_res = spew_entry(entry, &path, 1, &save_errno);
1041                         if(spew_res == -1) {
1042                                 Debug( LDAP_DEBUG_ANY,
1043                                         "%s ldif_back_modify: could not output entry \"%s\": %s\n",
1044                                         op->o_log_prefix, entry->e_name.bv_val, STRERROR( save_errno ) );
1045                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1046                         }
1047                 }
1048
1049                 entry_free( entry );
1050                 SLAP_FREE( path.bv_val );
1051         }
1052
1053         rs->sr_text = NULL;
1054         ldap_pvt_thread_rdwr_wunlock(&li->li_rdwr);
1055         send_ldap_result(op, rs);
1056         slap_graduate_commit_csn( op );
1057         return rs->sr_err;
1058 }
1059
1060 static int ldif_back_delete(Operation *op, SlapReply *rs) {
1061         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1062         struct berval path;
1063         int res = 0;
1064
1065         if ( BER_BVISEMPTY( &op->o_csn )) {
1066                 struct berval csn;
1067                 char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
1068
1069                 csn.bv_val = csnbuf;
1070                 csn.bv_len = sizeof( csnbuf );
1071                 slap_get_csn( op, &csn, 1 );
1072         }
1073
1074         ldap_pvt_thread_rdwr_wlock(&li->li_rdwr);
1075
1076         dn2path( op->o_bd, &op->o_req_ndn, &path );
1077         path.bv_val[path.bv_len - STRLENOF(LDIF)] = '\0';
1078         res = rmdir(path.bv_val);
1079         path.bv_val[path.bv_len - STRLENOF(LDIF)] = LDIF_FILETYPE_SEP;
1080         rs->sr_err = LDAP_SUCCESS;
1081         if ( res ) {
1082                 switch ( errno ) {
1083                 case ENOTEMPTY:
1084                         rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
1085                         break;
1086
1087                 case ENOENT:
1088                         /* is leaf, go on */
1089                         res = 0;
1090                         break;
1091
1092                 default:
1093                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1094                         break;
1095                 }
1096         }
1097
1098         if ( !res ) {
1099                 res = unlink(path.bv_val);
1100                 if ( res == -1 ) {
1101                         switch ( errno ) {
1102                         case ENOENT:
1103                                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1104                                 break;
1105
1106                         default:
1107                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1108                                 break;
1109                         }
1110                 }
1111         }
1112
1113         SLAP_FREE(path.bv_val);
1114         ldap_pvt_thread_rdwr_wunlock(&li->li_rdwr);
1115         send_ldap_result(op, rs);
1116         slap_graduate_commit_csn( op );
1117         return rs->sr_err;
1118 }
1119
1120
1121 static int
1122 ldif_move_entry(
1123         Operation *op,
1124         Entry *entry,
1125         struct berval *oldpath )
1126 {
1127         int res;
1128         int exists_res;
1129         struct berval newpath;
1130
1131         dn2path( op->o_bd, &entry->e_nname, &newpath );
1132
1133         if((entry == NULL || oldpath->bv_val == NULL) || newpath.bv_val == NULL) {
1134                 /* some object doesn't exist */
1135                 res = LDAP_NO_SUCH_OBJECT;
1136         }
1137         else { /* do the modrdn */
1138                 exists_res = open(newpath.bv_val, O_RDONLY);
1139                 if(exists_res == -1 && errno == ENOENT) {
1140                         ldap_pvt_thread_mutex_lock( &entry2str_mutex );
1141                         res = spew_entry(entry, &newpath, 0, NULL);
1142                         if(res != -1) {
1143                                 /* if this fails we should log something bad */
1144                                 res = unlink( oldpath->bv_val );
1145                                 oldpath->bv_val[oldpath->bv_len - STRLENOF(".ldif")] = '\0';
1146                                 newpath.bv_val[newpath.bv_len - STRLENOF(".ldif")] = '\0';
1147                                 res = rename( oldpath->bv_val, newpath.bv_val );
1148                                 res = LDAP_SUCCESS;
1149                         }
1150                         else {
1151                                 if(errno == ENOENT)
1152                                         res = LDAP_NO_SUCH_OBJECT;
1153                                 else
1154                                         res = LDAP_UNWILLING_TO_PERFORM;
1155                                 unlink(newpath.bv_val); /* in case file was created */
1156                         }
1157                         ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
1158                 }
1159                 else if(exists_res) {
1160                         int close_res = close(exists_res);
1161                         res = LDAP_ALREADY_EXISTS;
1162                         if(close_res == -1) {
1163                         /* log heinous error */
1164                         }
1165                 }
1166                 else {
1167                         res = LDAP_UNWILLING_TO_PERFORM;
1168                 }
1169         }
1170
1171         if(newpath.bv_val != NULL)
1172                 SLAP_FREE(newpath.bv_val);
1173         return res;
1174 }
1175
1176 static int
1177 ldif_back_modrdn(Operation *op, SlapReply *rs)
1178 {
1179         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1180         struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
1181         struct berval p_dn, old_path;
1182         Entry *entry;
1183         int rc;
1184
1185         slap_mods_opattrs( op, &op->orr_modlist, 1 );
1186
1187         ldap_pvt_thread_rdwr_wlock( &li->li_rdwr );
1188
1189         rc = get_entry( op, &entry, &old_path );
1190         if ( rc == LDAP_SUCCESS ) {
1191                 /* build new dn, and new ndn for the entry */
1192                 if ( op->oq_modrdn.rs_newSup != NULL ) {
1193                         struct berval   op_dn = op->o_req_dn,
1194                                         op_ndn = op->o_req_ndn;
1195                         Entry           *np;
1196
1197                         /* new superior */
1198                         p_dn = *op->oq_modrdn.rs_newSup;
1199                         op->o_req_dn = *op->oq_modrdn.rs_newSup;
1200                         op->o_req_ndn = *op->oq_modrdn.rs_nnewSup;
1201                         rc = get_entry( op, &np, NULL );
1202                         op->o_req_dn = op_dn;
1203                         op->o_req_ndn = op_ndn;
1204                         if ( rc != LDAP_SUCCESS ) {
1205                                 goto no_such_object;
1206                         }
1207                         entry_free( np );
1208                 } else {
1209                         dnParent( &entry->e_name, &p_dn );
1210                 }
1211                 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL ); 
1212                 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL );
1213                 ber_memfree_x( entry->e_name.bv_val, NULL );
1214                 ber_memfree_x( entry->e_nname.bv_val, NULL );
1215                 entry->e_name = new_dn;
1216                 entry->e_nname = new_ndn;
1217
1218                 /* perform the modifications */
1219                 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs );
1220                 if ( rc == LDAP_SUCCESS )
1221                         rc = ldif_move_entry( op, entry, &old_path );
1222
1223 no_such_object:;
1224                 entry_free( entry );
1225                 SLAP_FREE( old_path.bv_val );
1226         }
1227
1228         rs->sr_text = "";
1229         ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr );
1230         rs->sr_err = rc;
1231         send_ldap_result( op, rs );
1232         slap_graduate_commit_csn( op );
1233         return rs->sr_err;
1234 }
1235
1236
1237 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1238 static int
1239 ldif_back_entry_get(
1240         Operation *op,
1241         struct berval *ndn,
1242         ObjectClass *oc,
1243         AttributeDescription *at,
1244         int rw,
1245         Entry **e )
1246 {
1247         struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private;
1248         struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn;
1249         int rc;
1250
1251         assert( ndn != NULL );
1252         assert( !BER_BVISNULL( ndn ) );
1253
1254         ldap_pvt_thread_rdwr_rlock( &li->li_rdwr );
1255         op->o_req_dn = *ndn;
1256         op->o_req_ndn = *ndn;
1257         rc = get_entry( op, e, NULL );
1258         op->o_req_dn = op_dn;
1259         op->o_req_ndn = op_ndn;
1260         ldap_pvt_thread_rdwr_runlock( &li->li_rdwr );
1261
1262         if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) {
1263                 rc = LDAP_NO_SUCH_ATTRIBUTE;
1264                 entry_free( *e );
1265                 *e = NULL;
1266         }
1267
1268         return rc;
1269 }
1270
1271
1272 /* Slap tools */
1273
1274 static int ldif_tool_entry_open(BackendDB *be, int mode) {
1275         struct ldif_info *li = (struct ldif_info *) be->be_private;
1276         li->li_tool_current = 0;
1277         return 0;
1278 }                                       
1279
1280 static int ldif_tool_entry_close(BackendDB * be) {
1281         struct ldif_info *li = (struct ldif_info *) be->be_private;
1282
1283         SLAP_FREE(li->li_tool_cookie.entries);
1284         return 0;
1285 }
1286
1287 static ID ldif_tool_entry_next(BackendDB *be)
1288 {
1289         struct ldif_info *li = (struct ldif_info *) be->be_private;
1290         if(li->li_tool_current >= li->li_tool_cookie.eind)
1291                 return NOID;
1292         else
1293                 return ++li->li_tool_current;
1294 }
1295
1296 static ID
1297 ldif_tool_entry_first(BackendDB *be)
1298 {
1299         struct ldif_info *li = (struct ldif_info *) be->be_private;
1300
1301         if(li->li_tool_cookie.entries == NULL) {
1302                 Operation op = {0};
1303
1304                 op.o_bd = be;
1305                 op.o_req_dn = *be->be_suffix;
1306                 op.o_req_ndn = *be->be_nsuffix;
1307                 op.ors_scope = LDAP_SCOPE_SUBTREE;
1308                 li->li_tool_cookie.op = &op;
1309                 (void)enum_tree( &li->li_tool_cookie );
1310                 li->li_tool_cookie.op = NULL;
1311         }
1312         return ldif_tool_entry_next( be );
1313 }
1314
1315 static Entry * ldif_tool_entry_get(BackendDB * be, ID id) {
1316         struct ldif_info *li = (struct ldif_info *) be->be_private;
1317         Entry * e;
1318
1319         if(id > li->li_tool_cookie.eind || id < 1)
1320                 return NULL;
1321         else {
1322                 e = li->li_tool_cookie.entries[id - 1];
1323                 li->li_tool_cookie.entries[id - 1] = NULL;
1324                 return e;
1325         }
1326 }
1327
1328 static ID ldif_tool_entry_put(BackendDB * be, Entry * e, struct berval *text) {
1329         struct berval leaf_path = BER_BVNULL;
1330         struct stat stats;
1331         int statres;
1332         int res = LDAP_SUCCESS;
1333
1334         dn2path( be, &e->e_nname, &leaf_path );
1335
1336         if(leaf_path.bv_val != NULL) {
1337                 struct berval base = BER_BVNULL;
1338                 /* build path to container, and path to ldif of container */
1339                 get_parent_path(&leaf_path, &base);
1340
1341                 statres = stat(base.bv_val, &stats); /* check if container exists */
1342                 if(statres == -1 && errno == ENOENT) { /* container missing */
1343                         base.bv_val[base.bv_len] = LDIF_FILETYPE_SEP;
1344                         statres = stat(base.bv_val, &stats); /* check for leaf node */
1345                         base.bv_val[base.bv_len] = '\0';
1346                         if(statres == -1 && errno == ENOENT) {
1347                                 res = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
1348                         }
1349                         else if(statres != -1) { /* create parent */
1350                                 int mkdirres = mkdir(base.bv_val, 0750);
1351                                 if(mkdirres == -1) {
1352                                         res = LDAP_UNWILLING_TO_PERFORM;
1353                                 }
1354                         }
1355                         else
1356                                 res = LDAP_UNWILLING_TO_PERFORM;
1357                 }/* container was possibly created, move on to add the entry */
1358                 if(res == LDAP_SUCCESS) {
1359                         statres = stat(leaf_path.bv_val, &stats);
1360                         if(statres == -1 && errno == ENOENT) {
1361                                 res = spew_entry(e, &leaf_path, 0, NULL);
1362                         }
1363                         else /* it already exists */
1364                                 res = LDAP_ALREADY_EXISTS;
1365                 }
1366                 SLAP_FREE(base.bv_val);
1367                 SLAP_FREE(leaf_path.bv_val);
1368         }
1369
1370         if(res == LDAP_SUCCESS) {
1371                 return 1;
1372         }
1373         else
1374                 return NOID;
1375 }
1376
1377
1378 /* Setup */
1379
1380 static int
1381 ldif_back_db_init( BackendDB *be, ConfigReply *cr )
1382 {
1383         struct ldif_info *li;
1384
1385         li = ch_calloc( 1, sizeof(struct ldif_info) );
1386         be->be_private = li;
1387         be->be_cf_ocs = ldifocs;
1388         ldap_pvt_thread_rdwr_init(&li->li_rdwr);
1389         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
1390         return 0;
1391 }
1392
1393 static int
1394 ldif_back_db_destroy( Backend *be, ConfigReply *cr )
1395 {
1396         struct ldif_info *li = be->be_private;
1397
1398         ch_free(li->li_base_path.bv_val);
1399         ldap_pvt_thread_rdwr_destroy(&li->li_rdwr);
1400         free( be->be_private );
1401         return 0;
1402 }
1403
1404 static int
1405 ldif_back_db_open( Backend *be, ConfigReply *cr)
1406 {
1407         struct ldif_info *li = (struct ldif_info *) be->be_private;
1408         if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */
1409                 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0);
1410                 return 1;
1411         }
1412         return 0;
1413 }
1414
1415 int
1416 ldif_back_initialize(
1417                            BackendInfo  *bi
1418                            )
1419 {
1420         static char *controls[] = {
1421                 LDAP_CONTROL_MANAGEDSAIT,
1422                 NULL
1423         };
1424         int rc;
1425
1426         bi->bi_flags |=
1427                 SLAP_BFLAG_INCREMENT |
1428                 SLAP_BFLAG_REFERRALS;
1429
1430         bi->bi_controls = controls;
1431
1432         bi->bi_open = 0;
1433         bi->bi_close = 0;
1434         bi->bi_config = 0;
1435         bi->bi_destroy = 0;
1436
1437         bi->bi_db_init = ldif_back_db_init;
1438         bi->bi_db_config = config_generic_wrapper;
1439         bi->bi_db_open = ldif_back_db_open;
1440         bi->bi_db_close = 0;
1441         bi->bi_db_destroy = ldif_back_db_destroy;
1442
1443         bi->bi_op_bind = ldif_back_bind;
1444         bi->bi_op_unbind = 0;
1445         bi->bi_op_search = ldif_back_search;
1446         bi->bi_op_compare = 0;
1447         bi->bi_op_modify = ldif_back_modify;
1448         bi->bi_op_modrdn = ldif_back_modrdn;
1449         bi->bi_op_add = ldif_back_add;
1450         bi->bi_op_delete = ldif_back_delete;
1451         bi->bi_op_abandon = 0;
1452
1453         bi->bi_extended = 0;
1454
1455         bi->bi_chk_referrals = ldif_back_referrals;
1456
1457         bi->bi_connection_init = 0;
1458         bi->bi_connection_destroy = 0;
1459
1460         bi->bi_entry_get_rw = ldif_back_entry_get;
1461
1462 #if 0   /* NOTE: uncomment to completely disable access control */
1463         bi->bi_access_allowed = slap_access_always_allowed;
1464 #endif
1465
1466         bi->bi_tool_entry_open = ldif_tool_entry_open;
1467         bi->bi_tool_entry_close = ldif_tool_entry_close;
1468         bi->bi_tool_entry_first = ldif_tool_entry_first;
1469         bi->bi_tool_entry_next = ldif_tool_entry_next;
1470         bi->bi_tool_entry_get = ldif_tool_entry_get;
1471         bi->bi_tool_entry_put = ldif_tool_entry_put;
1472         bi->bi_tool_entry_reindex = 0;
1473         bi->bi_tool_sync = 0;
1474         
1475         bi->bi_tool_dn2id_get = 0;
1476         bi->bi_tool_entry_modify = 0;
1477
1478         bi->bi_cf_ocs = ldifocs;
1479
1480         rc = config_register_schema( ldifcfg, ldifocs );
1481         if ( rc ) return rc;
1482         return 0;
1483 }