backover.c 11.4 KB
Newer Older
1
2
/* backover.c - backend overlay routines */
/* $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 2003-2004 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
 * All rights reserved.
7
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
8
9
10
11
12
13
14
 * 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>.
15
16
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
17
18
/* Functions to overlay other modules over a backend. */

19
20
21
22
23
24
25
26
27
28
#include "portable.h"

#include <stdio.h>

#include <ac/string.h>
#include <ac/socket.h>

#define SLAPD_TOOLS
#include "slap.h"

29
static slap_overinst *overlays;
30
31
32
33
34
35
36
37
38

enum db_which { db_open = 0, db_close, db_destroy };

static int
over_db_func(
	BackendDB *be,
	enum db_which which
)
{
39
	slap_overinfo *oi = be->bd_info->bi_private;
40
	slap_overinst *on = oi->oi_list;
41
	BackendInfo *bi_orig = be->bd_info;
42
43
44
	BI_db_open **func;
	int rc = 0;

45
	func = &oi->oi_orig->bi_db_open;
46
	if ( func[which] ) {
47
48
		be->bd_info = oi->oi_orig;
		rc = func[which]( be );
49
50
	}

51
52
	for (; on && rc == 0; on=on->on_next) {
		be->bd_info = &on->on_bi;
53
54
		func = &on->on_bi.bi_db_open;
		if (func[which]) {
55
			rc = func[which]( be );
56
57
		}
	}
58
	be->bd_info = bi_orig;
59
60
61
62
63
64
65
66
67
68
69
70
	return rc;
}

static int
over_db_config(
	BackendDB *be,
	const char *fname,
	int lineno,
	int argc,
	char **argv
)
{
71
	slap_overinfo *oi = be->bd_info->bi_private;
72
	slap_overinst *on = oi->oi_list;
73
	BackendInfo *bi_orig = be->bd_info;
74
75
	int rc = 0;

76
77
78
	if ( oi->oi_orig->bi_db_config ) {
		be->bd_info = oi->oi_orig;
		rc = oi->oi_orig->bi_db_config( be, fname, lineno,
79
			argc, argv );
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

		if ( be->bd_info != oi->oi_orig ) {
			slap_overinfo	*oi2;
			slap_overinst	*on2, **onp;
			BackendDB	be2 = *be;
			int		i;

			/* a database added an overlay;
			 * work it around... */
			assert( overlay_is_over( be ) );
			
			oi2 = ( slap_overinfo * )be->bd_info->bi_private;
			on2 = oi2->oi_list;

			/* need to put a uniqueness check here as well;
			 * note that in principle there could be more than
			 * one overlay as a result of multiple calls to
			 * overlay_config() */
			be2.bd_info = (BackendInfo *)oi;

			for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
				if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
					Debug( LDAP_DEBUG_ANY, "over_db_config(): "
							"warning, freshly added "
							"overlay #%d \"%s\" is already in list\n",
							i, (*onp)->on_bi.bi_type, 0 );

					/* NOTE: if the overlay already exists,
					 * there is no way to merge the results
					 * of the configuration that may have 
					 * occurred during bi_db_config(); we
					 * just issue a warning, and the 
					 * administrator should deal with this */
				}
			}
			*onp = oi->oi_list;

			oi->oi_list = on2;

			ch_free( be->bd_info );
		}

122
		be->bd_info = (BackendInfo *)oi;
123
		if ( rc != SLAP_CONF_UNKNOWN ) return rc;
124
125
126
127
	}

	for (; on; on=on->on_next) {
		if (on->on_bi.bi_db_config) {
128
129
			be->bd_info = &on->on_bi;
			rc = on->on_bi.bi_db_config( be, fname, lineno,
130
				argc, argv );
131
			if ( rc != SLAP_CONF_UNKNOWN ) break;
132
133
		}
	}
134
	be->bd_info = bi_orig;
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
	return rc;
}

static int
over_db_open(
	BackendDB *be
)
{
	return over_db_func( be, db_open );
}

