1/*	$NetBSD: backover.c,v 1.1.1.4 2010/12/12 15:22:19 adam Exp $	*/
2
3/* backover.c - backend overlay routines */
4/* OpenLDAP: pkg/ldap/servers/slapd/backover.c,v 1.71.2.21 2010/04/13 20:23:11 kurt Exp */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2003-2010 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18
19/* Functions to overlay other modules over a backend. */
20
21#include "portable.h"
22
23#include <stdio.h>
24
25#include <ac/string.h>
26#include <ac/socket.h>
27
28#define SLAPD_TOOLS
29#include "slap.h"
30#include "config.h"
31
32static slap_overinst *overlays;
33
34static int
35over_db_config(
36	BackendDB *be,
37	const char *fname,
38	int lineno,
39	int argc,
40	char **argv
41)
42{
43	slap_overinfo *oi = be->bd_info->bi_private;
44	slap_overinst *on = oi->oi_list;
45	BackendInfo *bi_orig = be->bd_info;
46	struct ConfigOCs *be_cf_ocs = be->be_cf_ocs;
47	ConfigArgs ca = {0};
48	int rc = 0;
49
50	if ( oi->oi_orig->bi_db_config ) {
51		be->bd_info = oi->oi_orig;
52		be->be_cf_ocs = oi->oi_orig->bi_cf_ocs;
53		rc = oi->oi_orig->bi_db_config( be, fname, lineno,
54			argc, argv );
55
56		if ( be->bd_info != oi->oi_orig ) {
57			slap_overinfo	*oi2;
58			slap_overinst	*on2, **onp;
59			BackendDB	be2 = *be;
60			int		i;
61
62			/* a database added an overlay;
63			 * work it around... */
64			assert( overlay_is_over( be ) );
65
66			oi2 = ( slap_overinfo * )be->bd_info->bi_private;
67			on2 = oi2->oi_list;
68
69			/* need to put a uniqueness check here as well;
70			 * note that in principle there could be more than
71			 * one overlay as a result of multiple calls to
72			 * overlay_config() */
73			be2.bd_info = (BackendInfo *)oi;
74
75			for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
76				if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
77					Debug( LDAP_DEBUG_ANY, "over_db_config(): "
78							"warning, freshly added "
79							"overlay #%d \"%s\" is already in list\n",
80							i, (*onp)->on_bi.bi_type, 0 );
81
82					/* NOTE: if the overlay already exists,
83					 * there is no way to merge the results
84					 * of the configuration that may have
85					 * occurred during bi_db_config(); we
86					 * just issue a warning, and the
87					 * administrator should deal with this */
88				}
89			}
90			*onp = oi->oi_list;
91
92			oi->oi_list = on2;
93
94			ch_free( be->bd_info );
95		}
96
97		be->bd_info = (BackendInfo *)oi;
98		if ( rc != SLAP_CONF_UNKNOWN ) return rc;
99	}
100
101	ca.argv = argv;
102	ca.argc = argc;
103	ca.fname = fname;
104	ca.lineno = lineno;
105	ca.be = be;
106	snprintf( ca.log, sizeof( ca.log ), "%s: line %d",
107			ca.fname, ca.lineno );
108	ca.op = SLAP_CONFIG_ADD;
109	ca.valx = -1;
110
111	for (; on; on=on->on_next) {
112		rc = SLAP_CONF_UNKNOWN;
113		if (on->on_bi.bi_cf_ocs) {
114			ConfigTable *ct;
115			ca.bi = &on->on_bi;
116			ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca );
117			if ( ct ) {
118				ca.table = on->on_bi.bi_cf_ocs->co_type;
119				rc = config_add_vals( ct, &ca );
120				if ( rc != SLAP_CONF_UNKNOWN )
121					break;
122			}
123		}
124		if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) {
125			be->bd_info = &on->on_bi;
126			rc = on->on_bi.bi_db_config( be, fname, lineno,
127				argc, argv );
128			if ( rc != SLAP_CONF_UNKNOWN ) break;
129		}
130	}
131	be->bd_info = bi_orig;
132	be->be_cf_ocs = be_cf_ocs;
133
134	return rc;
135}
136
137static int
138over_db_open(
139	BackendDB *be,
140	ConfigReply *cr
141)
142{
143	slap_overinfo *oi = be->bd_info->bi_private;
144	slap_overinst *on = oi->oi_list;
145	BackendDB db = *be;
146	int rc = 0;
147
148	db.be_flags |= SLAP_DBFLAG_OVERLAY;
149	db.bd_info = oi->oi_orig;
150	if ( db.bd_info->bi_db_open ) {
151		rc = db.bd_info->bi_db_open( &db, cr );
152	}
153
154	for (; on && rc == 0; on=on->on_next) {
155		db.bd_info = &on->on_bi;
156		if ( db.bd_info->bi_db_open ) {
157			rc = db.bd_info->bi_db_open( &db, cr );
158		}
159	}
160
161	return rc;
162}
163
164static int
165over_db_close(
166	BackendDB *be,
167	ConfigReply *cr
168)
169{
170	slap_overinfo *oi = be->bd_info->bi_private;
171	slap_overinst *on = oi->oi_list;
172	BackendInfo *bi_orig = be->bd_info;
173	int rc = 0;
174
175	for (; on && rc == 0; on=on->on_next) {
176		be->bd_info = &on->on_bi;
177		if ( be->bd_info->bi_db_close ) {
178			rc = be->bd_info->bi_db_close( be, cr );
179		}
180	}
181
182	if ( oi->oi_orig->bi_db_close ) {
183		be->bd_info = oi->oi_orig;
184		rc = be->bd_info->bi_db_close( be, cr );
185	}
186
187	be->bd_info = bi_orig;
188	return rc;
189}
190
191static int
192over_db_destroy(
193	BackendDB *be,
194	ConfigReply *cr
195)
196{
197	slap_overinfo *oi = be->bd_info->bi_private;
198	slap_overinst *on = oi->oi_list, *next;
199	BackendInfo *bi_orig = be->bd_info;
200	int rc = 0;
201
202	be->bd_info = oi->oi_orig;
203	if ( be->bd_info->bi_db_destroy ) {
204		rc = be->bd_info->bi_db_destroy( be, cr );
205	}
206
207	for (; on && rc == 0; on=on->on_next) {
208		be->bd_info = &on->on_bi;
209		if ( be->bd_info->bi_db_destroy ) {
210			rc = be->bd_info->bi_db_destroy( be, cr );
211		}
212	}
213
214	on = oi->oi_list;
215	if ( on ) {
216		for (next = on->on_next; on; on=next) {
217			next = on->on_next;
218			free( on );
219		}
220	}
221	be->bd_info = bi_orig;
222	free( oi );
223	return rc;
224}
225
226static int
227over_back_response ( Operation *op, SlapReply *rs )
228{
229	slap_overinfo *oi = op->o_callback->sc_private;
230	slap_overinst *on = oi->oi_list;
231	int rc = SLAP_CB_CONTINUE;
232	BackendDB *be = op->o_bd, db = *op->o_bd;
233
234	db.be_flags |= SLAP_DBFLAG_OVERLAY;
235	op->o_bd = &db;
236	for (; on; on=on->on_next ) {
237		if ( on->on_response ) {
238			db.bd_info = (BackendInfo *)on;
239			rc = on->on_response( op, rs );
240			if ( rc != SLAP_CB_CONTINUE ) break;
241		}
242	}
243	/* Bypass the remaining on_response layers, but allow
244	 * normal execution to continue.
245	 */
246	if ( rc == SLAP_CB_BYPASS )
247		rc = SLAP_CB_CONTINUE;
248	op->o_bd = be;
249	return rc;
250}
251
252static int
253over_access_allowed(
254	Operation		*op,
255	Entry			*e,
256	AttributeDescription	*desc,
257	struct berval		*val,
258	slap_access_t		access,
259	AccessControlState	*state,
260	slap_mask_t		*maskp )
261{
262	slap_overinfo *oi;
263	slap_overinst *on;
264	BackendInfo *bi;
265	BackendDB *be = op->o_bd, db;
266	int rc = SLAP_CB_CONTINUE;
267
268	/* FIXME: used to happen for instance during abandon
269	 * when global overlays are used... */
270	assert( op->o_bd != NULL );
271
272	bi = op->o_bd->bd_info;
273	/* Were we invoked on the frontend? */
274	if ( !bi->bi_access_allowed ) {
275		oi = frontendDB->bd_info->bi_private;
276	} else {
277		oi = op->o_bd->bd_info->bi_private;
278	}
279	on = oi->oi_list;
280
281	for ( ; on; on = on->on_next ) {
282		if ( on->on_bi.bi_access_allowed ) {
283			/* NOTE: do not copy the structure until required */
284		 	if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
285 				db = *op->o_bd;
286				db.be_flags |= SLAP_DBFLAG_OVERLAY;
287				op->o_bd = &db;
288			}
289
290			op->o_bd->bd_info = (BackendInfo *)on;
291			rc = on->on_bi.bi_access_allowed( op, e,
292				desc, val, access, state, maskp );
293			if ( rc != SLAP_CB_CONTINUE ) break;
294		}
295	}
296
297	if ( rc == SLAP_CB_CONTINUE ) {
298		BI_access_allowed	*bi_access_allowed;
299
300		/* if the database structure was changed, o_bd points to a
301		 * copy of the structure; put the original bd_info in place */
302		if ( SLAP_ISOVERLAY( op->o_bd ) ) {
303			op->o_bd->bd_info = oi->oi_orig;
304		}
305
306		if ( oi->oi_orig->bi_access_allowed ) {
307			bi_access_allowed = oi->oi_orig->bi_access_allowed;
308		} else {
309			bi_access_allowed = slap_access_allowed;
310		}
311
312		rc = bi_access_allowed( op, e,
313			desc, val, access, state, maskp );
314	}
315	/* should not fall thru this far without anything happening... */
316	if ( rc == SLAP_CB_CONTINUE ) {
317		/* access not allowed */
318		rc = 0;
319	}
320
321	op->o_bd = be;
322	op->o_bd->bd_info = bi;
323
324	return rc;
325}
326
327int
328overlay_entry_get_ov(
329	Operation		*op,
330	struct berval	*dn,
331	ObjectClass		*oc,
332	AttributeDescription	*ad,
333	int	rw,
334	Entry	**e,
335	slap_overinst *on )
336{
337	slap_overinfo *oi = on->on_info;
338	BackendDB *be = op->o_bd, db;
339	BackendInfo *bi = op->o_bd->bd_info;
340	int rc = SLAP_CB_CONTINUE;
341
342	for ( ; on; on = on->on_next ) {
343		if ( on->on_bi.bi_entry_get_rw ) {
344			/* NOTE: do not copy the structure until required */
345		 	if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
346 				db = *op->o_bd;
347				db.be_flags |= SLAP_DBFLAG_OVERLAY;
348				op->o_bd = &db;
349			}
350
351			op->o_bd->bd_info = (BackendInfo *)on;
352			rc = on->on_bi.bi_entry_get_rw( op, dn,
353				oc, ad, rw, e );
354			if ( rc != SLAP_CB_CONTINUE ) break;
355		}
356	}
357
358	if ( rc == SLAP_CB_CONTINUE ) {
359		/* if the database structure was changed, o_bd points to a
360		 * copy of the structure; put the original bd_info in place */
361		if ( SLAP_ISOVERLAY( op->o_bd ) ) {
362			op->o_bd->bd_info = oi->oi_orig;
363		}
364
365		if ( oi->oi_orig->bi_entry_get_rw ) {
366			rc = oi->oi_orig->bi_entry_get_rw( op, dn,
367				oc, ad, rw, e );
368		}
369	}
370	/* should not fall thru this far without anything happening... */
371	if ( rc == SLAP_CB_CONTINUE ) {
372		rc = LDAP_UNWILLING_TO_PERFORM;
373	}
374
375	op->o_bd = be;
376	op->o_bd->bd_info = bi;
377
378	return rc;
379}
380
381static int
382over_entry_get_rw(
383	Operation		*op,
384	struct berval	*dn,
385	ObjectClass		*oc,
386	AttributeDescription	*ad,
387	int	rw,
388	Entry	**e )
389{
390	slap_overinfo *oi;
391	slap_overinst *on;
392
393	assert( op->o_bd != NULL );
394
395	oi = op->o_bd->bd_info->bi_private;
396	on = oi->oi_list;
397
398	return overlay_entry_get_ov( op, dn, oc, ad, rw, e, on );
399}
400
401int
402overlay_entry_release_ov(
403	Operation	*op,
404	Entry	*e,
405	int rw,
406	slap_overinst *on )
407{
408	slap_overinfo *oi = on->on_info;
409	BackendDB *be = op->o_bd, db;
410	BackendInfo *bi = op->o_bd->bd_info;
411	int rc = SLAP_CB_CONTINUE;
412
413	for ( ; on; on = on->on_next ) {
414		if ( on->on_bi.bi_entry_release_rw ) {
415			/* NOTE: do not copy the structure until required */
416		 	if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
417 				db = *op->o_bd;
418				db.be_flags |= SLAP_DBFLAG_OVERLAY;
419				op->o_bd = &db;
420			}
421
422			op->o_bd->bd_info = (BackendInfo *)on;
423			rc = on->on_bi.bi_entry_release_rw( op, e, rw );
424			if ( rc != SLAP_CB_CONTINUE ) break;
425		}
426	}
427
428	if ( rc == SLAP_CB_CONTINUE ) {
429		/* if the database structure was changed, o_bd points to a
430		 * copy of the structure; put the original bd_info in place */
431		if ( SLAP_ISOVERLAY( op->o_bd ) ) {
432			op->o_bd->bd_info = oi->oi_orig;
433		}
434
435		if ( oi->oi_orig->bi_entry_release_rw ) {
436			rc = oi->oi_orig->bi_entry_release_rw( op, e, rw );
437		}
438	}
439	/* should not fall thru this far without anything happening... */
440	if ( rc == SLAP_CB_CONTINUE ) {
441		entry_free( e );
442		rc = 0;
443	}
444
445	op->o_bd = be;
446	op->o_bd->bd_info = bi;
447
448	return rc;
449}
450
451static int
452over_entry_release_rw(
453	Operation	*op,
454	Entry	*e,
455	int rw )
456{
457	slap_overinfo *oi;
458	slap_overinst *on;
459
460	assert( op->o_bd != NULL );
461
462	oi = op->o_bd->bd_info->bi_private;
463	on = oi->oi_list;
464
465	return overlay_entry_release_ov( op, e, rw, on );
466}
467
468static int
469over_acl_group(
470	Operation		*op,
471	Entry			*e,
472	struct berval		*gr_ndn,
473	struct berval		*op_ndn,
474	ObjectClass		*group_oc,
475	AttributeDescription	*group_at )
476{
477	slap_overinfo *oi;
478	slap_overinst *on;
479	BackendInfo *bi = op->o_bd->bd_info;
480	BackendDB *be = op->o_bd, db;
481	int rc = SLAP_CB_CONTINUE;
482
483	/* FIXME: used to happen for instance during abandon
484	 * when global overlays are used... */
485	assert( op->o_bd != NULL );
486
487	oi = op->o_bd->bd_info->bi_private;
488	on = oi->oi_list;
489
490	for ( ; on; on = on->on_next ) {
491		if ( on->on_bi.bi_acl_group ) {
492			/* NOTE: do not copy the structure until required */
493		 	if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
494 				db = *op->o_bd;
495				db.be_flags |= SLAP_DBFLAG_OVERLAY;
496				op->o_bd = &db;
497			}
498
499			op->o_bd->bd_info = (BackendInfo *)on;
500			rc = on->on_bi.bi_acl_group( op, e,
501				gr_ndn, op_ndn, group_oc, group_at );
502			if ( rc != SLAP_CB_CONTINUE ) break;
503		}
504	}
505
506	if ( rc == SLAP_CB_CONTINUE ) {
507		BI_acl_group		*bi_acl_group;
508
509		/* if the database structure was changed, o_bd points to a
510		 * copy of the structure; put the original bd_info in place */
511		if ( SLAP_ISOVERLAY( op->o_bd ) ) {
512			op->o_bd->bd_info = oi->oi_orig;
513		}
514
515		if ( oi->oi_orig->bi_acl_group ) {
516			bi_acl_group = oi->oi_orig->bi_acl_group;
517		} else {
518			bi_acl_group = backend_group;
519		}
520
521		rc = bi_acl_group( op, e,
522			gr_ndn, op_ndn, group_oc, group_at );
523	}
524	/* should not fall thru this far without anything happening... */
525	if ( rc == SLAP_CB_CONTINUE ) {
526		/* access not allowed */
527		rc = 0;
528	}
529
530	op->o_bd = be;
531	op->o_bd->bd_info = bi;
532
533	return rc;
534}
535
536static int
537over_acl_attribute(
538	Operation		*op,
539	Entry			*target,
540	struct berval		*entry_ndn,
541	AttributeDescription	*entry_at,
542	BerVarray		*vals,
543	slap_access_t		access )
544{
545	slap_overinfo *oi;
546	slap_overinst *on;
547	BackendInfo *bi = op->o_bd->bd_info;
548	BackendDB *be = op->o_bd, db;
549	int rc = SLAP_CB_CONTINUE;
550
551	/* FIXME: used to happen for instance during abandon
552	 * when global overlays are used... */
553	assert( op->o_bd != NULL );
554
555	oi = op->o_bd->bd_info->bi_private;
556	on = oi->oi_list;
557
558	for ( ; on; on = on->on_next ) {
559		if ( on->on_bi.bi_acl_attribute ) {
560			/* NOTE: do not copy the structure until required */
561		 	if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
562 				db = *op->o_bd;
563				db.be_flags |= SLAP_DBFLAG_OVERLAY;
564				op->o_bd = &db;
565			}
566
567			op->o_bd->bd_info = (BackendInfo *)on;
568			rc = on->on_bi.bi_acl_attribute( op, target,
569				entry_ndn, entry_at, vals, access );
570			if ( rc != SLAP_CB_CONTINUE ) break;
571		}
572	}
573
574	if ( rc == SLAP_CB_CONTINUE ) {
575		BI_acl_attribute		*bi_acl_attribute;
576
577		/* if the database structure was changed, o_bd points to a
578		 * copy of the structure; put the original bd_info in place */
579		if ( SLAP_ISOVERLAY( op->o_bd ) ) {
580			op->o_bd->bd_info = oi->oi_orig;
581		}
582
583		if ( oi->oi_orig->bi_acl_attribute ) {
584			bi_acl_attribute = oi->oi_orig->bi_acl_attribute;
585		} else {
586			bi_acl_attribute = backend_attribute;
587		}
588
589		rc = bi_acl_attribute( op, target,
590			entry_ndn, entry_at, vals, access );
591	}
592	/* should not fall thru this far without anything happening... */
593	if ( rc == SLAP_CB_CONTINUE ) {
594		/* access not allowed */
595		rc = 0;
596	}
597
598	op->o_bd = be;
599	op->o_bd->bd_info = bi;
600
601	return rc;
602}
603
604int
605overlay_callback_after_backover( Operation *op, slap_callback *sc, int append )
606{
607	slap_callback **scp;
608
609	for ( scp = &op->o_callback; *scp != NULL; scp = &(*scp)->sc_next ) {
610		if ( (*scp)->sc_response == over_back_response ) {
611			sc->sc_next = (*scp)->sc_next;
612			(*scp)->sc_next = sc;
613			return 0;
614		}
615	}
616
617	if ( append ) {
618		*scp = sc;
619		return 0;
620	}
621
622	return 1;
623}
624
625/*
626 * default return code in case of missing backend function
627 * and overlay stack returning SLAP_CB_CONTINUE
628 */
629static int op_rc[ op_last ] = {
630	LDAP_UNWILLING_TO_PERFORM,	/* bind */
631	LDAP_UNWILLING_TO_PERFORM,	/* unbind */
632	LDAP_UNWILLING_TO_PERFORM,	/* search */
633	SLAP_CB_CONTINUE,		/* compare; pass to frontend */
634	LDAP_UNWILLING_TO_PERFORM,	/* modify */
635	LDAP_UNWILLING_TO_PERFORM,	/* modrdn */
636	LDAP_UNWILLING_TO_PERFORM,	/* add */
637	LDAP_UNWILLING_TO_PERFORM,	/* delete */
638	LDAP_UNWILLING_TO_PERFORM,	/* abandon */
639	LDAP_UNWILLING_TO_PERFORM,	/* cancel */
640	LDAP_UNWILLING_TO_PERFORM,	/* extended */
641	LDAP_SUCCESS,			/* aux_operational */
642	LDAP_SUCCESS,			/* aux_chk_referrals */
643	SLAP_CB_CONTINUE		/* aux_chk_controls; pass to frontend */
644};
645
646int overlay_op_walk(
647	Operation *op,
648	SlapReply *rs,
649	slap_operation_t which,
650	slap_overinfo *oi,
651	slap_overinst *on
652)
653{
654	BI_op_bind **func;
655	int rc = SLAP_CB_CONTINUE;
656
657	for (; on; on=on->on_next ) {
658		func = &on->on_bi.bi_op_bind;
659		if ( func[which] ) {
660			op->o_bd->bd_info = (BackendInfo *)on;
661			rc = func[which]( op, rs );
662			if ( rc != SLAP_CB_CONTINUE ) break;
663		}
664	}
665	if ( rc == SLAP_CB_BYPASS )
666		rc = SLAP_CB_CONTINUE;
667
668	func = &oi->oi_orig->bi_op_bind;
669	if ( func[which] && rc == SLAP_CB_CONTINUE ) {
670		op->o_bd->bd_info = oi->oi_orig;
671		rc = func[which]( op, rs );
672	}
673	/* should not fall thru this far without anything happening... */
674	if ( rc == SLAP_CB_CONTINUE ) {
675		rc = op_rc[ which ];
676	}
677
678	/* The underlying backend didn't handle the request, make sure
679	 * overlay cleanup is processed.
680	 */
681	if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
682		slap_callback *sc_next;
683		for ( ; op->o_callback && op->o_callback->sc_response !=
684			over_back_response; op->o_callback = sc_next ) {
685			sc_next = op->o_callback->sc_next;
686			if ( op->o_callback->sc_cleanup ) {
687				op->o_callback->sc_cleanup( op, rs );
688			}
689		}
690	}
691	return rc;
692}
693
694static int
695over_op_func(
696	Operation *op,
697	SlapReply *rs,
698	slap_operation_t which
699)
700{
701	slap_overinfo *oi;
702	slap_overinst *on;
703	BackendDB *be = op->o_bd, db;
704	slap_callback cb = {NULL, over_back_response, NULL, NULL}, **sc;
705	int rc = SLAP_CB_CONTINUE;
706
707	/* FIXME: used to happen for instance during abandon
708	 * when global overlays are used... */
709	assert( op->o_bd != NULL );
710
711	oi = op->o_bd->bd_info->bi_private;
712	on = oi->oi_list;
713
714 	if ( !SLAP_ISOVERLAY( op->o_bd )) {
715 		db = *op->o_bd;
716		db.be_flags |= SLAP_DBFLAG_OVERLAY;
717		op->o_bd = &db;
718	}
719	cb.sc_next = op->o_callback;
720	cb.sc_private = oi;
721	op->o_callback = &cb;
722
723	rc = overlay_op_walk( op, rs, which, oi, on );
724	for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) {
725		if ( *sc == &cb ) {
726			*sc = cb.sc_next;
727			break;
728		}
729	}
730
731	op->o_bd = be;
732	return rc;
733}
734
735static int
736over_op_bind( Operation *op, SlapReply *rs )
737{
738	return over_op_func( op, rs, op_bind );
739}
740
741static int
742over_op_unbind( Operation *op, SlapReply *rs )
743{
744	return over_op_func( op, rs, op_unbind );
745}
746
747static int
748over_op_search( Operation *op, SlapReply *rs )
749{
750	return over_op_func( op, rs, op_search );
751}
752
753static int
754over_op_compare( Operation *op, SlapReply *rs )
755{
756	return over_op_func( op, rs, op_compare );
757}
758
759static int
760over_op_modify( Operation *op, SlapReply *rs )
761{
762	return over_op_func( op, rs, op_modify );
763}
764
765static int
766over_op_modrdn( Operation *op, SlapReply *rs )
767{
768	return over_op_func( op, rs, op_modrdn );
769}
770
771static int
772over_op_add( Operation *op, SlapReply *rs )
773{
774	return over_op_func( op, rs, op_add );
775}
776
777static int
778over_op_delete( Operation *op, SlapReply *rs )
779{
780	return over_op_func( op, rs, op_delete );
781}
782
783static int
784over_op_abandon( Operation *op, SlapReply *rs )
785{
786	return over_op_func( op, rs, op_abandon );
787}
788
789static int
790over_op_cancel( Operation *op, SlapReply *rs )
791{
792	return over_op_func( op, rs, op_cancel );
793}
794
795static int
796over_op_extended( Operation *op, SlapReply *rs )
797{
798	return over_op_func( op, rs, op_extended );
799}
800
801static int
802over_aux_operational( Operation *op, SlapReply *rs )
803{
804	return over_op_func( op, rs, op_aux_operational );
805}
806
807static int
808over_aux_chk_referrals( Operation *op, SlapReply *rs )
809{
810	return over_op_func( op, rs, op_aux_chk_referrals );
811}
812
813static int
814over_aux_chk_controls( Operation *op, SlapReply *rs )
815{
816	return over_op_func( op, rs, op_aux_chk_controls );
817}
818
819enum conn_which {
820	conn_init = 0,
821	conn_destroy,
822	conn_last
823};
824
825static int
826over_connection_func(
827	BackendDB	*bd,
828	Connection	*conn,
829	enum conn_which	which
830)
831{
832	slap_overinfo		*oi;
833	slap_overinst		*on;
834	BackendDB		db;
835	int			rc = SLAP_CB_CONTINUE;
836	BI_connection_init	**func;
837
838	/* FIXME: used to happen for instance during abandon
839	 * when global overlays are used... */
840	assert( bd != NULL );
841
842	oi = bd->bd_info->bi_private;
843	on = oi->oi_list;
844
845 	if ( !SLAP_ISOVERLAY( bd ) ) {
846 		db = *bd;
847		db.be_flags |= SLAP_DBFLAG_OVERLAY;
848		bd = &db;
849	}
850
851	for ( ; on; on = on->on_next ) {
852		func = &on->on_bi.bi_connection_init;
853		if ( func[ which ] ) {
854			bd->bd_info = (BackendInfo *)on;
855			rc = func[ which ]( bd, conn );
856			if ( rc != SLAP_CB_CONTINUE ) break;
857		}
858	}
859
860	func = &oi->oi_orig->bi_connection_init;
861	if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
862		bd->bd_info = oi->oi_orig;
863		rc = func[ which ]( bd, conn );
864	}
865	/* should not fall thru this far without anything happening... */
866	if ( rc == SLAP_CB_CONTINUE ) {
867		rc = LDAP_UNWILLING_TO_PERFORM;
868	}
869
870	return rc;
871}
872
873static int
874over_connection_init(
875	BackendDB	*bd,
876	Connection	*conn
877)
878{
879	return over_connection_func( bd, conn, conn_init );
880}
881
882static int
883over_connection_destroy(
884	BackendDB	*bd,
885	Connection	*conn
886)
887{
888	return over_connection_func( bd, conn, conn_destroy );
889}
890
891int
892overlay_register(
893	slap_overinst *on
894)
895{
896	slap_overinst	*tmp;
897
898	/* FIXME: check for duplicates? */
899	for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) {
900		if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) {
901			Debug( LDAP_DEBUG_ANY,
902				"overlay_register(\"%s\"): "
903				"name already in use.\n",
904				on->on_bi.bi_type, 0, 0 );
905			return -1;
906		}
907
908		if ( on->on_bi.bi_obsolete_names != NULL ) {
909			int	i;
910
911			for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
912				if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) {
913					Debug( LDAP_DEBUG_ANY,
914						"overlay_register(\"%s\"): "
915						"obsolete name \"%s\" already in use "
916						"by overlay \"%s\".\n",
917						on->on_bi.bi_type,
918						on->on_bi.bi_obsolete_names[ i ],
919						tmp->on_bi.bi_type );
920					return -1;
921				}
922			}
923		}
924
925		if ( tmp->on_bi.bi_obsolete_names != NULL ) {
926			int	i;
927
928			for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
929				int	j;
930
931				if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
932					Debug( LDAP_DEBUG_ANY,
933						"overlay_register(\"%s\"): "
934						"name already in use "
935						"as obsolete by overlay \"%s\".\n",
936						on->on_bi.bi_type,
937						tmp->on_bi.bi_obsolete_names[ i ], 0 );
938					return -1;
939				}
940
941				if ( on->on_bi.bi_obsolete_names != NULL ) {
942					for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) {
943						if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
944							Debug( LDAP_DEBUG_ANY,
945								"overlay_register(\"%s\"): "
946								"obsolete name \"%s\" already in use "
947								"as obsolete by overlay \"%s\".\n",
948								on->on_bi.bi_type,
949								on->on_bi.bi_obsolete_names[ j ],
950								tmp->on_bi.bi_type );
951							return -1;
952						}
953					}
954				}
955			}
956		}
957	}
958
959	on->on_next = overlays;
960	overlays = on;
961	return 0;
962}
963
964/*
965 * iterator on registered overlays; overlay_next( NULL ) returns the first
966 * overlay; subsequent calls with the previously returned value allow to
967 * iterate over the entire list; returns NULL when no more overlays are
968 * registered.
969 */
970
971slap_overinst *
972overlay_next(
973	slap_overinst *on
974)
975{
976	if ( on == NULL ) {
977		return overlays;
978	}
979
980	return on->on_next;
981}
982
983/*
984 * returns a specific registered overlay based on the type; NULL if not
985 * registered.
986 */
987
988slap_overinst *
989overlay_find( const char *over_type )
990{
991	slap_overinst *on = overlays;
992
993	assert( over_type != NULL );
994
995	for ( ; on; on = on->on_next ) {
996		if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
997			goto foundit;
998		}
999
1000		if ( on->on_bi.bi_obsolete_names != NULL ) {
1001			int	i;
1002
1003			for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
1004				if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) {
1005					Debug( LDAP_DEBUG_ANY,
1006						"overlay_find(\"%s\"): "
1007						"obsolete name for \"%s\".\n",
1008						on->on_bi.bi_obsolete_names[ i ],
1009						on->on_bi.bi_type, 0 );
1010					goto foundit;
1011				}
1012			}
1013		}
1014	}
1015
1016foundit:;
1017	return on;
1018}
1019
1020static const char overtype[] = "over";
1021
1022/*
1023 * returns TRUE (1) if the database is actually an overlay instance;
1024 * FALSE (0) otherwise.
1025 */
1026
1027int
1028overlay_is_over( BackendDB *be )
1029{
1030	return be->bd_info->bi_type == overtype;
1031}
1032
1033/*
1034 * returns TRUE (1) if the given database is actually an overlay
1035 * instance and, somewhere in the list, contains the requested overlay;
1036 * FALSE (0) otherwise.
1037 */
1038
1039int
1040overlay_is_inst( BackendDB *be, const char *over_type )
1041{
1042	slap_overinst	*on;
1043
1044	assert( be != NULL );
1045
1046	if ( !overlay_is_over( be ) ) {
1047		return 0;
1048	}
1049
1050	on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
1051	for ( ; on; on = on->on_next ) {
1052		if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
1053			return 1;
1054		}
1055	}
1056
1057	return 0;
1058}
1059
1060int
1061overlay_register_control( BackendDB *be, const char *oid )
1062{
1063	int		gotit = 0;
1064	int		cid;
1065
1066	if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
1067		return -1;
1068	}
1069
1070	if ( SLAP_ISGLOBALOVERLAY( be ) ) {
1071		BackendDB *bd;
1072
1073		/* add to all backends... */
1074		LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
1075			if ( bd == be->bd_self ) {
1076				gotit = 1;
1077			}
1078
1079			bd->be_ctrls[ cid ] = 1;
1080			bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1081		}
1082
1083	}
1084
1085	if ( !gotit ) {
1086		be->bd_self->be_ctrls[ cid ] = 1;
1087		be->bd_self->be_ctrls[ SLAP_MAX_CIDS ] = 1;
1088	}
1089
1090	return 0;
1091}
1092
1093void
1094overlay_destroy_one( BackendDB *be, slap_overinst *on )
1095{
1096	slap_overinfo *oi = on->on_info;
1097	slap_overinst **oidx;
1098
1099	for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1100		if ( *oidx == on ) {
1101			*oidx = on->on_next;
1102			if ( on->on_bi.bi_db_destroy ) {
1103				BackendInfo *bi_orig = be->bd_info;
1104				be->bd_info = (BackendInfo *)on;
1105				on->on_bi.bi_db_destroy( be, NULL );
1106				be->bd_info = bi_orig;
1107			}
1108			free( on );
1109			break;
1110		}
1111	}
1112}
1113
1114#ifdef SLAP_CONFIG_DELETE
1115void
1116overlay_remove( BackendDB *be, slap_overinst *on )
1117{
1118	slap_overinfo *oi = on->on_info;
1119	slap_overinst **oidx;
1120	BackendInfo *bi_orig;
1121
1122	/* remove overlay from oi_list an call db_close and db_destroy
1123	 * handlers */
1124	for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
1125		if ( *oidx == on ) {
1126			*oidx = on->on_next;
1127			bi_orig = be->bd_info;
1128			be->bd_info = (BackendInfo *)on;
1129			if ( on->on_bi.bi_db_close ) {
1130				on->on_bi.bi_db_close( be, NULL );
1131			}
1132			if ( on->on_bi.bi_db_destroy ) {
1133				on->on_bi.bi_db_destroy( be, NULL );
1134			}
1135			be->bd_info = bi_orig;
1136			free( on );
1137			break;
1138		}
1139	}
1140
1141	/* clean up after removing last overlay */
1142	if ( ! oi->oi_list )
1143	{
1144		/* reset db flags and bd_info to orig */
1145		SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_GLOBAL_OVERLAY;
1146		be->bd_info = oi->oi_orig;
1147		ch_free(oi);
1148	}
1149}
1150#endif /* SLAP_CONFIG_DELETE */
1151
1152void
1153overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev,
1154	int idx )
1155{
1156	slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1157
1158	if ( idx == -1 ) {
1159		on2->on_next = oi->oi_list;
1160		oi->oi_list = on2;
1161	} else {
1162		int i;
1163		slap_overinst *on, *otmp1 = NULL, *otmp2;
1164
1165		/* Since the list is in reverse order and is singly linked,
1166		 * we reverse it to find the idx insertion point. Adding
1167		 * on overlay at a specific point should be a pretty
1168		 * infrequent occurrence.
1169		 */
1170		for ( on = oi->oi_list; on; on=otmp2 ) {
1171			otmp2 = on->on_next;
1172			on->on_next = otmp1;
1173			otmp1 = on;
1174		}
1175		oi->oi_list = NULL;
1176		/* advance to insertion point */
1177		for ( i=0, on = otmp1; i<idx; i++ ) {
1178			otmp1 = on->on_next;
1179			on->on_next = oi->oi_list;
1180			oi->oi_list = on;
1181		}
1182		/* insert */
1183		on2->on_next = oi->oi_list;
1184		oi->oi_list = on2;
1185		if ( otmp1 ) {
1186			*prev = &otmp1->on_next;
1187			/* replace remainder of list */
1188			for ( on=otmp1; on; on=otmp1 ) {
1189				otmp1 = on->on_next;
1190				on->on_next = oi->oi_list;
1191				oi->oi_list = on;
1192			}
1193		}
1194	}
1195}
1196
1197void
1198overlay_move( BackendDB *be, slap_overinst *on, int idx )
1199{
1200	slap_overinfo *oi = (slap_overinfo *)be->bd_info;
1201	slap_overinst **onp;
1202
1203	for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) {
1204		if ( *onp == on ) {
1205			*onp = on->on_next;
1206			break;
1207		}
1208	}
1209	overlay_insert( be, on, &onp, idx );
1210}
1211
1212/* add an overlay to a particular backend. */
1213int
1214overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res, ConfigReply *cr )
1215{
1216	slap_overinst *on = NULL, *on2 = NULL, **prev;
1217	slap_overinfo *oi = NULL;
1218	BackendInfo *bi = NULL;
1219
1220	if ( res )
1221		*res = NULL;
1222
1223	on = overlay_find( ov );
1224	if ( !on ) {
1225		Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
1226		return 1;
1227	}
1228
1229	/* If this is the first overlay on this backend, set up the
1230	 * overlay info structure
1231	 */
1232	if ( !overlay_is_over( be ) ) {
1233		int	isglobal = 0;
1234
1235		/* NOTE: the first time a global overlay is configured,
1236		 * frontendDB gets this flag; it is used later by overlays
1237		 * to determine if they're stacked on top of the frontendDB */
1238		if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) {
1239			isglobal = 1;
1240			if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) {
1241				Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1242					"overlay \"%s\" cannot be global.\n",
1243					ov, 0, 0 );
1244				return 1;
1245			}
1246
1247		} else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) {
1248			Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1249				"overlay \"%s\" can only be global.\n",
1250				ov, 0, 0 );
1251			return 1;
1252		}
1253
1254		oi = ch_malloc( sizeof( slap_overinfo ) );
1255		oi->oi_orig = be->bd_info;
1256		oi->oi_bi = *be->bd_info;
1257		oi->oi_origdb = be;
1258
1259		if ( isglobal ) {
1260			SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
1261		}
1262
1263		/* Save a pointer to ourself in bi_private.
1264		 */
1265		oi->oi_bi.bi_private = oi;
1266		oi->oi_list = NULL;
1267		bi = (BackendInfo *)oi;
1268
1269		bi->bi_type = (char *)overtype;
1270
1271		bi->bi_db_config = over_db_config;
1272		bi->bi_db_open = over_db_open;
1273		bi->bi_db_close = over_db_close;
1274		bi->bi_db_destroy = over_db_destroy;
1275
1276		bi->bi_op_bind = over_op_bind;
1277		bi->bi_op_unbind = over_op_unbind;
1278		bi->bi_op_search = over_op_search;
1279		bi->bi_op_compare = over_op_compare;
1280		bi->bi_op_modify = over_op_modify;
1281		bi->bi_op_modrdn = over_op_modrdn;
1282		bi->bi_op_add = over_op_add;
1283		bi->bi_op_delete = over_op_delete;
1284		bi->bi_op_abandon = over_op_abandon;
1285		bi->bi_op_cancel = over_op_cancel;
1286
1287		bi->bi_extended = over_op_extended;
1288
1289		/*
1290		 * this is fine because it has the same
1291		 * args of the operations; we need to rework
1292		 * all the hooks to share the same args
1293		 * of the operations...
1294		 */
1295		bi->bi_operational = over_aux_operational;
1296		bi->bi_chk_referrals = over_aux_chk_referrals;
1297		bi->bi_chk_controls = over_aux_chk_controls;
1298
1299		/* these have specific arglists */
1300		bi->bi_entry_get_rw = over_entry_get_rw;
1301		bi->bi_entry_release_rw = over_entry_release_rw;
1302		bi->bi_access_allowed = over_access_allowed;
1303		bi->bi_acl_group = over_acl_group;
1304		bi->bi_acl_attribute = over_acl_attribute;
1305
1306		bi->bi_connection_init = over_connection_init;
1307		bi->bi_connection_destroy = over_connection_destroy;
1308
1309		be->bd_info = bi;
1310
1311	} else {
1312		if ( overlay_is_inst( be, ov ) ) {
1313			if ( SLAPO_SINGLE( be ) ) {
1314				Debug( LDAP_DEBUG_ANY, "overlay_config(): "
1315					"overlay \"%s\" already in list\n",
1316					ov, 0, 0 );
1317				return 1;
1318			}
1319		}
1320
1321		oi = be->bd_info->bi_private;
1322	}
1323
1324	/* Insert new overlay into list. By default overlays are
1325	 * added to head of list and executed in LIFO order.
1326	 */
1327	on2 = ch_calloc( 1, sizeof(slap_overinst) );
1328	*on2 = *on;
1329	on2->on_info = oi;
1330
1331	prev = &oi->oi_list;
1332	/* Do we need to find the insertion point? */
1333	if ( idx >= 0 ) {
1334		int i;
1335
1336		/* count current overlays */
1337		for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ );
1338
1339		/* are we just appending a new one? */
1340		if ( idx >= i )
1341			idx = -1;
1342	}
1343	overlay_insert( be, on2, &prev, idx );
1344
1345	/* Any initialization needed? */
1346	if ( on2->on_bi.bi_db_init ) {
1347		int rc;
1348		be->bd_info = (BackendInfo *)on2;
1349		rc = on2->on_bi.bi_db_init( be, cr);
1350		be->bd_info = (BackendInfo *)oi;
1351		if ( rc ) {
1352			*prev = on2->on_next;
1353			ch_free( on2 );
1354			on2 = NULL;
1355			return rc;
1356		}
1357	}
1358
1359	if ( res )
1360		*res = &on2->on_bi;
1361
1362	return 0;
1363}
1364
1365