backend.c 38.5 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* backend.c - routines for dealing with back-end databases */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 1998-2007 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 * 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>.
 */
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of Michigan at Ann Arbor. The name of the University
 * may not be used to endorse or promote products derived from this
 * software without specific prior written permission. This software
 * is provided ``as is'' without express or implied warranty.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
25
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
26
27


Kurt Zeilenga's avatar
Kurt Zeilenga committed
28
29
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
30
#include <stdio.h>
Pierangelo Masarati's avatar
Pierangelo Masarati committed
31

Kurt Zeilenga's avatar
Kurt Zeilenga committed
32
33
#include <ac/string.h>
#include <ac/socket.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
#include <sys/stat.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
35

Kurt Zeilenga's avatar
Kurt Zeilenga committed
36
#include "slap.h"
37
#include "config.h"
38
#include "lutil.h"
39
#include "lber_pvt.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
40

41
42
43
44
45
46
47
48
/*
 * If a module is configured as dynamic, its header should not
 * get included into slapd. While this is a general rule and does
 * not have much of an effect in UNIX, this rule should be adhered
 * to for Windows, where dynamic object code should not be implicitly
 * imported into slapd without appropriate __declspec(dllimport) directives.
 */

49
int			nBackendInfo = 0;
50
slap_bi_head backendInfo = LDAP_STAILQ_HEAD_INITIALIZER(backendInfo);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
51

52
int			nBackendDB = 0; 
53
slap_be_head backendDB = LDAP_STAILQ_HEAD_INITIALIZER(backendDB);
54

55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
static int
backend_init_controls( BackendInfo *bi )
{
	if ( bi->bi_controls ) {
		int	i;

		for ( i = 0; bi->bi_controls[ i ]; i++ ) {
			int	cid;

			if ( slap_find_control_id( bi->bi_controls[ i ], &cid )
					== LDAP_CONTROL_NOT_FOUND )
			{
				if ( !( slapMode & SLAP_TOOL_MODE ) ) {
					assert( 0 );
				}

				return -1;
			}

			bi->bi_ctrls[ cid ] = 1;
		}
	}

	return 0;
}