static int
over_db_close(
	BackendDB *be
)
{
151
152
153
154
155
156
157
158
159
160
161
162
	slap_overinfo *oi = be->bd_info->bi_private;
	slap_overinst *on = oi->oi_list;
	BackendInfo *bi_orig = be->bd_info;
	int rc = 0;

	for (; on && rc == 0; on=on->on_next) {
		be->bd_info = &on->on_bi;
		if ( be->bd_info->bi_db_close ) {
			rc = be->bd_info->bi_db_close( be );
		}
	}

Howard Chu's avatar
Howard Chu committed
163
	if ( oi->oi_orig->bi_db_close ) {
164
165
166
167
168
169
		be->bd_info = oi->oi_orig;
		rc = be->bd_info->bi_db_close( be );
	}

	be->bd_info = bi_orig;
	return rc;
170
171
172
173
174
175
176
}

static int
over_db_destroy(
	BackendDB *be
)
{
177
	slap_overinfo *oi = be->bd_info->bi_private;
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
	slap_overinst *on = oi->oi_list, *next;
	int rc;

	rc = over_db_func( be, db_destroy );

	for (next = on->on_next; on; on=next) {
		next = on->on_next;
		free( on );
	}
	free( oi );
	return rc;
}

static int
over_back_response ( Operation *op, SlapReply *rs )
{
194
	slap_overinfo *oi = op->o_callback->sc_private;
195
	slap_overinst *on = oi->oi_list;
196
	int rc = SLAP_CB_CONTINUE;
197
198
	BackendDB *be = op->o_bd, db = *op->o_bd;

Howard Chu's avatar
Howard Chu committed
199
	db.be_flags |= SLAP_DBFLAG_OVERLAY;
200
201
202
203
204
	op->o_bd = &db;
	for (; on; on=on->on_next ) {
		if ( on->on_response ) {
			db.bd_info = (BackendInfo *)on;
			rc = on->on_response( op, rs );
205
			if ( rc != SLAP_CB_CONTINUE ) break;
206
207
208
209
210
211
		}
	}
	op->o_bd = be;
	return rc;
}

212
213
214
215
216
217
218
219
220
221
222
223
enum op_which {
	op_bind = 0,
	op_unbind,
	op_search,
	op_compare,
	op_modify,
	op_modrdn,
	op_add,
	op_delete,
	op_abandon,
	op_cancel,
	op_extended,
224
	op_aux_operational,
225
226
227
	op_aux_chk_referrals,
	op_last
};
228

229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/*
 * default return code in case of missing backend function
 * and overlay stack returning SLAP_CB_CONTINUE
 */
static int op_rc[] = {
	LDAP_UNWILLING_TO_PERFORM,	/* bind */
	LDAP_UNWILLING_TO_PERFORM,	/* unbind */
	LDAP_UNWILLING_TO_PERFORM,	/* search */
	LDAP_UNWILLING_TO_PERFORM,	/* compare */
	LDAP_UNWILLING_TO_PERFORM,	/* modify */
	LDAP_UNWILLING_TO_PERFORM,	/* modrdn */
	LDAP_UNWILLING_TO_PERFORM,	/* add */
	LDAP_UNWILLING_TO_PERFORM,	/* delete */
	LDAP_UNWILLING_TO_PERFORM,	/* abandon */
	LDAP_UNWILLING_TO_PERFORM,	/* cancel */
	LDAP_UNWILLING_TO_PERFORM,	/* extended */
245
	LDAP_SUCCESS,			/* aux_operational */
246
247
248
	LDAP_SUCCESS			/* aux_chk_referrals */
};

