ldif.c 30.8 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* ldif.c - the ldif backend */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
 * Copyright 2005 The OpenLDAP Foundation.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* ACKNOWLEDGEMENTS:
 * This work was originally developed by Eric Stokes for inclusion
 * in OpenLDAP Software.
 */

#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ac/dirent.h>
#include <fcntl.h>
#include <ac/errno.h>
#include <ac/unistd.h>
#include "slap.h"
#include "lutil.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
32
#include "config.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
33

Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
35
36
37
38
39
40
41
typedef struct enumCookie {
	Operation *op;
	SlapReply *rs;
	Entry **entries;
	int elen;
	int eind;
} enumCookie;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
42
43
struct ldif_info {
	struct berval li_base_path;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
44
45
	enumCookie li_tool_cookie;
	ID li_tool_current;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
46
47
48
	ldap_pvt_thread_mutex_t  li_mutex;
};

Kurt Zeilenga's avatar
Kurt Zeilenga committed
49
50
51
52
#ifdef _WIN32
#define mkdir(a,b)	mkdir(a)
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
53
54
#define LDIF	".ldif"

55
56
57
58
59
60
61
#define IX_DNL	'{'
#define	IX_DNR	'}'
#ifndef IX_FSL
#define	IX_FSL	IX_DNL
#define IX_FSR	IX_DNR
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
62
63
#define ENTRY_BUFF_INCREMENT 500

Kurt Zeilenga's avatar
Kurt Zeilenga committed
64
65
66
static ConfigTable ldifcfg[] = {
	{ "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET,
		(void *)offsetof(struct ldif_info, li_base_path),
67
		"( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
Kurt Zeilenga's avatar
Kurt Zeilenga committed
68
69
70
71
72
73
74
75
			"DESC 'Directory for database content' "
			"EQUALITY caseIgnoreMatch "
			"SYNTAX OMsDirectoryString )", NULL, NULL },
	{ NULL, NULL, 0, 0, 0, ARG_IGNORED,
		NULL, NULL, NULL, NULL }
};

