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>
30 static slap_overinst *overlays;
45 slap_overinfo *oi = be->bd_info->bi_private;
46 slap_overinst *on = oi->oi_list;
47 BackendInfo *bi_orig = be->bd_info;
51 func = &oi->oi_orig->bi_db_open;
53 be->bd_info = oi->oi_orig;
54 rc = func[which]( be );
57 for (; on && rc == 0; on=on->on_next) {
58 be->bd_info = &on->on_bi;
59 func = &on->on_bi.bi_db_open;
61 rc = func[which]( be );
64 be->bd_info = bi_orig;
77 slap_overinfo *oi = be->bd_info->bi_private;
78 slap_overinst *on = oi->oi_list;
79 BackendInfo *bi_orig = be->bd_info;
80 struct ConfigOCs *be_cf_ocs = be->be_cf_ocs;
84 if ( oi->oi_orig->bi_db_config ) {
85 be->bd_info = oi->oi_orig;
86 be->be_cf_ocs = oi->oi_orig->bi_cf_ocs;
87 rc = oi->oi_orig->bi_db_config( be, fname, lineno,
90 if ( be->bd_info != oi->oi_orig ) {
92 slap_overinst *on2, **onp;
96 /* a database added an overlay;
97 * work it around... */
98 assert( overlay_is_over( be ) );
100 oi2 = ( slap_overinfo * )be->bd_info->bi_private;
103 /* need to put a uniqueness check here as well;
104 * note that in principle there could be more than
105 * one overlay as a result of multiple calls to
106 * overlay_config() */
107 be2.bd_info = (BackendInfo *)oi;
109 for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
110 if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
111 Debug( LDAP_DEBUG_ANY, "over_db_config(): "
112 "warning, freshly added "
113 "overlay #%d \"%s\" is already in list\n",
114 i, (*onp)->on_bi.bi_type, 0 );
116 /* NOTE: if the overlay already exists,
117 * there is no way to merge the results
118 * of the configuration that may have
119 * occurred during bi_db_config(); we
120 * just issue a warning, and the
121 * administrator should deal with this */
128 ch_free( be->bd_info );
131 be->bd_info = (BackendInfo *)oi;
132 if ( rc != SLAP_CONF_UNKNOWN ) return rc;
140 for (; on; on=on->on_next) {
141 rc = SLAP_CONF_UNKNOWN;
142 if (on->on_bi.bi_cf_ocs) {
145 ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca );
147 rc = config_add_vals( ct, &ca );
148 if ( rc != SLAP_CONF_UNKNOWN )
152 if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) {
153 be->bd_info = &on->on_bi;
154 rc = on->on_bi.bi_db_config( be, fname, lineno,
156 if ( rc != SLAP_CONF_UNKNOWN ) break;
159 be->bd_info = bi_orig;
160 be->be_cf_ocs = be_cf_ocs;
170 return over_db_func( be, db_open );
178 slap_overinfo *oi = be->bd_info->bi_private;
179 slap_overinst *on = oi->oi_list;
180 BackendInfo *bi_orig = be->bd_info;
183 for (; on && rc == 0; on=on->on_next) {
184 be->bd_info = &on->on_bi;
185 if ( be->bd_info->bi_db_close ) {
186 rc = be->bd_info->bi_db_close( be );
190 if ( oi->oi_orig->bi_db_close ) {
191 be->bd_info = oi->oi_orig;
192 rc = be->bd_info->bi_db_close( be );
195 be->bd_info = bi_orig;
204 slap_overinfo *oi = be->bd_info->bi_private;
205 slap_overinst *on = oi->oi_list, *next;
208 rc = over_db_func( be, db_destroy );
210 for (next = on->on_next; on; on=next) {
219 over_back_response ( Operation *op, SlapReply *rs )
221 slap_overinfo *oi = op->o_callback->sc_private;
222 slap_overinst *on = oi->oi_list;
223 int rc = SLAP_CB_CONTINUE;
224 BackendDB *be = op->o_bd, db = *op->o_bd;
226 db.be_flags |= SLAP_DBFLAG_OVERLAY;
228 for (; on; on=on->on_next ) {
229 if ( on->on_response ) {
230 db.bd_info = (BackendInfo *)on;
231 rc = on->on_response( op, rs );
232 if ( rc != SLAP_CB_CONTINUE ) break;
239 #ifdef SLAP_OVERLAY_ACCESS
244 AttributeDescription *desc,
246 slap_access_t access,
247 AccessControlState *state,
252 BackendInfo *bi = op->o_bd->bd_info;
253 BackendDB *be = op->o_bd, db;
254 int rc = SLAP_CB_CONTINUE;
256 /* FIXME: used to happen for instance during abandon
257 * when global overlays are used... */
258 assert( op->o_bd != NULL );
260 oi = op->o_bd->bd_info->bi_private;
263 for ( ; on; on = on->on_next ) {
264 if ( on->on_bi.bi_access_allowed ) {
265 /* NOTE: do not copy the structure until required */
266 if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
268 db.be_flags |= SLAP_DBFLAG_OVERLAY;
272 op->o_bd->bd_info = (BackendInfo *)on;
273 rc = on->on_bi.bi_access_allowed( op, e,
274 desc, val, access, state, maskp );
275 if ( rc != SLAP_CB_CONTINUE ) break;
279 if ( rc == SLAP_CB_CONTINUE ) {
280 BI_access_allowed *bi_access_allowed;
282 /* if the database structure was changed, o_bd points to a
283 * copy of the structure; put the original bd_info in place */
284 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
285 op->o_bd->bd_info = oi->oi_orig;
288 if ( oi->oi_orig->bi_access_allowed ) {
289 bi_access_allowed = oi->oi_orig->bi_access_allowed;
291 bi_access_allowed = slap_access_allowed;
294 rc = bi_access_allowed( op, e,
295 desc, val, access, state, maskp );
297 /* should not fall thru this far without anything happening... */
298 if ( rc == SLAP_CB_CONTINUE ) {
299 /* access not allowed */
304 op->o_bd->bd_info = bi;
313 struct berval *gr_ndn,
314 struct berval *op_ndn,
315 ObjectClass *group_oc,
316 AttributeDescription *group_at )
320 BackendInfo *bi = op->o_bd->bd_info;
321 BackendDB *be = op->o_bd, db;
322 int rc = SLAP_CB_CONTINUE;
324 /* FIXME: used to happen for instance during abandon
325 * when global overlays are used... */
326 assert( op->o_bd != NULL );
328 oi = op->o_bd->bd_info->bi_private;
331 for ( ; on; on = on->on_next ) {
332 if ( on->on_bi.bi_acl_group ) {
333 /* NOTE: do not copy the structure until required */
334 if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
336 db.be_flags |= SLAP_DBFLAG_OVERLAY;
340 op->o_bd->bd_info = (BackendInfo *)on;
341 rc = on->on_bi.bi_acl_group( op, e,
342 gr_ndn, op_ndn, group_oc, group_at );
343 if ( rc != SLAP_CB_CONTINUE ) break;
347 if ( rc == SLAP_CB_CONTINUE ) {
348 BI_acl_group *bi_acl_group;
350 /* if the database structure was changed, o_bd points to a
351 * copy of the structure; put the original bd_info in place */
352 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
353 op->o_bd->bd_info = oi->oi_orig;
356 if ( oi->oi_orig->bi_acl_group ) {
357 bi_acl_group = oi->oi_orig->bi_acl_group;
359 bi_acl_group = backend_group;
362 rc = bi_acl_group( op, e,
363 gr_ndn, op_ndn, group_oc, group_at );
365 /* should not fall thru this far without anything happening... */
366 if ( rc == SLAP_CB_CONTINUE ) {
367 /* access not allowed */
372 op->o_bd->bd_info = bi;
381 struct berval *entry_ndn,
382 AttributeDescription *entry_at,
384 slap_access_t access )
388 BackendInfo *bi = op->o_bd->bd_info;
389 BackendDB *be = op->o_bd, db;
390 int rc = SLAP_CB_CONTINUE;
392 /* FIXME: used to happen for instance during abandon
393 * when global overlays are used... */
394 assert( op->o_bd != NULL );
396 oi = op->o_bd->bd_info->bi_private;
399 for ( ; on; on = on->on_next ) {
400 if ( on->on_bi.bi_acl_attribute ) {
401 /* NOTE: do not copy the structure until required */
402 if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
404 db.be_flags |= SLAP_DBFLAG_OVERLAY;
408 op->o_bd->bd_info = (BackendInfo *)on;
409 rc = on->on_bi.bi_acl_attribute( op, target,
410 entry_ndn, entry_at, vals, access );
411 if ( rc != SLAP_CB_CONTINUE ) break;
415 if ( rc == SLAP_CB_CONTINUE ) {
416 BI_acl_attribute *bi_acl_attribute;
418 /* if the database structure was changed, o_bd points to a
419 * copy of the structure; put the original bd_info in place */
420 if ( SLAP_ISOVERLAY( op->o_bd ) ) {
421 op->o_bd->bd_info = oi->oi_orig;
424 if ( oi->oi_orig->bi_acl_attribute ) {
425 bi_acl_attribute = oi->oi_orig->bi_acl_attribute;
427 bi_acl_attribute = backend_attribute;
430 rc = bi_acl_attribute( op, target,
431 entry_ndn, entry_at, vals, access );
433 /* should not fall thru this far without anything happening... */
434 if ( rc == SLAP_CB_CONTINUE ) {
435 /* access not allowed */
440 op->o_bd->bd_info = bi;
444 #endif /* SLAP_OVERLAY_ACCESS */
447 * default return code in case of missing backend function
448 * and overlay stack returning SLAP_CB_CONTINUE
450 static int op_rc[ op_last ] = {
451 LDAP_UNWILLING_TO_PERFORM, /* bind */
452 LDAP_UNWILLING_TO_PERFORM, /* unbind */
453 LDAP_UNWILLING_TO_PERFORM, /* search */
454 SLAP_CB_CONTINUE, /* compare; pass to frontend */
455 LDAP_UNWILLING_TO_PERFORM, /* modify */
456 LDAP_UNWILLING_TO_PERFORM, /* modrdn */
457 LDAP_UNWILLING_TO_PERFORM, /* add */
458 LDAP_UNWILLING_TO_PERFORM, /* delete */
459 LDAP_UNWILLING_TO_PERFORM, /* abandon */
460 LDAP_UNWILLING_TO_PERFORM, /* cancel */
461 LDAP_UNWILLING_TO_PERFORM, /* extended */
462 LDAP_SUCCESS, /* aux_operational */
463 LDAP_SUCCESS, /* aux_chk_referrals */
464 SLAP_CB_CONTINUE /* aux_chk_controls; pass to frontend */
470 slap_operation_t which,
476 int rc = SLAP_CB_CONTINUE;
478 for (; on; on=on->on_next ) {
479 func = &on->on_bi.bi_op_bind;
481 op->o_bd->bd_info = (BackendInfo *)on;
482 rc = func[which]( op, rs );
483 if ( rc != SLAP_CB_CONTINUE ) break;
487 func = &oi->oi_orig->bi_op_bind;
488 if ( func[which] && rc == SLAP_CB_CONTINUE ) {
489 op->o_bd->bd_info = oi->oi_orig;
490 rc = func[which]( op, rs );
492 /* should not fall thru this far without anything happening... */
493 if ( rc == SLAP_CB_CONTINUE ) {
497 /* The underlying backend didn't handle the request, make sure
498 * overlay cleanup is processed.
500 if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
501 slap_callback *sc_next;
502 for ( ; op->o_callback && op->o_callback->sc_response !=
503 over_back_response; op->o_callback = sc_next ) {
504 sc_next = op->o_callback->sc_next;
505 if ( op->o_callback->sc_cleanup ) {
506 op->o_callback->sc_cleanup( op, rs );
517 slap_operation_t which
522 BackendDB *be = op->o_bd, db;
523 slap_callback cb = {NULL, over_back_response, NULL, NULL};
524 int rc = SLAP_CB_CONTINUE;
526 /* FIXME: used to happen for instance during abandon
527 * when global overlays are used... */
528 assert( op->o_bd != NULL );
530 oi = op->o_bd->bd_info->bi_private;
533 if ( !SLAP_ISOVERLAY( op->o_bd )) {
535 db.be_flags |= SLAP_DBFLAG_OVERLAY;
538 cb.sc_next = op->o_callback;
540 op->o_callback = &cb;
542 rc = overlay_op_walk( op, rs, which, oi, on );
545 op->o_callback = cb.sc_next;
550 over_op_bind( Operation *op, SlapReply *rs )
552 return over_op_func( op, rs, op_bind );
556 over_op_unbind( Operation *op, SlapReply *rs )
558 return over_op_func( op, rs, op_unbind );
562 over_op_search( Operation *op, SlapReply *rs )
564 return over_op_func( op, rs, op_search );
568 over_op_compare( Operation *op, SlapReply *rs )
570 return over_op_func( op, rs, op_compare );
574 over_op_modify( Operation *op, SlapReply *rs )
576 return over_op_func( op, rs, op_modify );
580 over_op_modrdn( Operation *op, SlapReply *rs )
582 return over_op_func( op, rs, op_modrdn );
586 over_op_add( Operation *op, SlapReply *rs )
588 return over_op_func( op, rs, op_add );
592 over_op_delete( Operation *op, SlapReply *rs )
594 return over_op_func( op, rs, op_delete );
598 over_op_abandon( Operation *op, SlapReply *rs )
600 return over_op_func( op, rs, op_abandon );
604 over_op_cancel( Operation *op, SlapReply *rs )
606 return over_op_func( op, rs, op_cancel );
610 over_op_extended( Operation *op, SlapReply *rs )
612 return over_op_func( op, rs, op_extended );
616 over_aux_operational( Operation *op, SlapReply *rs )
618 return over_op_func( op, rs, op_aux_operational );
622 over_aux_chk_referrals( Operation *op, SlapReply *rs )
624 return over_op_func( op, rs, op_aux_chk_referrals );
628 over_aux_chk_controls( Operation *op, SlapReply *rs )
630 return over_op_func( op, rs, op_aux_chk_controls );
640 over_connection_func(
643 enum conn_which which
649 int rc = SLAP_CB_CONTINUE;
650 BI_connection_init **func;
652 /* FIXME: used to happen for instance during abandon
653 * when global overlays are used... */
654 assert( bd != NULL );
656 oi = bd->bd_info->bi_private;
659 if ( !SLAP_ISOVERLAY( bd ) ) {
661 db.be_flags |= SLAP_DBFLAG_OVERLAY;
665 for ( ; on; on = on->on_next ) {
666 func = &on->on_bi.bi_connection_init;
667 if ( func[ which ] ) {
668 bd->bd_info = (BackendInfo *)on;
669 rc = func[ which ]( bd, conn );
670 if ( rc != SLAP_CB_CONTINUE ) break;
674 func = &oi->oi_orig->bi_connection_init;
675 if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
676 bd->bd_info = oi->oi_orig;
677 rc = func[ which ]( bd, conn );
679 /* should not fall thru this far without anything happening... */
680 if ( rc == SLAP_CB_CONTINUE ) {
681 rc = LDAP_UNWILLING_TO_PERFORM;
688 over_connection_init(
693 return over_connection_func( bd, conn, conn_init );
697 over_connection_destroy(
702 return over_connection_func( bd, conn, conn_destroy );
710 on->on_next = overlays;
716 * iterator on registered overlays; overlay_next( NULL ) returns the first
717 * overlay; * subsequent calls with the previously returned value allow to
718 * iterate * over the entire list; returns NULL when no more overlays are
735 * returns a specific registered overlay based on the type; NULL if not
740 overlay_find( const char *over_type )
742 slap_overinst *on = overlays;
744 assert( over_type != NULL );
746 for ( ; on; on = on->on_next ) {
747 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
755 static const char overtype[] = "over";
758 * returns TRUE (1) if the database is actually an overlay instance;
759 * FALSE (0) otherwise.
763 overlay_is_over( BackendDB *be )
765 return be->bd_info->bi_type == overtype;
769 * returns TRUE (1) if the given database is actually an overlay
770 * instance and, somewhere in the list, contains the requested overlay;
771 * FALSE (0) otherwise.
775 overlay_is_inst( BackendDB *be, const char *over_type )
779 assert( be != NULL );
781 if ( !overlay_is_over( be ) ) {
785 on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
786 for ( ; on; on = on->on_next ) {
787 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
796 overlay_register_control( BackendDB *be, const char *oid )
802 if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
806 if ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_GLOBAL_OVERLAY ) {
809 /* add to all backends... */
810 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
815 bd->be_ctrls[ cid ] = 1;
816 bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
821 if ( rc == 0 && !gotit ) {
822 be->be_ctrls[ cid ] = 1;
823 be->be_ctrls[ SLAP_MAX_CIDS ] = 1;
830 overlay_destroy_one( BackendDB *be, slap_overinst *on )
832 slap_overinfo *oi = on->on_info;
833 slap_overinst **oidx;
835 for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
838 if ( on->on_bi.bi_db_destroy ) {
839 BackendInfo *bi_orig = be->bd_info;
840 be->bd_info = (BackendInfo *)on;
841 on->on_bi.bi_db_destroy( be );
842 be->bd_info = bi_orig;
850 /* add an overlay to a particular backend. */
852 overlay_config( BackendDB *be, const char *ov )
854 slap_overinst *on = NULL, *on2 = NULL;
855 slap_overinfo *oi = NULL;
856 BackendInfo *bi = NULL;
858 on = overlay_find( ov );
860 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
864 /* If this is the first overlay on this backend, set up the
865 * overlay info structure
867 if ( !overlay_is_over( be ) ) {
868 oi = ch_malloc( sizeof( slap_overinfo ) );
869 oi->oi_orig = be->bd_info;
870 oi->oi_bi = *be->bd_info;
873 /* NOTE: the first time a global overlay is configured,
874 * frontendDB gets this flag; it is used later by overlays
875 * to determine if they're stacked on top of the frontendDB */
876 if ( oi->oi_orig == frontendDB->bd_info ) {
877 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
880 /* Save a pointer to ourself in bi_private.
882 oi->oi_bi.bi_private = oi;
884 bi = (BackendInfo *)oi;
886 bi->bi_type = (char *)overtype;
888 bi->bi_db_config = over_db_config;
889 bi->bi_db_open = over_db_open;
890 bi->bi_db_close = over_db_close;
891 bi->bi_db_destroy = over_db_destroy;
893 bi->bi_op_bind = over_op_bind;
894 bi->bi_op_unbind = over_op_unbind;
895 bi->bi_op_search = over_op_search;
896 bi->bi_op_compare = over_op_compare;
897 bi->bi_op_modify = over_op_modify;
898 bi->bi_op_modrdn = over_op_modrdn;
899 bi->bi_op_add = over_op_add;
900 bi->bi_op_delete = over_op_delete;
901 bi->bi_op_abandon = over_op_abandon;
902 bi->bi_op_cancel = over_op_cancel;
904 bi->bi_extended = over_op_extended;
907 * this is fine because it has the same
908 * args of the operations; we need to rework
909 * all the hooks to share the same args
910 * of the operations...
912 bi->bi_operational = over_aux_operational;
913 bi->bi_chk_referrals = over_aux_chk_referrals;
914 bi->bi_chk_controls = over_aux_chk_controls;
916 #ifdef SLAP_OVERLAY_ACCESS
917 /* these have specific arglists */
918 bi->bi_access_allowed = over_access_allowed;
919 bi->bi_acl_group = over_acl_group;
920 bi->bi_acl_attribute = over_acl_attribute;
921 #endif /* SLAP_OVERLAY_ACCESS */
923 bi->bi_connection_init = over_connection_init;
924 bi->bi_connection_destroy = over_connection_destroy;
929 if ( overlay_is_inst( be, ov ) ) {
930 Debug( LDAP_DEBUG_ANY, "overlay_config(): "
931 "warning, overlay \"%s\" "
932 "already in list\n", ov, 0, 0 );
935 oi = be->bd_info->bi_private;
938 /* Insert new overlay on head of list. Overlays are executed
939 * in reverse of config order...
941 on2 = ch_calloc( 1, sizeof(slap_overinst) );
944 on2->on_next = oi->oi_list;
947 /* Any initialization needed? */
948 if ( on->on_bi.bi_db_init ) {
950 be->bd_info = (BackendInfo *)on2;
951 rc = on2->on_bi.bi_db_init( be );
952 be->bd_info = (BackendInfo *)oi;