249
250
251
252
253
254
255
static int
over_op_func(
	Operation *op,
	SlapReply *rs,
	enum op_which which
)
{
256
257
	slap_overinfo *oi;
	slap_overinst *on;
258
	BI_op_bind **func;
259
	BackendDB *be = op->o_bd, db;
260
	slap_callback cb = {NULL, over_back_response, NULL, NULL};
Howard Chu's avatar
Howard Chu committed
261
	int rc = SLAP_CB_CONTINUE;
262

Pierangelo Masarati's avatar
Pierangelo Masarati committed
263
264
265
	/* FIXME: used to happen for instance during abandon
	 * when global overlays are used... */
	assert( op->o_bd != NULL );
266
267
268
269

	oi = op->o_bd->bd_info->bi_private;
	on = oi->oi_list;

270
271
272
273
274
 	if ( !SLAP_ISOVERLAY( op->o_bd )) {
 		db = *op->o_bd;
		db.be_flags |= SLAP_DBFLAG_OVERLAY;
		op->o_bd = &db;
	}
275
	cb.sc_next = op->o_callback;
276
	cb.sc_private = oi;
Howard Chu's avatar
Howard Chu committed
277
278
	op->o_callback = &cb;

279
280
281
282
283
	for (; on; on=on->on_next ) {
		func = &on->on_bi.bi_op_bind;
		if ( func[which] ) {
			db.bd_info = (BackendInfo *)on;
			rc = func[which]( op, rs );
Howard Chu's avatar
Howard Chu committed
284
			if ( rc != SLAP_CB_CONTINUE ) break;
285
286
		}
	}
Howard Chu's avatar
Howard Chu committed
287

288
	func = &oi->oi_orig->bi_op_bind;
Howard Chu's avatar
Howard Chu committed
289
	if ( func[which] && rc == SLAP_CB_CONTINUE ) {
290
		db.bd_info = oi->oi_orig;
291
292
		rc = func[which]( op, rs );
	}
Howard Chu's avatar
Howard Chu committed
293
294
	/* should not fall thru this far without anything happening... */
	if ( rc == SLAP_CB_CONTINUE ) {
295
		rc = op_rc[ which ];
Howard Chu's avatar
Howard Chu committed
296
	}
297
	op->o_bd = be;
298
	op->o_callback = cb.sc_next;
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
	return rc;
}

static int
over_op_bind( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_bind );
}

static int
over_op_unbind( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_unbind );
}

static int
over_op_search( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_search );
}

static int
over_op_compare( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_compare );
}

static int
over_op_modify( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_modify );
}

static int
over_op_modrdn( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_modrdn );
}

static int
over_op_add( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_add );
}

static int
over_op_delete( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_delete );
}

static int
over_op_abandon( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_abandon );
}

static int
over_op_cancel( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_cancel );
}

static int
over_op_extended( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_extended );
}

368
static int
369
370
371
372
373
374
375
over_aux_operational( Operation *op, SlapReply *rs )
{
	return over_op_func( op, rs, op_aux_operational );
}

static int
over_aux_chk_referrals( Operation *op, SlapReply *rs )
376
377
378
379
{
	return over_op_func( op, rs, op_aux_chk_referrals );
}

380
381
382
383
384
385
386
387
388
389
int
overlay_register(
	slap_overinst *on
)
{
	on->on_next = overlays;
	overlays = on;
	return 0;
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
390
391
392
393
394
395
396
/*
 * iterator on registered overlays; overlay_next( NULL ) returns the first
 * overlay; * subsequent calls with the previously returned value allow to 
 * iterate * over the entire list; returns NULL when no more overlays are 
 * registered.
 */

397
398
399
400
401
402
403
404
405
406
407
408
slap_overinst *
overlay_next(
	slap_overinst *on
)
{
	if ( on == NULL ) {
		return overlays;
	}

	return on->on_next;
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
/*
 * returns a specific registered overlay based on the type; NULL if not
 * registered.
 */

slap_overinst *
overlay_find( const char *over_type )
{
	slap_overinst *on = overlays;

	assert( over_type );

	for ( ; on; on = on->on_next ) {
		if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
			break;
		}
	}

	return on;
}

430
431
static const char overtype[] = "over";

Pierangelo Masarati's avatar
Pierangelo Masarati committed
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
/*
 * returns TRUE (1) if the database is actually an overlay instance;
 * FALSE (0) otherwise.
 */

int
overlay_is_over( BackendDB *be )
{
	return be->bd_info->bi_type == overtype;
}

/*
 * returns TRUE (1) if the given database is actually an overlay
 * instance and, somewhere in the list, contains the requested overlay;
 * FALSE (0) otherwise.
 */

int
overlay_is_inst( BackendDB *be, const char *over_type )
{
	slap_overinst	*on;

	assert( be );

	if ( !overlay_is_over( be ) ) {
		return 0;
	}
	
	on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
	for ( ; on; on = on->on_next ) {
		if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
			return 1;
		}
	}

	return 0;
}

