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