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