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