81
int backend_init(void)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
82
{
83
	int rc = -1;
84
	BackendInfo *bi;
85

86
	if((nBackendInfo != 0) || !LDAP_STAILQ_EMPTY(&backendInfo)) {
87
88
		/* already initialized */
		Debug( LDAP_DEBUG_ANY,
89
			"backend_init: already initialized\n", 0, 0, 0 );
90
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
91
92
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
93
	for( bi=slap_binfo; bi->bi_type != NULL; bi++,nBackendInfo++ ) {
94
		assert( bi->bi_init != 0 );
95

96
		rc = bi->bi_init( bi );
97
98
99
100

		if(rc != 0) {
			Debug( LDAP_DEBUG_ANY,
				"backend_init: initialized for type \"%s\"\n",
101
				bi->bi_type, 0, 0 );
102
103
104
105
106
			/* destroy those we've already inited */
			for( nBackendInfo--;
				nBackendInfo >= 0 ;
				nBackendInfo-- )
			{ 
107
108
109
				if ( slap_binfo[nBackendInfo].bi_destroy ) {
					slap_binfo[nBackendInfo].bi_destroy(
						&slap_binfo[nBackendInfo] );
110
111
112
113
				}
			}
			return rc;
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
114

115
		LDAP_STAILQ_INSERT_TAIL(&backendInfo, bi, bi_next);
116
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
117

118
119
	if ( nBackendInfo > 0) {
		return 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
120
121
	}

122
123
124
#ifdef SLAPD_MODULES	
	return 0;
#else
125

126
	Debug( LDAP_DEBUG_ANY,
127
128
129
		"backend_init: failed\n",
		0, 0, 0 );

130
	return rc;
131
132
133
134
135
#endif /* SLAPD_MODULES */
}

int backend_add(BackendInfo *aBackendInfo)
{
136
	int rc = 0;
137

138
139
140
141
142
143
	if ( aBackendInfo->bi_init == NULL ) {
		Debug( LDAP_DEBUG_ANY, "backend_add: "
			"backend type \"%s\" does not have the (mandatory)init function\n",
			aBackendInfo->bi_type, 0, 0 );
		return -1;
	}
144

145
146
	rc = aBackendInfo->bi_init(aBackendInfo);
	if ( rc != 0) {
147
148
149
150
		Debug( LDAP_DEBUG_ANY,
			"backend_add:  initialization for type \"%s\" failed\n",
			aBackendInfo->bi_type, 0, 0 );
		return rc;
151
152
153
	}

	(void)backend_init_controls( aBackendInfo );
154

155
	/* now add the backend type to the Backend Info List */
156
157
158
	LDAP_STAILQ_INSERT_TAIL( &backendInfo, aBackendInfo, bi_next );
	nBackendInfo++;
	return 0;
159
160
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
161
162
static int
backend_set_controls( BackendDB *be )
Howard Chu's avatar
Howard Chu committed
163
{
164
	BackendInfo	*bi = be->bd_info;
Howard Chu's avatar
Howard Chu committed
165

166
	/* back-relay takes care of itself; so may do other */
167
168
169
	if ( overlay_is_over( be ) ) {
		bi = ((slap_overinfo *)be->bd_info->bi_private)->oi_orig;
	}
170

171
	if ( bi->bi_controls ) {
172
		if ( be->be_ctrls[ SLAP_MAX_CIDS ] == 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
173
174
			AC_MEMCPY( be->be_ctrls, bi->bi_ctrls,
					sizeof( be->be_ctrls ) );
175
			be->be_ctrls[ SLAP_MAX_CIDS ] = 1;
176
			
177
178
		} else {
			int	i;
179
			
180
181
			for ( i = 0; i < SLAP_MAX_CIDS; i++ ) {
				if ( bi->bi_ctrls[ i ] ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
182
					be->be_ctrls[ i ] = bi->bi_ctrls[ i ];
183
184
				}
			}
185
		}
186

187
188
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
189
190
191
192
	return 0;
}

/* startup a specific backend database */
193
int backend_startup_one(Backend *be, ConfigReply *cr)
Pierangelo Masarati's avatar
Pierangelo Masarati committed
194
195
196
{
	int		rc = 0;

197
	assert( be != NULL );
198

Pierangelo Masarati's avatar
Pierangelo Masarati committed
199
	be->be_pending_csn_list = (struct be_pcl *)
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
200
		ch_calloc( 1, sizeof( struct be_pcl ) );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
201
202
203
204
205
206
207

	LDAP_TAILQ_INIT( be->be_pending_csn_list );

	Debug( LDAP_DEBUG_TRACE,
		"backend_startup_one: starting \"%s\"\n",
		be->be_suffix ? be->be_suffix[0].bv_val : "(unknown)",
		0, 0 );
208
209

	/* set database controls */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
210
	(void)backend_set_controls( be );
211

Pierangelo Masarati's avatar
Pierangelo Masarati committed
212
	if ( be->bd_info->bi_db_open ) {
213
		rc = be->bd_info->bi_db_open( be, cr );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
214
215
216
217
218
219
220
221
222
223
		if ( rc == 0 ) {
			(void)backend_set_controls( be );

		} else {
			Debug( LDAP_DEBUG_ANY,
				"backend_startup_one: bi_db_open failed! (%d)\n",
				rc, 0, 0 );
		}
	}

Howard Chu's avatar
Howard Chu committed
224
225
226
	return rc;
}

227
int backend_startup(Backend *be)
228
229
230
{
	int i;
	int rc = 0;
231
	BackendInfo *bi;
232
	ConfigReply cr={0, ""};
233
234
235
236
237
238
239

	if( ! ( nBackendDB > 0 ) ) {
		/* no databases */
		Debug( LDAP_DEBUG_ANY,
			"backend_startup: %d databases to startup.\n",
			nBackendDB, 0, 0 );
		return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
240
241
	}

242
243
244
	if(be != NULL) {
		if ( be->bd_info->bi_open ) {
			rc = be->bd_info->bi_open( be->bd_info );
245
246
247
248
			if ( rc != 0 ) {
				Debug( LDAP_DEBUG_ANY,
					"backend_startup: bi_open failed!\n",
					0, 0, 0 );
249

250
251
				return rc;
			}
252
		}
253
254
		/* append global access controls */
		acl_append( &be->be_acl, frontendDB->be_acl, -1 );
255

256
		return backend_startup_one( be, &cr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
258
	}

259
260
	/* open frontend, if required */
	if ( frontendDB->bd_info->bi_db_open ) {
261
		rc = frontendDB->bd_info->bi_db_open( frontendDB, NULL );
262
263
264
265
266
267
268
269
		if ( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY,
				"backend_startup: bi_db_open(frontend) failed! (%d)\n",
				rc, 0, 0 );
			return rc;
		}
	}

270
	/* open each backend type */
271
272
273
274
	i = -1;
	LDAP_STAILQ_FOREACH(bi, &backendInfo, bi_next) {
		i++;
		if( bi->bi_nDB == 0) {
275
276
277
278
			/* no database of this type, don't open */
			continue;
		}

279
280
		if( bi->bi_open ) {
			rc = bi->bi_open( bi );
281
282
			if ( rc != 0 ) {
				Debug( LDAP_DEBUG_ANY,
283
284
					"backend_startup: bi_open %d (%s) failed!\n",
					i, bi->bi_type, 0 );
285
286
				return rc;
			}
287
		}
288

289
		(void)backend_init_controls( bi );
290
291
	}

292
	/* open each backend database */
293
294
295
296
	i = -1;
	LDAP_STAILQ_FOREACH(be, &backendDB, be_next) {
		i++;
		if ( be->be_suffix == NULL ) {
297
298
299
			Debug( LDAP_DEBUG_ANY,
				"backend_startup: warning, database %d (%s) "
				"has no suffix\n",
300
				i, be->bd_info->bi_type, 0 );
301
		}
Howard Chu's avatar
Howard Chu committed
302
		/* append global access controls */
303
		acl_append( &be->be_acl, frontendDB->be_acl, -1 );
Howard Chu's avatar
Howard Chu committed
304

305
		rc = backend_startup_one( be, &cr );
Howard Chu's avatar
Howard Chu committed
306
307

		if ( rc ) return rc;
308
309
310
311
312
	}

	return rc;
}

313
int backend_num( Backend *be )
314
{
315
316
	int i = 0;
	BackendDB *b2;
317

318
319
	if( be == NULL ) return -1;

320
321
322
	LDAP_STAILQ_FOREACH( b2, &backendDB, be_next ) {
		if( be == b2 ) return i;
		i++;
323
324
325
	}
	return -1;
}
326

327
328
329
int backend_shutdown( Backend *be )
{
	int rc = 0;
330
	BackendInfo *bi;
331

332
333
	if( be != NULL ) {
		/* shutdown a specific backend database */
334

335
		if ( be->bd_info->bi_nDB == 0 ) {
336
337
338
339
			/* no database of this type, we never opened it */
			return 0;
		}

340
		if ( be->bd_info->bi_db_close ) {
341
			be->bd_info->bi_db_close( be, NULL );
342
343
		}

344
345
		if( be->bd_info->bi_close ) {
			be->bd_info->bi_close( be->bd_info );
346
347
348
349
350
351
		}

		return 0;
	}

	/* close each backend database */
352
353
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
		if ( be->bd_info->bi_db_close ) {
354
			be->bd_info->bi_db_close( be, NULL );
355
		}
356
357
358

		if(rc != 0) {
			Debug( LDAP_DEBUG_ANY,
359
				"backend_close: bi_db_close %s failed!\n",
360
				be->be_type, 0, 0 );
361
		}
362
363
364
	}

	/* close each backend type */
365
366
	LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next ) {
		if( bi->bi_nDB == 0 ) {
367
368
369
370
			/* no database of this type */
			continue;
		}

371
372
		if( bi->bi_close ) {
			bi->bi_close( bi );
373
374
375
		}
	}

376
377
	/* close frontend, if required */
	if ( frontendDB->bd_info->bi_db_close ) {
378
		rc = frontendDB->bd_info->bi_db_close ( frontendDB, NULL );
379
380
381
382
383
384
385
		if ( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY,
				"backend_startup: bi_db_close(frontend) failed! (%d)\n",
				rc, 0, 0 );
		}
	}

386
387
388
	return 0;
}

389
390
391
392
393
394
395
396
397
398
399
/*
 * This function is supposed to be the exact counterpart
 * of backend_startup_one(), although this one calls bi_db_destroy()
 * while backend_startup_one() calls bi_db_open().
 *
 * Make sure backend_stopdown_one() destroys resources allocated
 * by backend_startup_one(); only call backend_destroy_one() when
 * all stuff in a BackendDB needs to be destroyed
 */
void
backend_stopdown_one( BackendDB *bd )
400
401
402
403
404
405
406
407
408
409
410
411
{
	if ( bd->be_pending_csn_list ) {
		struct slap_csn_entry *csne;
		csne = LDAP_TAILQ_FIRST( bd->be_pending_csn_list );
		while ( csne ) {
			struct slap_csn_entry *tmp_csne = csne;

			LDAP_TAILQ_REMOVE( bd->be_pending_csn_list, csne, ce_csn_link );
			ch_free( csne->ce_csn.bv_val );
			csne = LDAP_TAILQ_NEXT( csne, ce_csn_link );
			ch_free( tmp_csne );
		}
Howard Chu's avatar
Howard Chu committed
412
		ch_free( bd->be_pending_csn_list );
413
414
415
	}

	if ( bd->bd_info->bi_db_destroy ) {
416
		bd->bd_info->bi_db_destroy( bd, NULL );
417
	}
418
419
420
421
422
}

void backend_destroy_one( BackendDB *bd, int dynamic )
{
	if ( dynamic ) {
423
		LDAP_STAILQ_REMOVE(&backendDB, bd, BackendDB, be_next );
424
425
426
	}

	if ( bd->be_syncinfo ) {
427
		syncinfo_free( bd->be_syncinfo, 1 );
428
429
430
431
	}

	backend_stopdown_one( bd );

432
433
434
435
436
437
438
439
440
441
442
443
	ber_bvarray_free( bd->be_suffix );
	ber_bvarray_free( bd->be_nsuffix );
	if ( !BER_BVISNULL( &bd->be_rootdn ) ) {
		free( bd->be_rootdn.bv_val );
	}
	if ( !BER_BVISNULL( &bd->be_rootndn ) ) {
		free( bd->be_rootndn.bv_val );
	}
	if ( !BER_BVISNULL( &bd->be_rootpw ) ) {
		free( bd->be_rootpw.bv_val );
	}
	acl_destroy( bd->be_acl, frontendDB->be_acl );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
444
	limits_destroy( bd->be_limits );
445
446
447
448
449
450
	if ( !BER_BVISNULL( &bd->be_update_ndn ) ) {
		ch_free( bd->be_update_ndn.bv_val );
	}
	if ( bd->be_update_refs ) {
		ber_bvarray_free( bd->be_update_refs );
	}
451

Howard Chu's avatar
Howard Chu committed
452
453
454
	if ( dynamic ) {
		free( bd );
	}
455
456
}

457
458
int backend_destroy(void)
{
Howard Chu's avatar
Howard Chu committed
459
	BackendDB *bd;
460
	BackendInfo *bi;
461
462

	/* destroy each backend database */
463
	while (( bd = LDAP_STAILQ_FIRST(&backendDB))) {
Howard Chu's avatar
Howard Chu committed
464
		backend_destroy_one( bd, 1 );
465
	}
466

467
	/* destroy each backend type */
468
469
470
	LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next ) {
		if( bi->bi_destroy ) {
			bi->bi_destroy( bi );
471
472
473
		}
	}

474
	nBackendInfo = 0;
475
	LDAP_STAILQ_INIT(&backendInfo);
476

477
478
	/* destroy frontend database */
	bd = frontendDB;
479
480
	if ( bd ) {
		if ( bd->bd_info->bi_db_destroy ) {
481
			bd->bd_info->bi_db_destroy( bd, NULL );
482
483
484
		}
		ber_bvarray_free( bd->be_suffix );
		ber_bvarray_free( bd->be_nsuffix );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
485
486
487
488
489
490
491
492
493
		if ( !BER_BVISNULL( &bd->be_rootdn ) ) {
			free( bd->be_rootdn.bv_val );
		}
		if ( !BER_BVISNULL( &bd->be_rootndn ) ) {
			free( bd->be_rootndn.bv_val );
		}
		if ( !BER_BVISNULL( &bd->be_rootpw ) ) {
			free( bd->be_rootpw.bv_val );
		}
494
		acl_destroy( bd->be_acl, frontendDB->be_acl );
495
496
	}

497
498
499
	return 0;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
500
BackendInfo* backend_info(const char *type)
501
{
502
	BackendInfo *bi;
503

504
	/* search for the backend type */
505
506
507
	LDAP_STAILQ_FOREACH(bi,&backendInfo,bi_next) {
		if( strcasecmp(bi->bi_type, type) == 0 ) {
			return bi;
508
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
509
510
	}

511
512
513
	return NULL;
}

514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
void
backend_db_insert(
	BackendDB *be,
	int idx
)
{
	/* If idx < 0, just add to end of list */
	if ( idx < 0 ) {
		LDAP_STAILQ_INSERT_TAIL(&backendDB, be, be_next);
	} else if ( idx == 0 ) {
		LDAP_STAILQ_INSERT_HEAD(&backendDB, be, be_next);
	} else {
		int i;
		BackendDB *b2;

		b2 = LDAP_STAILQ_FIRST(&backendDB);
		idx--;
		for (i=0; i<idx; i++) {
			b2 = LDAP_STAILQ_NEXT(b2, be_next);
		}
		LDAP_STAILQ_INSERT_AFTER(&backendDB, b2, be, be_next);
	}
}

void
backend_db_move(
	BackendDB *be,
	int idx
)
{
544
	LDAP_STAILQ_REMOVE(&backendDB, be, BackendDB, be_next);
545
546
	backend_db_insert(be, idx);
}
547
548
549

BackendDB *
backend_db_init(
550
    const char	*type,
551
	BackendDB *b0,
552
	int idx,
553
	ConfigReply *cr)
554
555
{
	BackendInfo *bi = backend_info(type);
556
	BackendDB *be = b0;
557
558
559
	int	rc = 0;

	if( bi == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
560
		fprintf( stderr, "Unrecognized database type (%s)\n", type );
561
562
563
		return NULL;
	}

564
565
566
567
568
	/* If be is provided, treat it as private. Otherwise allocate
	 * one and add it to the global list.
	 */
	if ( !be ) {
		be = ch_calloc( 1, sizeof(Backend) );
569
570
571
		/* Just append */
		if ( idx >= nbackends )
			idx = -1;
572
		nbackends++;
573
		backend_db_insert( be, idx );
574
	}
575
576

	be->bd_info = bi;
577

578
579
	be->be_def_limit = frontendDB->be_def_limit;
	be->be_dfltaccess = frontendDB->be_dfltaccess;
580

581
582
583
	be->be_restrictops = frontendDB->be_restrictops;
	be->be_requires = frontendDB->be_requires;
	be->be_ssf_set = frontendDB->be_ssf_set;
584

585
586
	be->be_pcl_mutexp = &be->be_pcl_mutex;
	ldap_pvt_thread_mutex_init( be->be_pcl_mutexp );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
587

Kurt Zeilenga's avatar
Kurt Zeilenga committed
588
589
590
 	/* assign a default depth limit for alias deref */
	be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; 

591
	if ( bi->bi_db_init ) {
592
		rc = bi->bi_db_init( be, cr );
593
594
	}

595
	if ( rc != 0 ) {
596
		fprintf( stderr, "database init failed (%s)\n", type );
597
598
		/* If we created and linked this be, remove it and free it */
		if ( !b0 ) {
599
			LDAP_STAILQ_REMOVE(&backendDB, be, BackendDB, be_next);
600
601
602
603
604
605
			ch_free( be );
			be = NULL;
			nbackends--;
		}
	} else {
		bi->bi_nDB++;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
606
607
608
609
	}
	return( be );
}

610
611
612
void
be_db_close( void )
{
613
	BackendDB *be;
614

615
616
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
		if ( be->bd_info->bi_db_close ) {
617
			be->bd_info->bi_db_close( be, NULL );
618
619
		}
	}
620
621

	if ( frontendDB->bd_info->bi_db_close ) {
622
		frontendDB->bd_info->bi_db_close( frontendDB, NULL );
623
	}
624

625
626
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
627
Backend *
628
select_backend(
629
	struct berval * dn,
630
	int noSubs )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
631
{
Howard Chu's avatar
Howard Chu committed
632
	int		j;
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
633
	ber_len_t	len, dnlen = dn->bv_len;
634
	Backend		*be;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
635

636
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
637
		if ( be->be_nsuffix == NULL || SLAP_DBHIDDEN( be )) {
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
638
639
640
			continue;
		}

641
		for ( j = 0; !BER_BVISNULL( &be->be_nsuffix[j] ); j++ )
642
		{
643
			if ( ( SLAP_GLUE_SUBORDINATE( be ) ) && noSubs )
644
			{
645
			  	continue;
646
			}
647

648
			len = be->be_nsuffix[j].bv_len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
649
650

			if ( len > dnlen ) {
651
				/* suffix is longer than DN */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
652
653
				continue;
			}
654
			
655
656
657
658
			/*
			 * input DN is normalized, so the separator check
			 * need not look at escaping
			 */
659
			if ( len && len < dnlen &&
660
				!DN_SEPARATOR( dn->bv_val[(dnlen-len)-1] ))
661
			{
662
663
664
				continue;
			}

665
			if ( strcmp( be->be_nsuffix[j].bv_val,
666
667
				&dn->bv_val[dnlen-len] ) == 0 )
			{
Howard Chu's avatar
Howard Chu committed
668
				return be;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
669
670
671
672
			}
		}
	}

673
	return be;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
674
675
676
677
}

int
be_issuffix(
678
679
    Backend *be,
    struct berval *bvsuffix )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
680
681
682
{
	int	i;

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
683
684
685
686
687
	if ( be->be_nsuffix == NULL ) {
		return 0;
	}

	for ( i = 0; !BER_BVISNULL( &be->be_nsuffix[i] ); i++ ) {
688
		if ( bvmatch( &be->be_nsuffix[i], bvsuffix ) ) {
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
689
			return 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
690
691
692
		}
	}

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
693
	return 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
694
695
}

696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
int
be_issubordinate(
    Backend *be,
    struct berval *bvsubordinate )
{
	int	i;

	if ( be->be_nsuffix == NULL ) {
		return 0;
	}

	for ( i = 0; !BER_BVISNULL( &be->be_nsuffix[i] ); i++ ) {
		if ( dnIsSuffix( bvsubordinate, &be->be_nsuffix[i] ) ) {
			return 1;
		}
	}

	return 0;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
716
int
717
be_isroot_dn( Backend *be, struct berval *ndn )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
718
{
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
719
720
	if ( BER_BVISEMPTY( ndn ) || BER_BVISEMPTY( &be->be_rootndn ) ) {
		return 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
721
722
	}

723
	return dn_match( &be->be_rootndn, ndn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
724
725
}

726
727
728
int
be_slurp_update( Operation *op )
{
729
	return ( SLAP_SLURP_SHADOW( op->o_bd ) &&
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
730
		be_isupdate_dn( op->o_bd, &op->o_ndn ) );
731
732
733
734
735
}

int
be_shadow_update( Operation *op )
{
736
737
738
739
	/* This assumes that all internal ops (connid == -1) on a syncrepl
	 * database are syncrepl operations.
	 */
	return (( SLAP_SYNC_SHADOW( op->o_bd ) && op->o_connid == -1 ) ||
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
740
		( SLAP_SHADOW( op->o_bd ) && be_isupdate_dn( op->o_bd, &op->o_ndn ) ) );
741
742
743
744
}

int
be_isupdate_dn( Backend *be, struct berval *ndn )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
745
{
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
746
747
748
	if ( BER_BVISEMPTY( ndn ) || BER_BVISEMPTY( &be->be_update_ndn ) ) {
		return 0;
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
749

750
	return dn_match( &be->be_update_ndn, ndn );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
751
752
}

753
struct berval *
754
755
be_root_dn( Backend *be )
{
756
	return &be->be_rootdn;
757
758
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
759
int
760
be_isroot( Operation *op )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
761
{
762
	return be_isroot_dn( op->o_bd, &op->o_ndn );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
763
764
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
765
int
766
be_isroot_pw( Operation *op )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
767
{
768
769
	int result;

770
	if ( ! be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
771
		return 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
772
773
	}

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
774
	if ( BER_BVISEMPTY( &op->o_bd->be_rootpw ) ) {
775
776
777
		return 0;
	}

778
#ifdef SLAPD_SPASSWD
779
780
	ldap_pvt_thread_pool_setkey( op->o_threadctx, slap_sasl_bind,
		op->o_conn->c_sasl_authctx, NULL );
781
782
#endif

783
	result = lutil_passwd( &op->o_bd->be_rootpw, &op->orb_cred, NULL, NULL );
784

Kurt Zeilenga's avatar
Kurt Zeilenga committed
785
#ifdef SLAPD_SPASSWD
786
	ldap_pvt_thread_pool_setkey( op->o_threadctx, slap_sasl_bind, NULL, NULL );
787
788
789
#endif

	return result == 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
790
791
}

792
int
793
794
795
796
be_entry_release_rw(
	Operation *op,
	Entry *e,
	int rw )
797
{
798
	if ( op->o_bd->be_release ) {
799
		/* free and release entry from backend */
800
		return op->o_bd->be_release( op, e, rw );
801
802
803
804
805
806
807
	} else {
		/* free entry */
		entry_free( e );
		return 0;
	}
}

808
int
809
backend_unbind( Operation *op, SlapReply *rs )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
810
{
811
	BackendDB *be;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
812

813
814
815
816
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
		if ( be->be_unbind ) {
			op->o_bd = be;
			be->be_unbind( op, rs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
817
818
		}
	}
819
820

	return 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
821
}
822

823
824
int
backend_connection_init(
825
	Connection   *conn )
826
{
827
	BackendDB *be;
828

829
830
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
		if ( be->be_connection_init ) {
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
831
			be->be_connection_init( be, conn );
832
833
834
835
836
837
838
839
		}
	}

	return 0;
}

int
backend_connection_destroy(
840
	Connection   *conn )
841
{
842
	BackendDB *be;
843

844
845
846
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
		if ( be->be_connection_destroy ) {
			be->be_connection_destroy( be, conn);
847
848
849
850
851
852
		}
	}

	return 0;
}

853
int
854
backend_check_controls(
855
	Operation *op,
856
	SlapReply *rs )
857
{
858
	LDAPControl **ctrls = op->o_ctrls;
859
	rs->sr_err = LDAP_SUCCESS;
860

861
862
	if( ctrls ) {
		for( ; *ctrls != NULL ; ctrls++ ) {
863
			int cid;
864
865
866

			switch ( slap_global_control( op, (*ctrls)->ldctl_oid, &cid ) ) {
			case LDAP_CONTROL_NOT_FOUND:
867
868
869
				/* unrecognized control */ 
				if ( (*ctrls)->ldctl_iscritical ) {
					/* should not be reachable */ 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
870
871
					Debug( LDAP_DEBUG_ANY, "backend_check_controls: "
						"unrecognized critical control: %s\n",
872
873
						(*ctrls)->ldctl_oid, 0, 0 );
					assert( 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
874
875
876
877
				} else {
					Debug( LDAP_DEBUG_TRACE, "backend_check_controls: "
						"unrecognized non-critical control: %s\n",
						(*ctrls)->ldctl_oid, 0, 0 );
878
				}
879
				break;
880

881
			case LDAP_COMPARE_FALSE:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
882
				if ( !op->o_bd->be_ctrls[cid] && (*ctrls)->ldctl_iscritical ) {
883
884
885
886
					/* RFC 4511 allows unavailableCriticalExtension to be
					 * returned when the server is unwilling to perform
					 * an operation extended by a recognized critical
					 * control.
887
					 */
888
					rs->sr_text = "critical control unavailable in context";
889
					rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
890
891
892
893
894
					goto done;
				}
				break;

			case LDAP_COMPARE_TRUE:
895
				break;
896
897
898

			default:
				/* unreachable */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
899
900
901
902
903
				Debug( LDAP_DEBUG_ANY,
					"backend_check_controls: unable to check control: %s\n",
					(*ctrls)->ldctl_oid, 0, 0 );
				assert( 0 );

904
				rs->sr_text = "unable to check control";
905
906
				rs->sr_err = LDAP_OTHER;
				goto done;
907
			}
908
909
910
		}
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
911
#if 0 /* temporarily removed */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
912
	/* check should be generalized */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
913
	if( get_relax(op) && !be_isroot(op)) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
914
915
916
		rs->sr_text = "requires manager authorization";
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
	}
917
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
918

919
done:;
920
	return rs->sr_err;
921
922
}

923
924
925
int
backend_check_restrictions(
	Operation *op,
926
927
	SlapReply *rs,
	struct berval *opdata )
928
929
930
931
{
	slap_mask_t restrictops;
	slap_mask_t requires;
	slap_mask_t opflag;
Howard Chu's avatar
Howard Chu committed
932
	slap_mask_t exopflag = 0;
933
934
	slap_ssf_set_t *ssf;
	int updateop = 0;
935
936
	int starttls = 0;
	int session = 0;
937

938
939
940
941
942
943
944
945
946
947
948
949
	if ( op->o_bd ) {
		int	rc = SLAP_CB_CONTINUE;

		if ( op->o_bd->be_chk_controls ) {
			rc = ( *op->o_bd->be_chk_controls )( op, rs );
		}

		if ( rc == SLAP_CB_CONTINUE ) {
			rc = backend_check_controls( op, rs );
		}

		if ( rc != LDAP_SUCCESS ) {
950
			return rs->sr_err;
951
952
		}

953
954
955
		restrictops = op->o_bd->be_restrictops;
		requires = op->o_bd->be_requires;
		ssf = &op->o_bd->be_ssf_set;
956
957

	} else {
958
959
960
		restrictops = frontendDB->be_restrictops;
		requires = frontendDB->be_requires;
		ssf = &frontendDB->be_ssf_set;
961
962
963
964
965
966
967
968
969
	}

	switch( op->o_tag ) {
	case LDAP_REQ_ADD:
		opflag = SLAP_RESTRICT_OP_ADD;
		updateop++;
		break;
	case LDAP_REQ_BIND:
		opflag = SLAP_RESTRICT_OP_BIND;
970
		session++;
971
972
973
974
975
976
977
978
979
980
		break;
	case LDAP_REQ_COMPARE:
		opflag = SLAP_RESTRICT_OP_COMPARE;
		break;
	case LDAP_REQ_DELETE:
		updateop++;
		opflag = SLAP_RESTRICT_OP_DELETE;
		break;
	case LDAP_REQ_EXTENDED:
		opflag = SLAP_RESTRICT_OP_EXTENDED;
981
982
983
984
985
986
987
988

		if( !opdata ) {
			/* treat unspecified as a modify */
			opflag = SLAP_RESTRICT_OP_MODIFY;
			updateop++;
			break;
		}