1 /* backover.c - backend overlay routines */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2005 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 /* Functions to overlay other modules over a backend. */
23 #include <ac/string.h>
24 #include <ac/socket.h>
29 static slap_overinst *overlays;
31 enum db_which { db_open = 0, db_close, db_destroy };
39 slap_overinfo *oi = be->bd_info->bi_private;
40 slap_overinst *on = oi->oi_list;
41 BackendInfo *bi_orig = be->bd_info;
45 func = &oi->oi_orig->bi_db_open;
47 be->bd_info = oi->oi_orig;
48 rc = func[which]( be );
51 for (; on && rc == 0; on=on->on_next) {
52 be->bd_info = &on->on_bi;
53 func = &on->on_bi.bi_db_open;
55 rc = func[which]( be );
58 be->bd_info = bi_orig;
71 slap_overinfo *oi = be->bd_info->bi_private;
72 slap_overinst *on = oi->oi_list;
73 BackendInfo *bi_orig = be->bd_info;
76 if ( oi->oi_orig->bi_db_config ) {
77 be->bd_info = oi->oi_orig;
78 rc = oi->oi_orig->bi_db_config( be, fname, lineno,
81 if ( be->bd_info != oi->oi_orig ) {
83 slap_overinst *on2, **onp;
87 /* a database added an overlay;
88 * work it around... */
89 assert( overlay_is_over( be ) );
91 oi2 = ( slap_overinfo * )be->bd_info->bi_private;
94 /* need to put a uniqueness check here as well;
95 * note that in principle there could be more than
96 * one overlay as a result of multiple calls to
98 be2.bd_info = (BackendInfo *)oi;
100 for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
101 if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
102 Debug( LDAP_DEBUG_ANY, "over_db_config(): "
103 "warning, freshly added "
104 "overlay #%d \"%s\" is already in list\n",
105 i, (*onp)->on_bi.bi_type, 0 );
107 /* NOTE: if the overlay already exists,
108 * there is no way to merge the results
109 * of the configuration that may have
110 * occurred during bi_db_config(); we
111 * just issue a warning, and the
112 * administrator should deal with this */
119 ch_free( be->bd_info );
122 be->bd_info = (BackendInfo *)oi;
123 if ( rc != SLAP_CONF_UNKNOWN ) return rc;
126 for (; on; on=on->on_next) {
127 if (on->on_bi.bi_db_config) {
128 be->bd_info = &on->on_bi;
129 rc = on->on_bi.bi_db_config( be, fname, lineno,
131 if ( rc != SLAP_CONF_UNKNOWN ) break;
134 be->bd_info = bi_orig;
143 return over_db_func( be, db_open );
151 slap_overinfo *oi = be->bd_info->bi_private;
152 slap_overinst *on = oi->oi_list;
153 BackendInfo *bi_orig = be->bd_info;
156 for (; on && rc == 0; on=on->on_next) {
157 be->bd_info = &on->on_bi;
158 if ( be->bd_info->bi_db_close ) {
159 rc = be->bd_info->bi_db_close( be );
163 if ( oi->oi_orig->bi_db_close ) {
164 be->bd_info = oi->oi_orig;
165 rc = be->bd_info->bi_db_close( be );
168 be->bd_info = bi_orig;
177 slap_overinfo *oi = be->bd_info->bi_private;
178 slap_overinst *on = oi->oi_list, *next;
181 rc = over_db_func( be, db_destroy );
183 for (next = on->on_next; on; on=next) {
192 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 BackendDB *be = op->o_bd, db = *op->o_bd;
199 db.be_flags |= SLAP_DBFLAG_OVERLAY;
201 for (; on; on=on->on_next ) {
202 if ( on->on_response ) {
203 db.bd_info = (BackendInfo *)on;
204 rc = on->on_response( op, rs );
205 if ( rc != SLAP_CB_CONTINUE ) break;
225 op_aux_chk_referrals,
231 * default return code in case of missing backend function
232 * and overlay stack returning SLAP_CB_CONTINUE
234 static int op_rc[] = {
235 LDAP_UNWILLING_TO_PERFORM, /* bind */
236 LDAP_UNWILLING_TO_PERFORM, /* unbind */
237 LDAP_UNWILLING_TO_PERFORM, /* search */
238 SLAP_CB_CONTINUE, /* compare; pass to frontend */
239 LDAP_UNWILLING_TO_PERFORM, /* modify */
240 LDAP_UNWILLING_TO_PERFORM, /* modrdn */
241 LDAP_UNWILLING_TO_PERFORM, /* add */
242 LDAP_UNWILLING_TO_PERFORM, /* delete */
243 LDAP_UNWILLING_TO_PERFORM, /* abandon */
244 LDAP_UNWILLING_TO_PERFORM, /* cancel */
245 LDAP_UNWILLING_TO_PERFORM, /* extended */
246 LDAP_SUCCESS, /* aux_operational */
247 LDAP_SUCCESS, /* aux_chk_referrals */
248 SLAP_CB_CONTINUE /* aux_chk_controls; pass to frontend */
251 #ifdef SLAP_OVERLAY_ACCESS
256 AttributeDescription *desc,
258 slap_access_t access,
259 AccessControlState *state,
264 BackendDB *be = op->o_bd, db;
265 int rc = SLAP_CB_CONTINUE;
267 /* FIXME: used to happen for instance during abandon
268 * when global overlays are used... */
269 assert( op->o_bd != NULL );
271 oi = op->o_bd->bd_info->bi_private;
274 for ( ; on; on = on->on_next ) {
275 if ( on->on_bi.bi_access_allowed ) {
276 /* NOTE: do not copy the structure until required */
277 if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
279 db.be_flags |= SLAP_DBFLAG_OVERLAY;
283 op->o_bd->bd_info = (BackendInfo *)on;
284 rc = on->on_bi.bi_access_allowed( op, e,
285 desc, val, access, state, maskp );
286 if ( rc != SLAP_CB_CONTINUE ) break;
290 if ( rc == SLAP_CB_CONTINUE && oi->oi_orig->bi_access_allowed ) {
291 /* if the database structure was changed, o_bd points to a
292 * copy of the structure; put the original bd_info in place */
293 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
294 op->o_bd->bd_info = oi->oi_orig;
297 rc = oi->oi_orig->bi_access_allowed( op, e,
298 desc, val, access, state, maskp );
300 /* should not fall thru this far without anything happening... */
301 if ( rc == SLAP_CB_CONTINUE ) {
302 /* access not allowed */
309 #endif /* SLAP_OVERLAY_ACCESS */
321 BackendDB *be = op->o_bd, db;
322 slap_callback cb = {NULL, over_back_response, NULL, NULL};
323 int rc = SLAP_CB_CONTINUE;
325 /* FIXME: used to happen for instance during abandon
326 * when global overlays are used... */
327 assert( op->o_bd != NULL );
329 oi = op->o_bd->bd_info->bi_private;
332 if ( !SLAP_ISOVERLAY( op->o_bd )) {
334 db.be_flags |= SLAP_DBFLAG_OVERLAY;
337 cb.sc_next = op->o_callback;
339 op->o_callback = &cb;
341 for (; on; on=on->on_next ) {
342 func = &on->on_bi.bi_op_bind;
344 op->o_bd->bd_info = (BackendInfo *)on;
345 rc = func[which]( op, rs );
346 if ( rc != SLAP_CB_CONTINUE ) break;
350 func = &oi->oi_orig->bi_op_bind;
351 if ( func[which] && rc == SLAP_CB_CONTINUE ) {
352 op->o_bd->bd_info = oi->oi_orig;
353 rc = func[which]( op, rs );
355 /* should not fall thru this far without anything happening... */
356 if ( rc == SLAP_CB_CONTINUE ) {
360 /* The underlying backend didn't handle the request, make sure
361 * overlay cleanup is processed.
363 if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
364 slap_callback *sc_next;
365 for ( ; op->o_callback && op->o_callback != cb.sc_next;
366 op->o_callback = sc_next ) {
367 sc_next = op->o_callback->sc_next;
368 if ( op->o_callback->sc_cleanup ) {
369 op->o_callback->sc_cleanup( op, rs );
374 op->o_callback = cb.sc_next;
379 over_op_bind( Operation *op, SlapReply *rs )
381 return over_op_func( op, rs, op_bind );
385 over_op_unbind( Operation *op, SlapReply *rs )
387 return over_op_func( op, rs, op_unbind );
391 over_op_search( Operation *op, SlapReply *rs )
393 return over_op_func( op, rs, op_search );
397 over_op_compare( Operation *op, SlapReply *rs )
399 return over_op_func( op, rs, op_compare );
403 over_op_modify( Operation *op, SlapReply *rs )
405 return over_op_func( op, rs, op_modify );
409 over_op_modrdn( Operation *op, SlapReply *rs )
411 return over_op_func( op, rs, op_modrdn );
415 over_op_add( Operation *op, SlapReply *rs )
417 return over_op_func( op, rs, op_add );
421 over_op_delete( Operation *op, SlapReply *rs )
423 return over_op_func( op, rs, op_delete );
427 over_op_abandon( Operation *op, SlapReply *rs )
429 return over_op_func( op, rs, op_abandon );
433 over_op_cancel( Operation *op, SlapReply *rs )
435 return over_op_func( op, rs, op_cancel );
439 over_op_extended( Operation *op, SlapReply *rs )
441 return over_op_func( op, rs, op_extended );
445 over_aux_operational( Operation *op, SlapReply *rs )
447 return over_op_func( op, rs, op_aux_operational );
451 over_aux_chk_referrals( Operation *op, SlapReply *rs )
453 return over_op_func( op, rs, op_aux_chk_referrals );
457 over_aux_chk_controls( Operation *op, SlapReply *rs )
459 return over_op_func( op, rs, op_aux_chk_controls );
463 over_connection_destroy(
471 int rc = SLAP_CB_CONTINUE;
473 /* FIXME: used to happen for instance during abandon
474 * when global overlays are used... */
475 assert( bd != NULL );
477 oi = bd->bd_info->bi_private;
480 if ( !SLAP_ISOVERLAY( bd )) {
482 db.be_flags |= SLAP_DBFLAG_OVERLAY;
486 for (; on; on=on->on_next ) {
487 if ( on->on_bi.bi_connection_destroy ) {
488 bd->bd_info = (BackendInfo *)on;
489 rc = on->on_bi.bi_connection_destroy( bd, conn );
490 if ( rc != SLAP_CB_CONTINUE ) break;
494 if ( oi->oi_orig->bi_connection_destroy && rc == SLAP_CB_CONTINUE ) {
495 bd->bd_info = oi->oi_orig;
496 rc = oi->oi_orig->bi_connection_destroy( bd, conn );
498 /* should not fall thru this far without anything happening... */
499 if ( rc == SLAP_CB_CONTINUE ) {
500 rc = LDAP_UNWILLING_TO_PERFORM;
511 on->on_next = overlays;
517 * iterator on registered overlays; overlay_next( NULL ) returns the first
518 * overlay; * subsequent calls with the previously returned value allow to
519 * iterate * over the entire list; returns NULL when no more overlays are
536 * returns a specific registered overlay based on the type; NULL if not
541 overlay_find( const char *over_type )
543 slap_overinst *on = overlays;
547 for ( ; on; on = on->on_next ) {
548 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
556 static const char overtype[] = "over";
559 * returns TRUE (1) if the database is actually an overlay instance;
560 * FALSE (0) otherwise.
564 overlay_is_over( BackendDB *be )
566 return be->bd_info->bi_type == overtype;
570 * returns TRUE (1) if the given database is actually an overlay
571 * instance and, somewhere in the list, contains the requested overlay;
572 * FALSE (0) otherwise.
576 overlay_is_inst( BackendDB *be, const char *over_type )
582 if ( !overlay_is_over( be ) ) {
586 on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
587 for ( ; on; on = on->on_next ) {
588 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
597 overlay_register_control( BackendDB *be, const char *oid )
603 if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
607 if ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_GLOBAL_OVERLAY ) {
610 /* add to all backends... */
611 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
616 bd->be_ctrls[ cid ] = 1;
617 bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
622 if ( rc == 0 && !gotit ) {
623 be->be_ctrls[ cid ] = 1;
624 be->be_ctrls[ SLAP_MAX_CIDS ] = 1;
630 /* add an overlay to a particular backend. */
632 overlay_config( BackendDB *be, const char *ov )
634 slap_overinst *on = NULL, *on2 = NULL;
635 slap_overinfo *oi = NULL;
636 BackendInfo *bi = NULL;
638 on = overlay_find( ov );
640 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
644 /* If this is the first overlay on this backend, set up the
645 * overlay info structure
647 if ( !overlay_is_over( be ) ) {
648 oi = ch_malloc( sizeof( slap_overinfo ) );
649 oi->oi_orig = be->bd_info;
650 oi->oi_bi = *be->bd_info;
652 /* NOTE: the first time a global overlay is configured,
653 * frontendDB gets this flag; it is used later by overlays
654 * to determine if they're stacked on top of the frontendDB */
655 if ( oi->oi_orig == frontendDB->bd_info ) {
656 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
659 /* Save a pointer to ourself in bi_private.
661 oi->oi_bi.bi_private = oi;
663 bi = (BackendInfo *)oi;
665 bi->bi_type = (char *)overtype;
667 bi->bi_db_config = over_db_config;
668 bi->bi_db_open = over_db_open;
669 bi->bi_db_close = over_db_close;
670 bi->bi_db_destroy = over_db_destroy;
672 bi->bi_op_bind = over_op_bind;
673 bi->bi_op_unbind = over_op_unbind;
674 bi->bi_op_search = over_op_search;
675 bi->bi_op_compare = over_op_compare;
676 bi->bi_op_modify = over_op_modify;
677 bi->bi_op_modrdn = over_op_modrdn;
678 bi->bi_op_add = over_op_add;
679 bi->bi_op_delete = over_op_delete;
680 bi->bi_op_abandon = over_op_abandon;
681 bi->bi_op_cancel = over_op_cancel;
683 bi->bi_extended = over_op_extended;
686 * this is fine because it has the same
687 * args of the operations; we need to rework
688 * all the hooks to share the same args
689 * of the operations...
691 bi->bi_operational = over_aux_operational;
692 bi->bi_chk_referrals = over_aux_chk_referrals;
693 bi->bi_chk_controls = over_aux_chk_controls;
695 #ifdef SLAP_OVERLAY_ACCESS
696 /* this has a specific arglist */
697 bi->bi_access_allowed = over_access_allowed;
698 #endif /* SLAP_OVERLAY_ACCESS */
700 bi->bi_connection_destroy = over_connection_destroy;
705 if ( overlay_is_inst( be, ov ) ) {
706 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
707 "warning, overlay \"%s\" "
708 "already in list\n", ov, 0, 0 );
711 oi = be->bd_info->bi_private;
714 /* Insert new overlay on head of list. Overlays are executed
715 * in reverse of config order...
717 on2 = ch_calloc( 1, sizeof(slap_overinst) );
720 on2->on_next = oi->oi_list;
723 /* Any initialization needed? */
724 if ( on->on_bi.bi_db_init ) {
726 be->bd_info = (BackendInfo *)on2;
727 rc = on2->on_bi.bi_db_init( be );
728 be->bd_info = (BackendInfo *)oi;