]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldif/ldif.c
More for loading config from LDIF
[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 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 struct ldif_info {
35         struct berval li_base_path;
36         ID tool_current;
37         Entry ** tool_entries;
38         int tool_put_entry_flag;
39         int tool_numentries;
40         ldap_pvt_thread_mutex_t  li_mutex;
41 };
42
43 #define LDIF    ".ldif"
44
45 #define ENTRY_BUFF_INCREMENT 500
46
47 static ObjectClass *ldif_oc;
48
49 static ConfigDriver ldif_cf;
50
51 static ConfigTable ldifcfg[] = {
52         { "", "", 0, 0, 0, ARG_MAGIC,
53                 ldif_cf, NULL, NULL, NULL },
54         { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
55                 (void *)offsetof(struct ldif_info, li_base_path),
56                 "( OLcfgAt:1.1 NAME 'dbDirectory' "
57                         "DESC 'Directory for database content' "
58                         "EQUALITY caseIgnoreMatch "
59                         "SYNTAX OMsDirectoryString )", NULL, NULL },
60         { NULL, NULL, 0, 0, 0, ARG_IGNORED,
61                 NULL, NULL, NULL, NULL }
62 };
63
64 static ConfigOCs ldifocs[] = {
65         { "( OLcfgOc:2.1 "
66                 "NAME 'ldifConfig' "
67                 "DESC 'LDIF backend configuration' "
68                 "SUP olcDatabaseConfig "
69                 "MUST ( dbDirectory ) )", Cft_Database,
70                 &ldif_oc },
71         { NULL, 0, NULL }
72 };
73
74 static int
75 ldif_cf( ConfigArgs *c )
76 {
77         if ( c->op == SLAP_CONFIG_EMIT ) {
78                 value_add_one( &c->rvalue_vals, &ldif_oc->soc_cname );
79                 return 0;
80         }
81         return 1;
82 }
83
84 static void
85 dn2path(struct berval * dn, struct berval * rootdn, struct berval * base_path,
86         struct berval *res)
87 {
88         char *ptr, *sep, *end;
89
90         res->bv_len = dn->bv_len + base_path->bv_len + 1 + STRLENOF( LDIF );
91         res->bv_val = ch_malloc( res->bv_len + 1 );
92         ptr = lutil_strcopy( res->bv_val, base_path->bv_val );
93         *ptr++ = LDAP_DIRSEP[0];
94         ptr = lutil_strcopy( ptr, rootdn->bv_val );
95         end = dn->bv_val + dn->bv_len - rootdn->bv_len - 1;
96         while ( end > dn->bv_val ) {
97                 for (sep = end-1; sep >=dn->bv_val && !DN_SEPARATOR( *sep ); sep--);
98                 *ptr++ = LDAP_DIRSEP[0];
99                 ptr = lutil_strncopy( ptr, sep+1, end-sep-1 );
100                 end = sep;
101         }
102         strcpy(ptr, LDIF);
103 }
104
105 static char * slurp_file(int fd) {
106         int entry_buf_size = 40 * ENTRY_BUFF_INCREMENT;
107         int read_chars_total = 0;
108         int read_chars = 0;
109         int entry_size = 40 * ENTRY_BUFF_INCREMENT;
110         char * entry = (char *) malloc(sizeof(char) * 40 * ENTRY_BUFF_INCREMENT);
111         char * entry_pos = entry;
112         
113         while(1) {
114                 if(entry_size - read_chars_total == 0) {
115                         entry = (char *) realloc(entry, sizeof(char) * 2 * entry_size);
116                         entry_size = 2 * entry_size;
117                 }
118                 read_chars = read(fd, (void *) entry_pos, entry_size - read_chars_total);
119                 if(read_chars == -1) {
120                         SLAP_FREE(entry);
121                         return NULL;
122                 }
123                 entry_pos += read_chars;
124                 if(read_chars == 0) {
125                         if(entry_size - read_chars_total > 0)
126                                 entry[read_chars_total] = '\0';
127                         else {
128                                 entry = (char *) realloc(entry, sizeof(char) * entry_size + 1);
129                                 entry_size = entry_size + 1;
130                                 entry[read_chars_total] = '\0';
131                         }       
132                         break;
133                 }
134                 else {
135                         read_chars_total += read_chars;
136                 }
137         }
138         return entry;
139 }
140
141 static int spew_file(int fd, char * spew) {
142         int written = 0;
143         int writeres;
144         int len = strlen(spew);
145         char * spewptr = spew;
146         
147         while(written < len) {
148                 writeres = write(fd, spewptr, len - written);
149                 if(writeres == -1) {
150                         perror("could not spew write");
151                         return -1;
152                 }
153                 else {
154                         spewptr += writeres;
155                         written += writeres;
156                 }
157         }
158         return writeres;
159 }
160
161 static int spew_entry(Entry * e, struct berval * path) {
162         int rs;
163         int openres;
164         int spew_res;
165         int entry_length;
166         char * entry_as_string;
167
168         openres = open(path->bv_val, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
169         if(openres == -1) {
170                 if(errno == ENOENT)
171                         rs = LDAP_NO_SUCH_OBJECT;
172                 else
173                         rs = LDAP_UNWILLING_TO_PERFORM;
174         }
175         else {
176                 struct berval rdn;
177                 int tmp;
178
179                 /* Only save the RDN onto disk */
180                 dnRdn( &e->e_name, &rdn );
181                 if ( rdn.bv_len != e->e_name.bv_len ) {
182                         e->e_name.bv_val[rdn.bv_len] = '\0';
183                         tmp = e->e_name.bv_len;
184                         e->e_name.bv_len = rdn.bv_len;
185                         rdn.bv_len = tmp;
186                 }
187
188                 entry_as_string = entry2str(e, &entry_length);
189
190                 /* Restore full DN */
191                 if ( rdn.bv_len != e->e_name.bv_len ) {
192                         e->e_name.bv_val[e->e_name.bv_len] = ',';
193                         e->e_name.bv_len = rdn.bv_len;
194                 }
195
196                 if(entry_as_string == NULL) {
197                         rs = LDAP_UNWILLING_TO_PERFORM;
198                         close(openres);
199                 }
200                 else {
201                         spew_res = spew_file(openres, entry_as_string);
202                         close(openres);
203                         if(spew_res == -1)
204                                 rs = LDAP_UNWILLING_TO_PERFORM;
205                         else
206                                 rs = LDAP_SUCCESS;
207                 }
208         }
209         return rs;
210 }
211
212 static Entry * get_entry_for_fd(int fd,
213         struct berval *pdn,
214         struct berval *pndn) {
215         char * entry = (char *) slurp_file(fd);
216         Entry * ldentry = NULL;
217         
218         /* error reading file */
219         if(entry == NULL) {
220                 goto return_value;
221         }
222
223         ldentry = str2entry(entry);
224         if ( ldentry ) {
225                 struct berval rdn;
226                 rdn = ldentry->e_name;
227                 build_new_dn( &ldentry->e_name, pdn, &rdn, NULL );
228                 ch_free( rdn.bv_val );
229                 rdn = ldentry->e_nname;
230                 build_new_dn( &ldentry->e_nname, pndn, &rdn, NULL );
231                 ch_free( rdn.bv_val );
232         }
233
234  return_value:
235         if(fd != -1) {
236                 if(close(fd) != 0) {
237                         /* log error */
238                 }
239         }
240         if(entry != NULL)
241                 SLAP_FREE(entry);
242         return ldentry;
243 }
244
245 static Entry * get_entry(Operation *op, struct berval *base_path) {
246         struct berval path, pdn, pndn;
247         int fd;
248
249         dnParent(&op->o_req_dn, &pdn);
250         dnParent(&op->o_req_ndn, &pndn);
251         dn2path(&op->o_req_ndn, op->o_bd->be_nsuffix, base_path, &path);
252         fd = open(path.bv_val, O_RDONLY);
253         /* error opening file (mebbe should log error) */
254         if(fd == -1) {
255                 perror("failed to open file");
256         }
257
258         if(path.bv_val != NULL)
259                 SLAP_FREE(path.bv_val);
260         return get_entry_for_fd(fd, &pdn, &pndn);
261 }
262
263 static void fullpath(struct berval *base, struct berval *name, struct berval *res) {
264         char *ptr;
265         res->bv_len = name->bv_len + base->bv_len + 1;
266         res->bv_val = ch_malloc( res->bv_len + 1 );
267         strcpy(res->bv_val, base->bv_val);
268         ptr = res->bv_val + base->bv_len;
269         *ptr++ = LDAP_DIRSEP[0];
270         strcpy(ptr, name->bv_val);
271 }
272
273 typedef struct bvlist {
274         struct bvlist *next;
275         struct berval bv;
276 } bvlist;
277
278 typedef struct enumCookie {
279         Entry **entries;
280         int elen;
281         int eind;
282         int scope;
283 } enumCookie;
284
285 static void r_enum_tree(enumCookie *ck, struct berval *path,
286         struct berval *pdn, struct berval *pndn) {
287         Entry *e;
288         int fd;
289
290         if(ck->entries == NULL) {
291                 ck->entries = (Entry **) SLAP_MALLOC(sizeof(Entry *) * ENTRY_BUFF_INCREMENT);
292                 ck->elen = ENTRY_BUFF_INCREMENT;
293         }
294
295         fd = open( path->bv_val, O_RDONLY );
296         if ( fd < 0 ) {
297                 Debug( LDAP_DEBUG_TRACE,
298                         "=> ldif_enum_tree: failed to open %s\n",
299                         path->bv_val, 0, 0 );
300                 return;
301         }
302         e = get_entry_for_fd(fd, pdn, pndn);
303         if ( !e ) {
304                 Debug( LDAP_DEBUG_ANY,
305                         "=> ldif_enum_tree: failed to read entry for %s\n",
306                         path->bv_val, 0, 0 );
307                 return;
308         }
309
310         if ( ck->scope == LDAP_SCOPE_BASE || ck->scope == LDAP_SCOPE_SUBTREE ) {
311                 if(! (ck->eind < ck->elen)) { /* grow entries if necessary */   
312                         ck->entries = (Entry **) SLAP_REALLOC(ck->entries, sizeof(Entry *) * (ck->elen) * 2);
313                         ck->elen *= 2;
314                 }
315
316                 ck->entries[ck->eind] = e;
317                 ck->eind++;
318                 fd = 0;
319         } else {
320                 fd = 1;
321         }
322
323         if ( ck->scope != LDAP_SCOPE_BASE ) {
324                 DIR * dir_of_path;
325                 bvlist *list = NULL, *ptr;
326
327                 path->bv_len -= STRLENOF( LDIF );
328                 path->bv_val[path->bv_len] = '\0';
329
330                 dir_of_path = opendir(path->bv_val);
331                 if(dir_of_path == NULL) {/* can't open directory */
332                         Debug( LDAP_DEBUG_TRACE,
333                                 "=> ldif_enum_tree: failed to opendir %s\n",
334                                 path->bv_val, 0, 0 );
335                         goto leave;
336                 }
337         
338                 while(1) {
339                         struct berval fname;
340                         struct dirent * dir;
341                         bvlist *bvl, *prev;
342
343                         dir = readdir(dir_of_path);
344                         if(dir == NULL) break; /* end of the directory */
345                         fname.bv_len = strlen( dir->d_name );
346                         if ( fname.bv_len <= STRLENOF( LDIF ))
347                                 continue;
348                         if ( strcmp( dir->d_name + (fname.bv_len - STRLENOF(LDIF)), LDIF))
349                                 continue;
350                         fname.bv_val = dir->d_name;
351
352                         bvl = ch_malloc( sizeof(bvlist) );
353                         ber_dupbv( &bvl->bv, &fname );
354
355                         for (ptr = list, prev = (bvlist *)&list; ptr;
356                                 prev = ptr, ptr = ptr->next) {
357                                 if ( strcmp( bvl->bv.bv_val, ptr->bv.bv_val ) < 0 )
358                                         break;
359                         }
360                         prev->next = bvl;
361                         bvl->next = ptr;
362                                 
363                 }
364                 closedir(dir_of_path);
365
366                 if (ck->scope == LDAP_SCOPE_ONELEVEL)
367                         ck->scope = LDAP_SCOPE_BASE;
368                 else if ( ck->scope == LDAP_SCOPE_SUBORDINATE)
369                         ck->scope = LDAP_SCOPE_SUBTREE;
370
371                 for ( ptr = list; ptr; ptr=ptr->next ) {
372                         struct berval fpath;
373                         fullpath( path, &ptr->bv, &fpath );
374                         r_enum_tree(ck, &fpath, &e->e_name, &e->e_nname );
375                         free(fpath.bv_val);
376                 }
377         }
378 leave:
379         if ( fd ) entry_free( e );
380         return;
381 }
382
383 static Entry ** enum_tree(
384         BackendDB *be,
385         struct berval *dn,
386         struct berval *ndn,
387         int * length,
388         int scope )
389 {
390         struct ldif_info *ni = (struct ldif_info *) be->be_private;
391         struct berval path;
392         int index = 0;
393         enumCookie ck = {0};
394         struct berval pdn, pndn;
395
396         ck.scope = scope;
397         dnParent( dn, &pdn );
398         dnParent( ndn, &pndn );
399         dn2path(ndn, &be->be_nsuffix[0], &ni->li_base_path, &path);
400         r_enum_tree(&ck, &path, &pdn, &pndn);
401         *length = ck.eind;
402         return ck.entries;
403 }
404
405 /* Get the parent path plus the LDIF suffix */
406 static void get_parent_path(struct berval * dnpath, struct berval *res) {
407         int dnpathlen = dnpath->bv_len;
408         int i;
409         
410         for(i = dnpathlen;i>0;i--) /* find the first path seperator */
411                 if(dnpath->bv_val[i] == LDAP_DIRSEP[0])
412                         break;
413         res->bv_len = i;
414         res->bv_val = ch_malloc( res->bv_len + 1 + STRLENOF(LDIF) );
415         strncpy(res->bv_val, dnpath->bv_val, i);
416         strcpy(res->bv_val+i, LDIF);
417         res->bv_val[i] = '\0';
418 }
419
420 static int apply_modify_to_entry(Entry * entry,
421                                 Modifications * modlist,
422                                 Operation * op,
423                                 SlapReply * rs)
424 {
425         char textbuf[SLAP_TEXT_BUFLEN];
426         size_t textlen = sizeof textbuf;
427         int rc;
428         int tempdebug;
429         Modification *mods = NULL;
430         Attribute *save_attrs;
431
432         if (!acl_check_modlist(op, entry, modlist)) {
433                 return LDAP_INSUFFICIENT_ACCESS;
434         }
435
436         /*  save_attrs = entry->e_attrs; Why?
437                         entry->e_attrs = attrs_dup(entry->e_attrs); */
438
439         for (; modlist != NULL; modlist = modlist->sml_next) {
440                 mods = &modlist->sml_mod;
441
442                 switch (mods->sm_op) {
443                 case LDAP_MOD_ADD:
444                         rc = modify_add_values(entry, mods,
445                                    get_permissiveModify(op),
446                                    &rs->sr_text, textbuf,
447                                    textlen);
448                         break;
449                                 
450                 case LDAP_MOD_DELETE:
451                         rc = modify_delete_values(entry, mods,
452                                 get_permissiveModify(op),
453                                 &rs->sr_text, textbuf,
454                                 textlen);
455
456                         break;
457                                 
458                 case LDAP_MOD_REPLACE:
459                         rc = modify_replace_values(entry, mods,
460                                  get_permissiveModify(op),
461                                  &rs->sr_text, textbuf,
462                                  textlen);
463
464                         break;
465                 case LDAP_MOD_INCREMENT:
466                         break;
467                 case SLAP_MOD_SOFTADD:
468                         mods->sm_op = LDAP_MOD_ADD;
469                         rc = modify_add_values(entry, mods,
470                                    get_permissiveModify(op),
471                                    &rs->sr_text, textbuf,
472                                    textlen);
473                         mods->sm_op = SLAP_MOD_SOFTADD;
474                         if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
475                                 rc = LDAP_SUCCESS;
476                         }
477                         break;
478                 default:
479                         break;
480                 }
481                 if(rc != LDAP_SUCCESS) break;
482         }
483         
484         if(rc == LDAP_SUCCESS) {
485                 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
486                         entry->e_ocflags = 0;
487                 }
488                 /* check that the entry still obeys the schema */
489                 rc = entry_schema_check(op->o_bd, entry,
490                                   save_attrs, &rs->sr_text,
491                                   textbuf, textlen);
492         }
493         return rc;
494 }
495
496 static int
497 ldif_back_bind( Operation *op, SlapReply *rs )
498 {
499         struct ldif_info *ni = NULL;
500         Attribute * a = NULL;
501         AttributeDescription *password = slap_schema.si_ad_userPassword;
502         int return_val = 0;
503         Entry * entry = NULL;
504
505         ni = (struct ldif_info *) op->o_bd->be_private;
506         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
507         entry = (Entry *) get_entry(op, &ni->li_base_path);
508
509         /* no object is found for them */
510         if(entry == NULL) {
511                 if(be_isroot_pw(op)) {
512                         return_val = LDAP_SUCCESS;
513                         goto return_result;
514                 }
515                 else if(be_root_dn(op->o_bd)) {
516                         return_val = LDAP_INVALID_CREDENTIALS;
517                         rs->sr_err = LDAP_INVALID_CREDENTIALS;
518                         goto return_result;
519                 }
520                 else {
521                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
522                         return_val = 1;
523                         goto return_result;
524                 }
525         }
526
527         /* they don't have userpassword */
528         if((a = attr_find(entry->e_attrs, password)) == NULL) {
529                 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
530                 return_val = 1;
531                 goto return_result;
532         }
533
534         /* authentication actually failed */
535         if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
536                              &rs->sr_text) != 0) {
537                 rs->sr_err = LDAP_INVALID_CREDENTIALS;
538                 return_val = 1;
539                 goto return_result;
540         }
541
542         /* let the front-end send success */
543         return_val = 0;
544         goto return_result;
545
546  return_result:
547         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
548         if(return_val != 0)
549                 send_ldap_result( op, rs );
550         if(entry != NULL)
551                 entry_free(entry);
552         return return_val;
553 }
554
555 static int ldif_back_search(Operation *op, SlapReply *rs)
556 {
557         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
558         int numentries = 0;
559         int i = 0;
560         Entry ** entries = NULL;
561
562         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
563         entries = (Entry **) enum_tree(op->o_bd, &op->o_req_dn, &op->o_req_ndn, &numentries, op->ors_scope);
564
565         if(entries != NULL) {
566                 for(i=0;i<numentries;i++) {
567                         if(test_filter(op, entries[i], op->ors_filter) == LDAP_COMPARE_TRUE) {
568                                 rs->sr_entry = entries[i];
569                                 rs->sr_attrs = op->ors_attrs;
570                                 rs->sr_flags = REP_ENTRY_MODIFIABLE;
571                                 send_search_entry(op, rs);
572                         }
573                         entry_free(entries[i]);
574                 }
575                 SLAP_FREE(entries);
576                 rs->sr_err = LDAP_SUCCESS;
577                 ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
578                 send_ldap_result(op, rs);
579         }
580         else {
581                 rs->sr_err = LDAP_BUSY;
582                 ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
583                 send_ldap_result(op, rs);
584         }
585
586         return 0;
587 }
588
589 static int ldif_back_add(Operation *op, SlapReply *rs) {
590         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
591         Entry * e = op->ora_e;
592         struct berval dn = e->e_nname;
593         struct berval leaf_path = BER_BVNULL;
594         struct stat stats;
595         int statres;
596         char textbuf[SLAP_TEXT_BUFLEN];
597         size_t textlen = sizeof textbuf;
598
599         rs->sr_err = entry_schema_check(op->o_bd, e,
600                                   NULL, &rs->sr_text, textbuf, textlen);
601         if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
602                                 
603         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
604
605         dn2path(&dn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &leaf_path);
606
607         if(leaf_path.bv_val != NULL) {
608                 struct berval base = BER_BVNULL;
609                 /* build path to container and ldif of container */
610                 get_parent_path(&leaf_path, &base);
611
612                 statres = stat(base.bv_val, &stats); /* check if container exists */
613                 if(statres == -1 && errno == ENOENT) { /* container missing */
614                         base.bv_val[base.bv_len] = '.';
615                         statres = stat(base.bv_val, &stats); /* check for leaf node */
616                         base.bv_val[base.bv_len] = '\0';
617                         if(statres == -1 && errno == ENOENT) {
618                                 rs->sr_err = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
619                         }
620                         else if(statres != -1) { /* create parent */
621                                 int mkdirres = mkdir(base.bv_val, 0750);
622                                 if(mkdirres == -1) {
623                                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
624                                 }
625                         }
626                         else
627                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
628                 }/* container was possibly created, move on to add the entry */
629                 if(rs->sr_err == LDAP_SUCCESS) {
630                         statres = stat(leaf_path.bv_val, &stats);
631                         if(statres == -1 && errno == ENOENT) {
632                                 ldap_pvt_thread_mutex_lock(&entry2str_mutex);
633                                 rs->sr_err = (int) spew_entry(e, &leaf_path);
634                                 ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
635                         }
636                         else /* it already exists */
637                                 rs->sr_err = LDAP_ALREADY_EXISTS;
638                 }
639                 SLAP_FREE(base.bv_val);
640                 SLAP_FREE(leaf_path.bv_val);
641         }
642
643         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
644
645 send_res:
646         send_ldap_result(op, rs);
647         return 0;
648 }
649
650 static int ldif_back_modify(Operation *op, SlapReply *rs) {
651         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
652         Modifications * modlst = op->orm_modlist;
653         struct berval path = BER_BVNULL;
654         Entry * entry = NULL;
655         int spew_res;
656
657         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
658         dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path,
659                 &path);
660         entry = (Entry *) get_entry(op, &ni->li_base_path);
661
662         if(entry != NULL) {
663                 rs->sr_err = apply_modify_to_entry(entry, modlst, op, rs);
664                 if(rs->sr_err == LDAP_SUCCESS) {
665                         ldap_pvt_thread_mutex_lock(&entry2str_mutex);
666                         spew_res = spew_entry(entry, &path);
667                         ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
668                         if(spew_res == -1) {
669                                 perror("could not output entry");
670                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
671                         }
672                 }
673         }
674         else {
675                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
676         }
677         
678         if(entry != NULL)
679                 entry_free(entry);
680         if(path.bv_val != NULL)
681                 SLAP_FREE(path.bv_val);
682         rs->sr_text = NULL;
683         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
684         send_ldap_result(op, rs);
685         return 0;
686 }
687
688 static int ldif_back_delete(Operation *op, SlapReply *rs) {
689         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
690         struct berval path = BER_BVNULL;
691         int res = 0;
692
693         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
694         dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &path);
695
696         path.bv_val[path.bv_len - STRLENOF(LDIF)] = '\0';
697         res = rmdir(path.bv_val);
698         path.bv_val[path.bv_len - STRLENOF(LDIF)] = '.';
699         if ( res && errno != ENOENT ) {
700                 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
701         } else {
702                 res = unlink(path.bv_val);
703         }
704
705         if(res == -1) {
706                 if(errno == ENOENT)
707                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
708                 else
709                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
710         }
711         else
712                 rs->sr_err = LDAP_SUCCESS;
713
714         SLAP_FREE(path.bv_val);
715         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
716         send_ldap_result(op, rs);
717         return 0;
718 }
719
720
721 static int move_entry(Entry * entry, struct berval * ndn,
722                            struct berval * newndn, struct berval * rootdn,
723                            struct berval * base_path) {
724         int res;
725         int exists_res;
726         struct berval path;
727         struct berval newpath;
728
729         dn2path(ndn, rootdn, base_path, &path);
730         dn2path(newndn, rootdn, base_path, &newpath);
731
732         if((entry == NULL || path.bv_val == NULL) || newpath.bv_val == NULL) {
733                 /* some object doesn't exist */
734                 res = LDAP_NO_SUCH_OBJECT;
735         }
736         else { /* do the modrdn */
737                 exists_res = open(newpath.bv_val, O_RDONLY);
738                 if(exists_res == -1 && errno == ENOENT) {
739                         res = spew_entry(entry, &newpath);
740                         if(res != -1) {
741                                 /* if this fails we should log something bad */
742                                 res = unlink(path.bv_val);
743                                 res = LDAP_SUCCESS;
744                         }
745                         else {
746                                 if(errno == ENOENT)
747                                         res = LDAP_NO_SUCH_OBJECT;
748                                 else
749                                         res = LDAP_UNWILLING_TO_PERFORM;
750                                 unlink(newpath.bv_val); /* in case file was created */
751                         }
752                 }
753                 else if(exists_res) {
754                         int close_res = close(exists_res);
755                         res = LDAP_ALREADY_EXISTS;
756                         if(close_res == -1) {
757                         /* log heinous error */
758                         }
759                 }
760                 else {
761                         res = LDAP_UNWILLING_TO_PERFORM;
762                 }
763         }
764
765         if(newpath.bv_val != NULL)
766                 SLAP_FREE(newpath.bv_val);
767         if(path.bv_val != NULL)
768                 SLAP_FREE(path.bv_val);
769         return res;
770 }
771
772 static int ldif_back_modrdn(Operation *op, SlapReply *rs) {
773         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
774         struct berval new_dn = {0, NULL}, new_ndn = {0, NULL};
775         struct berval * new_parent_dn = NULL;
776         struct berval p_dn, bv = {0, NULL};
777         Entry * entry = NULL;
778         LDAPRDN new_rdn = NULL;
779         LDAPRDN old_rdn = NULL;
780         Modifications * mods = NULL;
781         int res;
782
783         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
784         ldap_pvt_thread_mutex_lock(&entry2str_mutex);
785         entry = (Entry *) get_entry(op, &ni->li_base_path);
786
787         /* build the mods to the entry */
788         if(entry != NULL) {
789                 if(ldap_bv2rdn(&op->oq_modrdn.rs_newrdn, &new_rdn,
790                         (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP)) {
791                         rs->sr_err = LDAP_INVALID_DN_SYNTAX;
792                 }
793                 else if(op->oq_modrdn.rs_deleteoldrdn &&
794                         ldap_bv2rdn(&op->o_req_dn, &old_rdn, (char **)&rs->sr_text,
795                         LDAP_DN_FORMAT_LDAP)) {
796                         rs->sr_err = LDAP_OTHER;
797                 }
798                 else { /* got both rdns successfully, ready to build mods */
799                         if(slap_modrdn2mods(op, rs, entry, old_rdn, new_rdn, &mods)
800                                 != LDAP_SUCCESS) {
801                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
802                         }
803                         else { /* built mods successfully */
804
805                                 /* build new dn, and new ndn for the entry */
806                                 if(op->oq_modrdn.rs_newSup != NULL) /* new superior */
807                                         p_dn = *op->oq_modrdn.rs_newSup;
808                                 else
809                                         p_dn = slap_empty_bv;
810                                 dnParent(&entry->e_name, &p_dn);
811                                 build_new_dn(&new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL); 
812                                 dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx );
813                                 ber_dupbv( &new_ndn, &bv );
814                                 entry->e_name = new_dn;
815                                 entry->e_nname = new_ndn;
816
817                                 /* perform the modifications */
818                                 res = apply_modify_to_entry(entry, mods, op, rs);
819                                 if(res == LDAP_SUCCESS) {
820                                         rs->sr_err = move_entry(entry, &op->o_req_ndn,
821                                                                 &new_ndn,
822                                                                 &op->o_bd->be_nsuffix[0],
823                                                                 &ni->li_base_path);
824                                 }
825                                 else
826                                         rs->sr_err = res;
827                         }
828                 }
829         }
830         else /* entry was null */
831                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
832
833         if(entry != NULL)
834                 entry_free(entry);
835         rs->sr_text = "";
836         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
837         ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
838         send_ldap_result(op, rs);
839         return 0;
840 }
841
842 static int ldif_back_compare(Operation *op, SlapReply *rs) {
843         struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
844         Entry * e = NULL;
845         Attribute       *a;
846
847         ldap_pvt_thread_mutex_lock(&ni->li_mutex);
848
849         e = (Entry *) get_entry(op, &ni->li_base_path);
850         if(e != NULL) {
851                 for(a = attrs_find( e->e_attrs, op->oq_compare.rs_ava->aa_desc );
852                         a != NULL;
853                         a = attrs_find( a->a_next, op->oq_compare.rs_ava->aa_desc )) {
854                         rs->sr_err = LDAP_COMPARE_FALSE;
855                 
856                         if (value_find_ex(op->oq_compare.rs_ava->aa_desc,
857                                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
858                                                 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
859                                                 a->a_nvals, &op->oq_compare.rs_ava->aa_value,
860                                                 op->o_tmpmemctx ) == 0) {
861                                 rs->sr_err = LDAP_COMPARE_TRUE;
862                                 break;
863                         }
864                 }
865         }
866         else {
867                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
868         }
869
870         if(e != NULL)
871                 entry_free(e);
872         ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
873         send_ldap_result(op, rs);
874         return 0;
875 }
876
877 static int ldif_tool_entry_open(BackendDB * be, int mode) {
878         struct ldif_info *ni = (struct ldif_info *) be->be_private;
879         ni->tool_entries = NULL;
880         ni->tool_numentries = 0;
881         ni->tool_current = 0;
882         ni->tool_put_entry_flag = 0;
883         return 0;
884 }                                       
885
886 static int ldif_tool_entry_close(BackendDB * be) {
887         struct ldif_info *ni = (struct ldif_info *) be->be_private;
888
889         SLAP_FREE(ni->tool_entries);
890         return 0;
891 }
892
893 static ID ldif_tool_entry_first(BackendDB *be) {
894         struct ldif_info *ni = (struct ldif_info *) be->be_private;
895         ID id = 1; /* first entry in the array of entries shifted by one */
896
897         ni->tool_current = 1;
898         if(ni->tool_entries == NULL || ni->tool_put_entry_flag) {
899                 ni->tool_entries = (Entry **) enum_tree(be, be->be_suffix,
900                         be->be_nsuffix, &ni->tool_numentries, LDAP_SCOPE_SUBTREE);
901                 ni->tool_put_entry_flag = 0;
902         }
903         return id;
904 }
905
906 static ID ldif_tool_entry_next(BackendDB *be) {
907         struct ldif_info *ni = (struct ldif_info *) be->be_private;
908         ni->tool_current += 1;
909         if(ni->tool_put_entry_flag) {
910                 ni->tool_entries = (Entry **) enum_tree(be, be->be_suffix,
911                         be->be_nsuffix, &ni->tool_numentries, LDAP_SCOPE_SUBTREE);
912                 ni->tool_put_entry_flag = 0;
913         }
914         if(ni->tool_current > ni->tool_numentries)
915                 return NOID;
916         else
917                 return ni->tool_current;
918 }
919
920 static Entry * ldif_tool_entry_get(BackendDB * be, ID id) {
921         struct ldif_info *ni = (struct ldif_info *) be->be_private;
922         Entry * e;
923
924         if(id > ni->tool_numentries || id < 1)
925                 return NULL;
926         else {
927                 e = ni->tool_entries[id - 1];
928                 ni->tool_entries[id - 1] = NULL;
929                 return e;
930         }
931 }
932
933 static ID ldif_tool_entry_put(BackendDB * be, Entry * e, struct berval *text) {
934         struct ldif_info *ni = (struct ldif_info *) be->be_private;
935         Attribute *save_attrs;
936         struct berval dn = e->e_nname;
937         struct berval leaf_path = BER_BVNULL;
938         struct stat stats;
939         int statres;
940         char textbuf[SLAP_TEXT_BUFLEN];
941         size_t textlen = sizeof textbuf;
942         int res = LDAP_SUCCESS;
943
944         dn2path(&dn, &be->be_nsuffix[0], &ni->li_base_path, &leaf_path);
945
946         if(leaf_path.bv_val != NULL) {
947                 struct berval base = BER_BVNULL;
948                 /* build path to container, and path to ldif of container */
949                 get_parent_path(&leaf_path, &base);
950
951                 statres = stat(base.bv_val, &stats); /* check if container exists */
952                 if(statres == -1 && errno == ENOENT) { /* container missing */
953                         base.bv_val[base.bv_len] = '.';
954                         statres = stat(base.bv_val, &stats); /* check for leaf node */
955                         base.bv_val[base.bv_len] = '\0';
956                         if(statres == -1 && errno == ENOENT) {
957                                 res = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
958                         }
959                         else if(statres != -1) { /* create parent */
960                                 int mkdirres = mkdir(base.bv_val, 0750);
961                                 if(mkdirres == -1) {
962                                         res = LDAP_UNWILLING_TO_PERFORM;
963                                 }
964                         }
965                         else
966                                 res = LDAP_UNWILLING_TO_PERFORM;
967                 }/* container was possibly created, move on to add the entry */
968                 if(res == LDAP_SUCCESS) {
969                         statres = stat(leaf_path.bv_val, &stats);
970                         if(statres == -1 && errno == ENOENT) {
971                                 res = (int) spew_entry(e, &leaf_path);
972                         }
973                         else /* it already exists */
974                                 res = LDAP_ALREADY_EXISTS;
975                 }
976                 SLAP_FREE(base.bv_val);
977                 SLAP_FREE(leaf_path.bv_val);
978         }
979
980         if(res == LDAP_SUCCESS) {
981                 ni->tool_put_entry_flag = 1;
982                 return 1;
983         }
984         else
985                 return NOID;
986 }
987
988 static int
989 ldif_back_db_init( BackendDB *be )
990 {
991         struct ldif_info *ni;
992
993         ni = ch_calloc( 1, sizeof(struct ldif_info) );
994         be->be_private = ni;
995         be->be_cf_table = be->bd_info->bi_cf_table;
996         ldap_pvt_thread_mutex_init(&ni->li_mutex);
997         return 0;
998 }
999
1000 static int
1001 ldif_back_db_destroy(
1002                            Backend      *be
1003                            )
1004 {
1005         struct ldif_info *ni = be->be_private;
1006         ldap_pvt_thread_mutex_destroy(&ni->li_mutex);
1007         free( be->be_private );
1008         return 0;
1009 }
1010
1011 static int
1012 ldif_back_db_open(
1013                         Backend *be
1014                         )
1015 {
1016         struct ldif_info *ni = (struct ldif_info *) be->be_private;
1017         if( BER_BVISEMPTY(&ni->li_base_path)) {/* missing base path */
1018                 fprintf(stderr, "missing base path for back-ldif\n");
1019                 return 1;
1020         }
1021         return 0;
1022 }
1023
1024 int
1025 ldif_back_initialize(
1026                            BackendInfo  *bi
1027                            )
1028 {
1029         int rc;
1030
1031         bi->bi_cf_table = ldifcfg;
1032
1033         bi->bi_open = 0;
1034         bi->bi_close = 0;
1035         bi->bi_config = 0;
1036         bi->bi_destroy = 0;
1037
1038         bi->bi_db_init = ldif_back_db_init;
1039         bi->bi_db_config = config_generic_wrapper;
1040         bi->bi_db_open = ldif_back_db_open;
1041         bi->bi_db_close = 0;
1042         bi->bi_db_destroy = ldif_back_db_destroy;
1043
1044         bi->bi_op_bind = ldif_back_bind;
1045         bi->bi_op_unbind = 0;
1046         bi->bi_op_search = ldif_back_search;
1047         bi->bi_op_compare = ldif_back_compare;
1048         bi->bi_op_modify = ldif_back_modify;
1049         bi->bi_op_modrdn = ldif_back_modrdn;
1050         bi->bi_op_add = ldif_back_add;
1051         bi->bi_op_delete = ldif_back_delete;
1052         bi->bi_op_abandon = 0;
1053
1054         bi->bi_extended = 0;
1055
1056         bi->bi_chk_referrals = 0;
1057
1058         bi->bi_connection_init = 0;
1059         bi->bi_connection_destroy = 0;
1060
1061         bi->bi_tool_entry_open = ldif_tool_entry_open;
1062         bi->bi_tool_entry_close = ldif_tool_entry_close;
1063         bi->bi_tool_entry_first = ldif_tool_entry_first;
1064         bi->bi_tool_entry_next = ldif_tool_entry_next;
1065         bi->bi_tool_entry_get = ldif_tool_entry_get;
1066         bi->bi_tool_entry_put = ldif_tool_entry_put;
1067         bi->bi_tool_entry_reindex = 0;
1068         bi->bi_tool_sync = 0;
1069         
1070         bi->bi_tool_dn2id_get = 0;
1071         bi->bi_tool_id2entry_get = 0;
1072         bi->bi_tool_entry_modify = 0;
1073
1074         rc = config_register_schema( ldifcfg, ldifocs );
1075         if ( rc ) return rc;
1076         ldifcfg[0].ad = slap_schema.si_ad_objectClass;
1077         return 0;
1078 }