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

263
264
265
266
267
268
269
270
	if ( op->o_bd == NULL ) {
		/* FIXME: happens for instance during abandon... */
		return 0;
	}

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

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

280
281
282
283
284
	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
285
			if ( rc != SLAP_CB_CONTINUE ) break;
286
287
		}
	}
Howard Chu's avatar
Howard Chu committed
288

289
	func = &oi->oi_orig->bi_op_bind;
Howard Chu's avatar
Howard Chu committed
290
	if ( func[which] && rc == SLAP_CB_CONTINUE ) {
291
		db.bd_info = oi->oi_orig;
292
293
		rc = func[which]( op, rs );
	}
Howard Chu's avatar
Howard Chu committed
294
295
	/* should not fall thru this far without anything happening... */
	if ( rc == SLAP_CB_CONTINUE ) {
296
		rc = op_rc[ which ];
Howard Chu's avatar
Howard Chu committed
297
	}
298
	op->o_bd = be;
299
	op->o_callback = cb.sc_next;
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
368
	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 );
}

369
static int
370
371
372
373
374
375
376
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 )
377
378
379
380
{
	return over_op_func( op, rs, op_aux_chk_referrals );
}

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
391
392
393
394
395
396
397
/*
 * 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.
 */

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

	return on->on_next;
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/*
 * 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;
}

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
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
470
/*
 * 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;
}

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

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

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

		/* Save a pointer to ourself in bi_private.
		 */
		oi->oi_bi.bi_private = oi;
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
		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;
516

517
518
		bi->bi_extended = over_op_extended;

519
520
521
522
523
524
		/*
		 * 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...
		 */
525
526
		bi->bi_operational = over_aux_operational;
		bi->bi_chk_referrals = over_aux_chk_referrals;
527

528
		be->bd_info = bi;
529
530

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

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

540
541
542
543
544
545
546
547
	/* 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;
548

549
550
551
552
553
554
555
	/* 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;
	}

556
557
558
	return 0;
}