static ConfigOCs ldifocs[] = {
76
77
	{ "( OLcfgDbOc:2.1 "
		"NAME 'olcLdifConfig' "
Kurt Zeilenga's avatar
Kurt Zeilenga committed
78
		"DESC 'LDIF backend configuration' "
79
		"SUP olcDatabaseConfig "
80
		"MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg },
81
	{ NULL, 0, NULL }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
82
83
84
85
86
};

static void
dn2path(struct berval * dn, struct berval * rootdn, struct berval * base_path,
	struct berval *res)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
87
88
89
{
	char *ptr, *sep, *end;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
90
91
92
	res->bv_len = dn->bv_len + base_path->bv_len + 1 + STRLENOF( LDIF );
	res->bv_val = ch_malloc( res->bv_len + 1 );
	ptr = lutil_strcopy( res->bv_val, base_path->bv_val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
93
94
95
96
97
98
99
100
101
102
	*ptr++ = LDAP_DIRSEP[0];
	ptr = lutil_strcopy( ptr, rootdn->bv_val );
	end = dn->bv_val + dn->bv_len - rootdn->bv_len - 1;
	while ( end > dn->bv_val ) {
		for (sep = end-1; sep >=dn->bv_val && !DN_SEPARATOR( *sep ); sep--);
		*ptr++ = LDAP_DIRSEP[0];
		ptr = lutil_strncopy( ptr, sep+1, end-sep-1 );
		end = sep;
	}
	strcpy(ptr, LDIF);
103
104
105
106
107
108
109
110
111
112
113
#if IX_FSL != IX_DNL
	ptr = res->bv_val;
	while( ptr=strchr(ptr, IX_DNL) ) {
		*ptr++ = IX_FSL;
		ptr = strchr(ptr, IX_DNR);
		if ( ptr )
			*ptr++ = IX_FSR;
		else
			break;
	}
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
114
115
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
116
static char * slurp_file(int fd) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
117
118
	int read_chars_total = 0;
	int read_chars = 0;
119
120
121
122
123
124
125
126
127
	int entry_size;
	char * entry;
	char * entry_pos;
	struct stat st;

	fstat(fd, &st);
	entry_size = st.st_size;
	entry = ch_malloc( entry_size+1 );
	entry_pos = entry;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
128
129
	
	while(1) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
130
131
132
133
134
135
		read_chars = read(fd, (void *) entry_pos, entry_size - read_chars_total);
		if(read_chars == -1) {
			SLAP_FREE(entry);
			return NULL;
		}
		if(read_chars == 0) {
136
			entry[read_chars_total] = '\0';
Kurt Zeilenga's avatar
Kurt Zeilenga committed
137
138
139
140
			break;
		}
		else {
			read_chars_total += read_chars;
141
			entry_pos += read_chars;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
142
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
143
144
145
146
	}
	return entry;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
147
static int spew_file(int fd, char * spew, int len) {
148
	int writeres = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
149
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
150
151
	while(len > 0) {
		writeres = write(fd, spew, len);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
152
153
154
155
156
		if(writeres == -1) {
			perror("could not spew write");
			return -1;
		}
		else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
157
158
			spew += writeres;
			len -= writeres;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
159
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
160
161
162
163
	}
	return writeres;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
164
static int spew_entry(Entry * e, struct berval * path) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
165
166
167
168
169
170
	int rs;
	int openres;
	int spew_res;
	int entry_length;
	char * entry_as_string;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
171
	openres = open(path->bv_val, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172
	if(openres == -1) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
173
174
175
176
		if(errno == ENOENT)
			rs = LDAP_NO_SUCH_OBJECT;
		else
			rs = LDAP_UNWILLING_TO_PERFORM;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
177
178
	}
	else {
179
180
181
182
183
184
185
186
187
188
189
190
		struct berval rdn;
		int tmp;

		/* Only save the RDN onto disk */
		dnRdn( &e->e_name, &rdn );
		if ( rdn.bv_len != e->e_name.bv_len ) {
			e->e_name.bv_val[rdn.bv_len] = '\0';
			tmp = e->e_name.bv_len;
			e->e_name.bv_len = rdn.bv_len;
			rdn.bv_len = tmp;
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
191
		entry_as_string = entry2str(e, &entry_length);
192
193
194
195
196
197
198

		/* Restore full DN */
		if ( rdn.bv_len != e->e_name.bv_len ) {
			e->e_name.bv_val[e->e_name.bv_len] = ',';
			e->e_name.bv_len = rdn.bv_len;
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
199
200
201
202
203
		if(entry_as_string == NULL) {
			rs = LDAP_UNWILLING_TO_PERFORM;
			close(openres);
		}
		else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
204
			spew_res = spew_file(openres, entry_as_string, entry_length);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
205
206
207
208
209
210
211
			close(openres);
			if(spew_res == -1)
				rs = LDAP_UNWILLING_TO_PERFORM;
			else
				rs = LDAP_SUCCESS;
		}
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
212
213
214
	return rs;
}

215
216
217
218
static Entry * get_entry_for_fd(int fd,
	struct berval *pdn,
	struct berval *pndn)
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
219
220
221
222
223
	char * entry = (char *) slurp_file(fd);
	Entry * ldentry = NULL;
	
	/* error reading file */
	if(entry == NULL) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
224
		goto return_value;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
225
226
227
	}

	ldentry = str2entry(entry);
228
229
230
231
232
233
234
235
236
	if ( ldentry ) {
		struct berval rdn;
		rdn = ldentry->e_name;
		build_new_dn( &ldentry->e_name, pdn, &rdn, NULL );
		ch_free( rdn.bv_val );
		rdn = ldentry->e_nname;
		build_new_dn( &ldentry->e_nname, pndn, &rdn, NULL );
		ch_free( rdn.bv_val );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
237
238
239

 return_value:
	if(fd != -1) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
240
241
242
		if(close(fd) != 0) {
			/* log error */
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
243
244
	}
	if(entry != NULL)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
245
		SLAP_FREE(entry);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
246
247
248
	return ldentry;
}

249
250
static Entry * get_entry(Operation *op, struct berval *base_path) {
	struct berval path, pdn, pndn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
251
	int fd;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
252

253
254
255
	dnParent(&op->o_req_dn, &pdn);
	dnParent(&op->o_req_ndn, &pndn);
	dn2path(&op->o_req_ndn, op->o_bd->be_nsuffix, base_path, &path);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
256
	fd = open(path.bv_val, O_RDONLY);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
258
	/* error opening file (mebbe should log error) */
	if(fd == -1) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
259
		perror("failed to open file");
Kurt Zeilenga's avatar
Kurt Zeilenga committed
260
261
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
262
263
	if(path.bv_val != NULL)
		SLAP_FREE(path.bv_val);
264
265
266
267
268
269

	if ( fd != -1 ) {
		return get_entry_for_fd(fd, &pdn, &pndn);
	}

	return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
270
271
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
272
273
274
275
276
277
278
279
static void fullpath(struct berval *base, struct berval *name, struct berval *res) {
	char *ptr;
	res->bv_len = name->bv_len + base->bv_len + 1;
	res->bv_val = ch_malloc( res->bv_len + 1 );
	strcpy(res->bv_val, base->bv_val);
	ptr = res->bv_val + base->bv_len;
	*ptr++ = LDAP_DIRSEP[0];
	strcpy(ptr, name->bv_val);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
280
281
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
282
283
284
typedef struct bvlist {
	struct bvlist *next;
	struct berval bv;
285
286
287
	struct berval num;
	unsigned int inum;
	int off;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
288
289
} bvlist;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
290

291
292
293
294
295
296
297
298
299
300
301
302
static int r_enum_tree(enumCookie *ck, struct berval *path,
	struct berval *pdn, struct berval *pndn)
{
	Entry *e;
	int fd, rc = LDAP_SUCCESS;

	fd = open( path->bv_val, O_RDONLY );
	if ( fd < 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			"=> ldif_enum_tree: failed to open %s\n",
			path->bv_val, 0, 0 );
		return LDAP_NO_SUCH_OBJECT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
303
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
304

305
306
307
308
309
310
311
312
	e = get_entry_for_fd(fd, pdn, pndn);
	if ( !e ) {
		Debug( LDAP_DEBUG_ANY,
			"=> ldif_enum_tree: failed to read entry for %s\n",
			path->bv_val, 0, 0 );
		return LDAP_BUSY;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
	if ( ck->op->ors_scope == LDAP_SCOPE_BASE ||
		ck->op->ors_scope == LDAP_SCOPE_SUBTREE ) {
		/* Send right away? */
		if ( ck->rs ) {
			/*
			 * if it's a referral, add it to the list of referrals. only do
			 * this for non-base searches, and don't check the filter
			 * explicitly here since it's only a candidate anyway.
			 */
			if ( !get_manageDSAit( ck->op )
					&& ck->op->ors_scope != LDAP_SCOPE_BASE
					&& is_entry_referral( e ) )
			{
				BerVarray erefs = get_entry_referrals( ck->op, e );
				ck->rs->sr_ref = referral_rewrite( erefs,
						&e->e_name, NULL,
						ck->op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL
							? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );

332
				ck->rs->sr_entry = e;
Howard Chu's avatar
Howard Chu committed
333
				rc = send_search_reference( ck->op, ck->rs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
334
335
336
				ber_bvarray_free( ck->rs->sr_ref );
				ber_bvarray_free( erefs );
				ck->rs->sr_ref = NULL;
337
				ck->rs->sr_entry = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
338
339
340
341
342
343

			} else if ( test_filter( ck->op, e, ck->op->ors_filter ) == LDAP_COMPARE_TRUE )
			{
				ck->rs->sr_entry = e;
				ck->rs->sr_attrs = ck->op->ors_attrs;
				ck->rs->sr_flags = REP_ENTRY_MODIFIABLE;
Howard Chu's avatar
Howard Chu committed
344
				rc = send_search_entry(ck->op, ck->rs);
345
				ck->rs->sr_entry = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
346
347
			}
			fd = 1;
348
			if ( rc )
Howard Chu's avatar
Howard Chu committed
349
				goto done;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
350
351
352
353
354
355
356
357
358
359
		} else {
		/* Queueing up for tool mode */
			if(ck->entries == NULL) {
				ck->entries = (Entry **) SLAP_MALLOC(sizeof(Entry *) * ENTRY_BUFF_INCREMENT);
				ck->elen = ENTRY_BUFF_INCREMENT;
			}
			if(ck->eind >= ck->elen) { /* grow entries if necessary */	
				ck->entries = (Entry **) SLAP_REALLOC(ck->entries, sizeof(Entry *) * (ck->elen) * 2);
				ck->elen *= 2;
			}
360

Kurt Zeilenga's avatar
Kurt Zeilenga committed
361
362
363
			ck->entries[ck->eind++] = e;
			fd = 0;
		}
364
365
	} else {
		fd = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
366
	}
367

Kurt Zeilenga's avatar
Kurt Zeilenga committed
368
	if ( ck->op->ors_scope != LDAP_SCOPE_BASE ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
369
370
371
372
373
374
375
		DIR * dir_of_path;
		bvlist *list = NULL, *ptr;

		path->bv_len -= STRLENOF( LDIF );
		path->bv_val[path->bv_len] = '\0';

		dir_of_path = opendir(path->bv_val);
376
377
378
379
380
381
382
383
384
		if(dir_of_path == NULL) { /* can't open directory */
			if ( errno != ENOENT ) {
				/* it shouldn't be treated as an error
				 * only if the directory doesn't exist */
				rc = LDAP_BUSY;
				Debug( LDAP_DEBUG_TRACE,
					"=> ldif_enum_tree: failed to opendir %s (%d)\n",
					path->bv_val, errno, 0 );
			}
Howard Chu's avatar
Howard Chu committed
385
			goto done;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
386
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
387
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
388
		while(1) {
389
			struct berval fname, itmp;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
390
			struct dirent * dir;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
391
			bvlist *bvl, **prev;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
392
393
394
395
396
397
398
399
400
401
402
403

			dir = readdir(dir_of_path);
			if(dir == NULL) break; /* end of the directory */
			fname.bv_len = strlen( dir->d_name );
			if ( fname.bv_len <= STRLENOF( LDIF ))
				continue;
			if ( strcmp( dir->d_name + (fname.bv_len - STRLENOF(LDIF)), LDIF))
				continue;
			fname.bv_val = dir->d_name;

			bvl = ch_malloc( sizeof(bvlist) );
			ber_dupbv( &bvl->bv, &fname );
404
405
406
407
408
409
410
411
412
413
414
415
416
417
			BER_BVZERO( &bvl->num );
			itmp.bv_val = strchr( bvl->bv.bv_val, IX_FSL );
			if ( itmp.bv_val ) {
				char *ptr;
				itmp.bv_val++;
				ptr = strchr( itmp.bv_val, IX_FSR );
				if ( ptr ) {
					itmp.bv_len = ptr - itmp.bv_val;
					ber_dupbv( &bvl->num, &itmp );
					bvl->inum = strtoul( itmp.bv_val, NULL, 0 );
					itmp.bv_val[0] = '\0';
					bvl->off = itmp.bv_val - bvl->bv.bv_val;
				}
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
418

Kurt Zeilenga's avatar
Kurt Zeilenga committed
419
			for (prev = &list; (ptr = *prev) != NULL; prev = &ptr->next) {
420
421
422
423
				int cmp = strcmp( bvl->bv.bv_val, ptr->bv.bv_val );
				if ( !cmp && bvl->num.bv_val )
					cmp = bvl->inum - ptr->inum;
				if ( cmp < 0 )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
424
425
					break;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
426
			*prev = bvl;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
427
428
429
430
431
			bvl->next = ptr;
				
		}
		closedir(dir_of_path);

Kurt Zeilenga's avatar
Kurt Zeilenga committed
432
433
434
435
		if (ck->op->ors_scope == LDAP_SCOPE_ONELEVEL)
			ck->op->ors_scope = LDAP_SCOPE_BASE;
		else if ( ck->op->ors_scope == LDAP_SCOPE_SUBORDINATE)
			ck->op->ors_scope = LDAP_SCOPE_SUBTREE;
436
437

		while ( ( ptr = list ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
438
			struct berval fpath;
439
440
441

			list = ptr->next;

442
443
444
445
446
447
448
449
			if ( rc == LDAP_SUCCESS ) {
				if ( ptr->num.bv_val )
					AC_MEMCPY( ptr->bv.bv_val + ptr->off, ptr->num.bv_val,
						ptr->num.bv_len );
				fullpath( path, &ptr->bv, &fpath );
				rc = r_enum_tree(ck, &fpath, &e->e_name, &e->e_nname );
				free(fpath.bv_val);
			}
450
451
452
453
			if ( ptr->num.bv_val )
				free( ptr->num.bv_val );
			free(ptr->bv.bv_val);
			free(ptr);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
454
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
455
	}
Howard Chu's avatar
Howard Chu committed
456
done:
457
458
	if ( fd ) entry_free( e );
	return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
459
460
}

461
462
static int
enum_tree(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
463
464
	enumCookie *ck
)
465
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
466
	struct ldif_info *ni = (struct ldif_info *) ck->op->o_bd->be_private;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
467
	struct berval path;
468
	struct berval pdn, pndn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
469
	int rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
470

Kurt Zeilenga's avatar
Kurt Zeilenga committed
471
472
473
	dnParent( &ck->op->o_req_dn, &pdn );
	dnParent( &ck->op->o_req_ndn, &pndn );
	dn2path( &ck->op->o_req_ndn, &ck->op->o_bd->be_nsuffix[0], &ni->li_base_path, &path);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
474
475
476
	rc = r_enum_tree(ck, &path, &pdn, &pndn);
	ch_free( path.bv_val );
	return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
477
478
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
479
480
481
/* Get the parent path plus the LDIF suffix */
static void get_parent_path(struct berval * dnpath, struct berval *res) {
	int dnpathlen = dnpath->bv_len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
482
483
484
	int i;
	
	for(i = dnpathlen;i>0;i--) /* find the first path seperator */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
485
486
487
488
489
490
491
		if(dnpath->bv_val[i] == LDAP_DIRSEP[0])
			break;
	res->bv_len = i;
	res->bv_val = ch_malloc( res->bv_len + 1 + STRLENOF(LDIF) );
	strncpy(res->bv_val, dnpath->bv_val, i);
	strcpy(res->bv_val+i, LDIF);
	res->bv_val[i] = '\0';
Kurt Zeilenga's avatar
Kurt Zeilenga committed
492
493
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
494
495
496
497
static int apply_modify_to_entry(Entry * entry,
				Modifications * modlist,
				Operation * op,
				SlapReply * rs)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
498
499
{
	char textbuf[SLAP_TEXT_BUFLEN];
500
	int rc = LDAP_UNWILLING_TO_PERFORM;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
501
502
503
	Modification *mods = NULL;

	if (!acl_check_modlist(op, entry, modlist)) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
504
		return LDAP_INSUFFICIENT_ACCESS;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
505
506
507
	}

	for (; modlist != NULL; modlist = modlist->sml_next) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
508
509
510
511
512
513
514
		mods = &modlist->sml_mod;

		switch (mods->sm_op) {
		case LDAP_MOD_ADD:
			rc = modify_add_values(entry, mods,
				   get_permissiveModify(op),
				   &rs->sr_text, textbuf,
515
				   sizeof( textbuf ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
516
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
517
				
Kurt Zeilenga's avatar
Kurt Zeilenga committed
518
519
520
521
		case LDAP_MOD_DELETE:
			rc = modify_delete_values(entry, mods,
				get_permissiveModify(op),
				&rs->sr_text, textbuf,
522
				sizeof( textbuf ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
523
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
524
				
Kurt Zeilenga's avatar
Kurt Zeilenga committed
525
526
527
528
		case LDAP_MOD_REPLACE:
			rc = modify_replace_values(entry, mods,
				 get_permissiveModify(op),
				 &rs->sr_text, textbuf,
529
				 sizeof( textbuf ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
530
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
531

Kurt Zeilenga's avatar
Kurt Zeilenga committed
532
		case LDAP_MOD_INCREMENT:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
533
534
535
536
537
538
			rc = modify_increment_values( entry,
				mods, get_permissiveModify(op),
				&rs->sr_text, textbuf,
				sizeof( textbuf ) );
			break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
539
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
540

Kurt Zeilenga's avatar
Kurt Zeilenga committed
541
542
543
544
545
		case SLAP_MOD_SOFTADD:
			mods->sm_op = LDAP_MOD_ADD;
			rc = modify_add_values(entry, mods,
				   get_permissiveModify(op),
				   &rs->sr_text, textbuf,
546
				   sizeof( textbuf ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
547
548
549
550
551
552
553
554
555
			mods->sm_op = SLAP_MOD_SOFTADD;
			if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
				rc = LDAP_SUCCESS;
			}
			break;
		default:
			break;
		}
		if(rc != LDAP_SUCCESS) break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
557
558
	}
	
	if(rc == LDAP_SUCCESS) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
559
560
561
562
		if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
			entry->e_ocflags = 0;
		}
		/* check that the entry still obeys the schema */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
563
		rc = entry_schema_check(op, entry, NULL, 0,
564
			  &rs->sr_text, textbuf, sizeof( textbuf ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
565
566
567
568
	}
	return rc;
}

569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
int
ldif_back_referrals( Operation *op, SlapReply *rs )
{
	struct ldif_info	*ni = NULL;
	Entry			*entry;
	int			rc = LDAP_SUCCESS;

#if 0
	if ( op->o_tag == LDAP_REQ_SEARCH ) {
		/* let search take care of itself */
		return rc;
	}
#endif

	if ( get_manageDSAit( op ) ) {
		/* let op take care of DSA management */
		return rc;
	}

	ni = (struct ldif_info *)op->o_bd->be_private;
	ldap_pvt_thread_mutex_lock( &ni->li_mutex );
	entry = (Entry *)get_entry( op, &ni->li_base_path );

	/* no object is found for them */
	if ( entry == NULL ) {
		struct berval	odn = op->o_req_dn;
		struct berval	ondn = op->o_req_ndn;

		struct berval	pndn = op->o_req_ndn;

		for ( ; entry == NULL; ) {
			dnParent( &pndn, &pndn );
			
			if ( !dnIsSuffix( &pndn, &op->o_bd->be_nsuffix[0] ) ) {
				break;
			}

			op->o_req_dn = pndn;
			op->o_req_ndn = pndn;

			entry = (Entry *)get_entry( op, &ni->li_base_path );
		}

		ldap_pvt_thread_mutex_unlock( &ni->li_mutex );

		op->o_req_dn = odn;
		op->o_req_ndn = ondn;

		rc = LDAP_SUCCESS;
		rs->sr_matched = NULL;
		if ( entry != NULL ) {
			Debug( LDAP_DEBUG_TRACE,
				"ldif_back_referrals: op=%ld target=\"%s\" matched=\"%s\"\n",
				(long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val );

			if ( is_entry_referral( entry ) ) {
				rc = LDAP_OTHER;
				rs->sr_ref = get_entry_referrals( op, entry );
				if ( rs->sr_ref ) {
					rs->sr_matched = ber_strdup_x(
					entry->e_name.bv_val, op->o_tmpmemctx );
				}
			}

			entry_free(entry);

		} else if ( default_referral != NULL ) {
			rc = LDAP_OTHER;
			rs->sr_ref = referral_rewrite( default_referral,
				NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
		}

		if ( rs->sr_ref != NULL ) {
			/* send referrals */
			rc = rs->sr_err = LDAP_REFERRAL;
			send_ldap_result( op, rs );
			ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;

		} else if ( rc != LDAP_SUCCESS ) {
			rs->sr_err = rc;
			rs->sr_text = rs->sr_matched ? "bad referral object" : NULL;
			send_ldap_result( op, rs );
		}

		if ( rs->sr_matched ) {
			op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
			rs->sr_matched = NULL;
		}

		return rc;
	}

	ldap_pvt_thread_mutex_unlock( &ni->li_mutex );

	if ( is_entry_referral( entry ) ) {
		/* entry is a referral */
		BerVarray refs = get_entry_referrals( op, entry );
		rs->sr_ref = referral_rewrite(
			refs, &entry->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT );

		Debug( LDAP_DEBUG_TRACE,
			"ldif_back_referrals: op=%ld target=\"%s\" matched=\"%s\"\n",
			(long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val );

		rs->sr_matched = entry->e_name.bv_val;
		if ( rs->sr_ref != NULL ) {
			rc = rs->sr_err = LDAP_REFERRAL;
			send_ldap_result( op, rs );
			ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;

		} else {
			send_ldap_error( op, rs, LDAP_OTHER, "bad referral object" );
			rc = rs->sr_err;
		}

		rs->sr_matched = NULL;
		ber_bvarray_free( refs );
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
690
691
	entry_free( entry );

692
693
694
	return rc;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
695
696
697
698
699
700
701
702
703
704
705
static int
ldif_back_bind( Operation *op, SlapReply *rs )
{
	struct ldif_info *ni = NULL;
	Attribute * a = NULL;
	AttributeDescription *password = slap_schema.si_ad_userPassword;
	int return_val = 0;
	Entry * entry = NULL;

	ni = (struct ldif_info *) op->o_bd->be_private;
	ldap_pvt_thread_mutex_lock(&ni->li_mutex);
706
	entry = (Entry *) get_entry(op, &ni->li_base_path);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
707
708
709

	/* no object is found for them */
	if(entry == NULL) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
710
		if(be_isroot_pw(op)) {
711
712
713
			rs->sr_err = return_val = LDAP_SUCCESS;
		} else {
			rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
714
		}
715
		goto return_result;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
716
717
718
719
	}

	/* they don't have userpassword */
	if((a = attr_find(entry->e_attrs, password)) == NULL) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
720
721
722
		rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
		return_val = 1;
		goto return_result;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
723
724
725
726
	}

	/* authentication actually failed */
	if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
727
728
729
730
			     &rs->sr_text) != 0) {
		rs->sr_err = LDAP_INVALID_CREDENTIALS;
		return_val = 1;
		goto return_result;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
731
732
733
734
735
736
737
738
739
	}

	/* let the front-end send success */
	return_val = 0;
	goto return_result;

 return_result:
	ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
	if(return_val != 0)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
740
		send_ldap_result( op, rs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
741
	if(entry != NULL)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
742
		entry_free(entry);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
743
744
745
746
747
748
	return return_val;
}

static int ldif_back_search(Operation *op, SlapReply *rs)
{
	struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
749
	enumCookie ck = { NULL, NULL, NULL, 0, 0 };
Kurt Zeilenga's avatar
Kurt Zeilenga committed
750

Kurt Zeilenga's avatar
Kurt Zeilenga committed
751
752
	ck.op = op;
	ck.rs = rs;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
753
	ldap_pvt_thread_mutex_lock(&ni->li_mutex);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
754
	rs->sr_err = enum_tree( &ck );
755
756
	ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
	send_ldap_result(op, rs);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
757

758
	return rs->sr_err;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
759
760
761
762
763
764
}

static int ldif_back_add(Operation *op, SlapReply *rs) {
	struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
	Entry * e = op->ora_e;
	struct berval dn = e->e_nname;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
765
	struct berval leaf_path = BER_BVNULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
766
767
768
769
	struct stat stats;
	int statres;
	char textbuf[SLAP_TEXT_BUFLEN];

Kurt Zeilenga's avatar
Kurt Zeilenga committed
770
	slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
771

Kurt Zeilenga's avatar
Kurt Zeilenga committed
772
	rs->sr_err = entry_schema_check(op, e, NULL, 0,
773
		&rs->sr_text, textbuf, sizeof( textbuf ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
774
775
	if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
				
Kurt Zeilenga's avatar
Kurt Zeilenga committed
776
777
	ldap_pvt_thread_mutex_lock(&ni->li_mutex);

Kurt Zeilenga's avatar
Kurt Zeilenga committed
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
	dn2path(&dn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &leaf_path);

	if(leaf_path.bv_val != NULL) {
		struct berval base = BER_BVNULL;
		/* build path to container and ldif of container */
		get_parent_path(&leaf_path, &base);

		statres = stat(base.bv_val, &stats); /* check if container exists */
		if(statres == -1 && errno == ENOENT) { /* container missing */
			base.bv_val[base.bv_len] = '.';
			statres = stat(base.bv_val, &stats); /* check for leaf node */
			base.bv_val[base.bv_len] = '\0';
			if(statres == -1 && errno == ENOENT) {
				rs->sr_err = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
			}
			else if(statres != -1) { /* create parent */
				int mkdirres = mkdir(base.bv_val, 0750);
				if(mkdirres == -1) {
					rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
				}
			}
			else
				rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		}/* container was possibly created, move on to add the entry */
		if(rs->sr_err == LDAP_SUCCESS) {
			statres = stat(leaf_path.bv_val, &stats);
			if(statres == -1 && errno == ENOENT) {
				ldap_pvt_thread_mutex_lock(&entry2str_mutex);
				rs->sr_err = (int) spew_entry(e, &leaf_path);
				ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
			}
			else /* it already exists */
				rs->sr_err = LDAP_ALREADY_EXISTS;
		}
		SLAP_FREE(base.bv_val);
		SLAP_FREE(leaf_path.bv_val);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
814
815
816
817
	}

	ldap_pvt_thread_mutex_unlock(&ni->li_mutex);

Kurt Zeilenga's avatar
Kurt Zeilenga committed
818
819
send_res:
	send_ldap_result(op, rs);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
820
821
	if ( !SLAP_SHADOW( op->o_bd ))
		slap_graduate_commit_csn( op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
822
823
824
825
826
827
	return 0;
}

static int ldif_back_modify(Operation *op, SlapReply *rs) {
	struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
	Modifications * modlst = op->orm_modlist;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
828
	struct berval path = BER_BVNULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
829
830
831
	Entry * entry = NULL;
	int spew_res;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
832
	if ( !SLAP_SHADOW( op->o_bd ))
Kurt Zeilenga's avatar
Kurt Zeilenga committed
833
		slap_mods_opattrs( op, &op->orm_modlist, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
834

Kurt Zeilenga's avatar
Kurt Zeilenga committed
835
	ldap_pvt_thread_mutex_lock(&ni->li_mutex);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
836
837
	dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path,
		&path);
838
	entry = (Entry *) get_entry(op, &ni->li_base_path);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
839
840

	if(entry != NULL) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
841
842
843
844
845
846
847
848
849
850
		rs->sr_err = apply_modify_to_entry(entry, modlst, op, rs);
		if(rs->sr_err == LDAP_SUCCESS) {
			ldap_pvt_thread_mutex_lock(&entry2str_mutex);
			spew_res = spew_entry(entry, &path);
			ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
			if(spew_res == -1) {
				perror("could not output entry");
				rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
851
852
	}
	else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
853
		rs->sr_err = LDAP_NO_SUCH_OBJECT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
854
855
856
	}
	
	if(entry != NULL)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
857
858
859
860
		entry_free(entry);
	if(path.bv_val != NULL)
		SLAP_FREE(path.bv_val);
	rs->sr_text = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
861
862
	ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
	send_ldap_result(op, rs);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
863
864
	if ( !SLAP_SHADOW( op->o_bd ))
		slap_graduate_commit_csn( op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
865
866
867
868
869
	return 0;
}

static int ldif_back_delete(Operation *op, SlapReply *rs) {
	struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
870
	struct berval path = BER_BVNULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
871
872
	int res = 0;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
873
874
875
876
877
878
879
880
881
	if ( !SLAP_SHADOW( op->o_bd )) {
		struct berval csn;
		char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];

		csn.bv_val = csnbuf;
		csn.bv_len = sizeof( csnbuf );
		slap_get_csn( op, &csn, 1 );
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
882
	ldap_pvt_thread_mutex_lock(&ni->li_mutex);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
883
	dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &path);
884
885
886
887
888
889
890
891
892

	path.bv_val[path.bv_len - STRLENOF(LDIF)] = '\0';
	res = rmdir(path.bv_val);
	path.bv_val[path.bv_len - STRLENOF(LDIF)] = '.';
	if ( res && errno != ENOENT ) {
		rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
	} else {
		res = unlink(path.bv_val);
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
893
894

	if(res == -1) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
895
896
897
898
		if(errno == ENOENT)
			rs->sr_err = LDAP_NO_SUCH_OBJECT;
		else
			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
899
900
	}
	else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
901
		rs->sr_err = LDAP_SUCCESS;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
902

Kurt Zeilenga's avatar
Kurt Zeilenga committed
903
	SLAP_FREE(path.bv_val);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
904
905
	ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
	send_ldap_result(op, rs);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
906
907
	if ( !SLAP_SHADOW( op->o_bd ))
		slap_graduate_commit_csn( op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
908
909
910
911
	return 0;
}


Kurt Zeilenga's avatar
Kurt Zeilenga committed
912
913
914
static int move_entry(Entry * entry, struct berval * ndn,
			   struct berval * newndn, struct berval * rootdn,
			   struct berval * base_path) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
915
916
	int res;
	int exists_res;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
917
918
	struct berval path;
	struct berval newpath;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
919

Kurt Zeilenga's avatar
Kurt Zeilenga committed
920
921
922
923
924
925
	dn2path(ndn, rootdn, base_path, &path);
	dn2path(newndn, rootdn, base_path, &newpath);

	if((entry == NULL || path.bv_val == NULL) || newpath.bv_val == NULL) {
		/* some object doesn't exist */
		res = LDAP_NO_SUCH_OBJECT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
926
927
	}
	else { /* do the modrdn */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
		exists_res = open(newpath.bv_val, O_RDONLY);
		if(exists_res == -1 && errno == ENOENT) {
			res = spew_entry(entry, &newpath);
			if(res != -1) {
				/* if this fails we should log something bad */
				res = unlink(path.bv_val);
				res = LDAP_SUCCESS;
			}
			else {
				if(errno == ENOENT)
					res = LDAP_NO_SUCH_OBJECT;
				else
					res = LDAP_UNWILLING_TO_PERFORM;
				unlink(newpath.bv_val); /* in case file was created */
			}
		}
		else if(exists_res) {
			int close_res = close(exists_res);
			res = LDAP_ALREADY_EXISTS;
			if(close_res == -1) {
			/* log heinous error */
			}
		}
		else {
			res = LDAP_UNWILLING_TO_PERFORM;
		}
	}

	if(newpath.bv_val != NULL)
		SLAP_FREE(newpath.bv_val);
	if(path.bv_val != NULL)
		SLAP_FREE(path.bv_val);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
960
961
962
963
964
	return res;
}

static int ldif_back_modrdn(Operation *op, SlapReply *rs) {
	struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
965
966
	struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
	struct berval p_dn, bv = BER_BVNULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
967
968
969
970
971
972
973
974
	Entry * entry = NULL;
	LDAPRDN new_rdn = NULL;
	LDAPRDN old_rdn = NULL;
	Modifications * mods = NULL;
	int res;

	ldap_pvt_thread_mutex_lock(&ni->li_mutex);
	ldap_pvt_thread_mutex_lock(&entry2str_mutex);
975
	entry = (Entry *) get_entry(op, &ni->li_base_path);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
976
977
978

	/* build the mods to the entry */
	if(entry != NULL) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
979
980
981
982
983
984
		if(ldap_bv2rdn(&op->oq_modrdn.rs_newrdn, &new_rdn,
			(char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP)) {
			rs->sr_err = LDAP_INVALID_DN_SYNTAX;
		}
		else if(op->oq_modrdn.rs_deleteoldrdn &&
			ldap_bv2rdn(&op->o_req_dn, &old_rdn, (char **)&rs->sr_text,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
985
			LDAP_DN_FORMAT_LDAP)) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
			rs->sr_err = LDAP_OTHER;
		}
		else { /* got both rdns successfully, ready to build mods */
			if(slap_modrdn2mods(op, rs, entry, old_rdn, new_rdn, &mods)
				!= LDAP_SUCCESS) {
				rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
			}
			else { /* built mods successfully */

				/* build new dn, and new ndn for the entry */
				if(op->oq_modrdn.rs_newSup != NULL) /* new superior */
					p_dn = *op->oq_modrdn.rs_newSup;
				else
					p_dn = slap_empty_bv;
				dnParent(&entry->e_name, &p_dn);
				build_new_dn(&new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL); 
				dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx );
				ber_dupbv( &new_ndn, &bv );
				entry->e_name = new_dn;
				entry->e_nname = new_ndn;

				/* perform the modifications */
				res = apply_modify_to_entry(entry, mods, op, rs);
				if(res == LDAP_SUCCESS) {
					rs->sr_err = move_entry(entry, &op->o_req_ndn,
								&new_ndn,
								&op->o_bd->be_nsuffix[0],
								&ni->li_base_path);
				}
				else
					rs->sr_err = res;
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1019
1020
	}
	else /* entry was null */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1021
		rs->sr_err = LDAP_NO_SUCH_OBJECT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1022
1023

	if(entry != NULL)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1024
		entry_free(entry);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1025
1026
1027
1028
1029
1030
1031
	rs->sr_text = "";
	ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
	ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
	send_ldap_result(op, rs);
	return 0;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
/* return LDAP_SUCCESS IFF we can retrieve the specified entry.
 */
int ldif_back_entry_get(
	Operation *op,
	struct berval *ndn,
	ObjectClass *oc,
	AttributeDescription *at,
	int rw,
	Entry **ent )
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1042
1043
	struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1044
	ldap_pvt_thread_mutex_lock( &ni->li_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1045

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1046
	*ent = (Entry *) get_entry( op, &ni->li_base_path );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1047

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1048
1049
1050
	ldap_pvt_thread_mutex_unlock( &ni->li_mutex );

	return ( *ent == NULL ? 1 : 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1051
1052
1053
}

static int ldif_tool_entry_open(BackendDB * be, int mode) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1054
	struct ldif_info *ni = (struct ldif_info *) be->be_private;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1055
	ni->li_tool_current = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1056
1057
1058
1059
	return 0;
}					

static int ldif_tool_entry_close(BackendDB * be) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1060
1061
	struct ldif_info *ni = (struct ldif_info *) be->be_private;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1062
	SLAP_FREE(ni->li_tool_cookie.entries);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1063
1064
1065
	return 0;
}

1066
1067
1068
static ID
ldif_tool_entry_first(BackendDB *be)
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1069
	struct ldif_info *ni = (struct ldif_info *) be->be_private;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1070
	ID id = 1; /* first entry in the array of entries shifted by one */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1071

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
	ni->li_tool_current = 1;
	if(ni->li_tool_cookie.entries == NULL) {
		Operation op = {0};

		op.o_bd = be;
		op.o_req_dn = *be->be_suffix;
		op.o_req_ndn = *be->be_nsuffix;
		op.ors_scope = LDAP_SCOPE_SUBTREE;
		ni->li_tool_cookie.op = &op;
		(void)enum_tree( &ni->li_tool_cookie );
		ni->li_tool_cookie.op = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1083
1084
1085
1086
	}
	return id;
}

1087
1088
static ID ldif_tool_entry_next(BackendDB *be)
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1089
	struct ldif_info *ni = (struct ldif_info *) be->be_private;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1090
1091
	ni->li_tool_current += 1;
	if(ni->li_tool_current > ni->li_tool_cookie.eind)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1092
		return NOID;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1093
	else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1094
		return ni->li_tool_current;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1095
1096
1097
}

static Entry * ldif_tool_entry_get(BackendDB * be, ID id) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1098
	struct ldif_info *ni = (struct ldif_info *) be->be_private;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1099
1100
	Entry * e;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1101
	if(id > ni->li_tool_cookie.eind || id < 1)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1102
		return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1103
	else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1104
1105
		e = ni->li_tool_cookie.entries[id - 1];
		ni->li_tool_cookie.entries[id - 1] = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1106
		return e;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1107
1108
1109
1110
	}
}

static ID ldif_tool_entry_put(BackendDB * be, Entry * e, struct berval *text) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1111
	struct ldif_info *ni = (struct ldif_info *) be->be_private;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1112
	struct berval dn = e->e_nname;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1113
	struct berval leaf_path = BER_BVNULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1114
1115
1116
1117
	struct stat stats;
	int statres;
	int res = LDAP_SUCCESS;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
	dn2path(&dn, &be->be_nsuffix[0], &ni->li_base_path, &leaf_path);

	if(leaf_path.bv_val != NULL) {
		struct berval base = BER_BVNULL;
		/* build path to container, and path to ldif of container */
		get_parent_path(&leaf_path, &base);

		statres = stat(base.bv_val, &stats); /* check if container exists */
		if(statres == -1 && errno == ENOENT) { /* container missing */
			base.bv_val[base.bv_len] = '.';
			statres = stat(base.bv_val, &stats); /* check for leaf node */
			base.bv_val[base.bv_len] = '\0';
			if(statres == -1 && errno == ENOENT) {
				res = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
			}
			else if(statres != -1) { /* create parent */
				int mkdirres = mkdir(base.bv_val, 0750);
				if(mkdirres == -1) {
					res = LDAP_UNWILLING_TO_PERFORM;
				}
			}
			else
				res = LDAP_UNWILLING_TO_PERFORM;
		}/* container was possibly created, move on to add the entry */
		if(res == LDAP_SUCCESS) {
			statres = stat(leaf_path.bv_val, &stats);
			if(statres == -1 && errno == ENOENT) {
				res = (int) spew_entry(e, &leaf_path);
			}
			else /* it already exists */
				res = LDAP_ALREADY_EXISTS;
		}
		SLAP_FREE(base.bv_val);
		SLAP_FREE(leaf_path.bv_val);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1152
1153
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1154
1155
	if(res == LDAP_SUCCESS) {
		return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1156
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1157
1158
	else
		return NOID;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1159
1160
1161
1162
1163
1164
1165
1166
1167
}

static int
ldif_back_db_init( BackendDB *be )
{
	struct ldif_info *ni;

	ni = ch_calloc( 1, sizeof(struct ldif_info) );
	be->be_private = ni;
1168
	be->be_cf_ocs = ldifocs;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1169
1170
1171
1172
1173
1174
	ldap_pvt_thread_mutex_init(&ni->li_mutex);
	return 0;
}

static int
ldif_back_db_destroy(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1175
1176
			   Backend	*be
			   )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1177
1178
{
	struct ldif_info *ni = be->be_private;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1179
1180

	ch_free(ni->li_base_path.bv_val);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1181
1182
1183
1184
1185
1186
1187
	ldap_pvt_thread_mutex_destroy(&ni->li_mutex);
	free( be->be_private );
	return 0;
}

static int
ldif_back_db_open(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1188
1189
			Backend	*be
			)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1190
1191
1192
{
	struct ldif_info *ni = (struct ldif_info *) be->be_private;
	if( BER_BVISEMPTY(&ni->li_base_path)) {/* missing base path */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1193
1194
		fprintf(stderr, "missing base path for back-ldif\n");
		return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1195
1196
1197
1198
1199
1200
	}
	return 0;
}

int
ldif_back_initialize(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1201
1202
			   BackendInfo	*bi
			   )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1203
{
1204
1205
1206
1207
	static char *controls[] = {
		LDAP_CONTROL_MANAGEDSAIT,
		NULL
	};
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1208
1209
	int rc;

1210
	bi->bi_flags |=
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1211
		SLAP_BFLAG_INCREMENT |
1212
1213
1214
1215
		SLAP_BFLAG_REFERRALS;

	bi->bi_controls = controls;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1216
1217
1218
1219
1220
1221
	bi->bi_open = 0;
	bi->bi_close = 0;
	bi->bi_config = 0;
	bi->bi_destroy = 0;

	bi->bi_db_init = ldif_back_db_init;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1222
	bi->bi_db_config = config_generic_wrapper;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1223
1224
1225
1226
1227
1228
1229
	bi->bi_db_open = ldif_back_db_open;
	bi->bi_db_close = 0;
	bi->bi_db_destroy = ldif_back_db_destroy;

	bi->bi_op_bind = ldif_back_bind;
	bi->bi_op_unbind = 0;
	bi->bi_op_search = ldif_back_search;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1230
	bi->bi_op_compare = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1231
1232
1233
1234
1235
1236
1237
1238
	bi->bi_op_modify = ldif_back_modify;
	bi->bi_op_modrdn = ldif_back_modrdn;
	bi->bi_op_add = ldif_back_add;
	bi->bi_op_delete = ldif_back_delete;
	bi->bi_op_abandon = 0;

	bi->bi_extended = 0;

1239
	bi->bi_chk_referrals = ldif_back_referrals;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1240
1241
1242
1243

	bi->bi_connection_init = 0;
	bi->bi_connection_destroy = 0;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1244
1245
1246
1247
1248
1249
1250
1251
	bi->bi_entry_get_rw = ldif_back_entry_get;

#if 0	/* NOTE: uncomment to completely disable access control */
#ifdef SLAP_OVERLAY_ACCESS
	bi->bi_access_allowed = slap_access_always_allowed;
#endif /* SLAP_OVERLAY_ACCESS */
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
	bi->bi_tool_entry_open = ldif_tool_entry_open;
	bi->bi_tool_entry_close = ldif_tool_entry_close;
	bi->bi_tool_entry_first = ldif_tool_entry_first;
	bi->bi_tool_entry_next = ldif_tool_entry_next;
	bi->bi_tool_entry_get = ldif_tool_entry_get;
	bi->bi_tool_entry_put = ldif_tool_entry_put;
	bi->bi_tool_entry_reindex = 0;
	bi->bi_tool_sync = 0;
	
	bi->bi_tool_dn2id_get = 0;
	bi->bi_tool_id2entry_get = 0;
	bi->bi_tool_entry_modify = 0;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1265
1266
	bi->bi_cf_ocs = ldifocs;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1267
1268
	rc = config_register_schema( ldifcfg, ldifocs );
	if ( rc ) return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1269
1270
	return 0;
}