470
471
472
473
/* add an overlay to a particular backend. */
int
overlay_config( BackendDB *be, const char *ov )
{
474
	slap_overinst *on = NULL, *on2 = NULL;
475
476
	slap_overinfo *oi = NULL;
	BackendInfo *bi = NULL;
477

Pierangelo Masarati's avatar
Pierangelo Masarati committed
478
	on = overlay_find( ov );
479
480
	if ( !on ) {
		Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
481
482
483
		return 1;
	}

484
485
486
	/* If this is the first overlay on this backend, set up the
	 * overlay info structure
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
487
	if ( !overlay_is_over( be ) ) {
488
		oi = ch_malloc( sizeof( slap_overinfo ) );
489
		oi->oi_orig = be->bd_info;
490
		oi->oi_bi = *be->bd_info;
491
492
493
494

		/* Save a pointer to ourself in bi_private.
		 */
		oi->oi_bi.bi_private = oi;
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
		oi->oi_list = NULL;
		bi = (BackendInfo *)oi;

		bi->bi_type = (char *)overtype;

		bi->bi_db_config = over_db_config;
		bi->bi_db_open = over_db_open;
		bi->bi_db_close = over_db_close;
		bi->bi_db_destroy = over_db_destroy;

		bi->bi_op_bind = over_op_bind;
		bi->bi_op_unbind = over_op_unbind;
		bi->bi_op_search = over_op_search;
		bi->bi_op_compare = over_op_compare;
		bi->bi_op_modify = over_op_modify;
		bi->bi_op_modrdn = over_op_modrdn;
		bi->bi_op_add = over_op_add;
		bi->bi_op_delete = over_op_delete;
		bi->bi_op_abandon = over_op_abandon;
		bi->bi_op_cancel = over_op_cancel;
515

516
517
		bi->bi_extended = over_op_extended;

518
519
520
521
522
523
		/*
		 * this is fine because it has the same
		 * args of the operations; we need to rework
		 * all the hooks to share the same args
		 * of the operations...
		 */
524
525
		bi->bi_operational = over_aux_operational;
		bi->bi_chk_referrals = over_aux_chk_referrals;
526

527
		be->bd_info = bi;
528
529

	} else {
530
531
532
533
534
535
		if ( overlay_is_inst( be, ov ) ) {
			Debug( LDAP_DEBUG_ANY, "overlay_config(): "
					"warning, overlay \"%s\" "
					"already in list\n", ov, 0, 0 );
		}

536
		oi = be->bd_info->bi_private;
537
538
	}

539
540
541
542
543
544
545
546
	/* Insert new overlay on head of list. Overlays are executed
	 * in reverse of config order...
	 */
	on2 = ch_calloc( 1, sizeof(slap_overinst) );
	*on2 = *on;
	on2->on_info = oi;
	on2->on_next = oi->oi_list;
	oi->oi_list = on2;
547

548
549
550
551
552
553
554
	/* Any initialization needed? */
	if ( on->on_bi.bi_db_init ) {
		be->bd_info = (BackendInfo *)on2;
		on2->on_bi.bi_db_init( be );
		be->bd_info = (BackendInfo *)oi;
	}

555
556
557
	return 0;
}