~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to servers/slapd/back-ldif/ldif.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

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