1 /* op.c - relay backend operations */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2004-2008 The OpenLDAP Foundation.
5 * Portions Copyright 2004 Pierangelo Masarati.
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 * This work was initially developed by Pierangelo Masarati for inclusion
18 * in OpenLDAP Software.
26 #include "back-relay.h"
28 #define RB_ERR_MASK (0x0000FFFFU)
29 #define RB_ERR (0x10000000U)
30 #define RB_UNSUPPORTED_FLAG (0x20000000U)
31 #define RB_REFERRAL (0x40000000U)
32 #define RB_SEND (0x80000000U)
33 #define RB_UNSUPPORTED (LDAP_UNWILLING_TO_PERFORM|RB_ERR|RB_UNSUPPORTED_FLAG)
34 #define RB_UNSUPPORTED_SEND (RB_UNSUPPORTED|RB_SEND)
35 #define RB_REFERRAL_SEND (RB_REFERRAL|RB_SEND)
36 #define RB_ERR_SEND (RB_ERR|RB_SEND)
37 #define RB_ERR_REFERRAL_SEND (RB_ERR|RB_REFERRAL|RB_SEND)
40 relay_back_swap_bd( Operation *op, SlapReply *rs )
42 slap_callback *cb = op->o_callback;
43 BackendDB *be = op->o_bd;
45 op->o_bd = cb->sc_private;
48 return SLAP_CB_CONTINUE;
51 #define relay_back_add_cb( cb, op ) \
53 (cb)->sc_next = (op)->o_callback; \
54 (cb)->sc_response = relay_back_swap_bd; \
55 (cb)->sc_cleanup = relay_back_swap_bd; \
56 (cb)->sc_private = (op)->o_bd; \
57 (op)->o_callback = (cb); \
61 * selects the backend if not enforced at config;
62 * in case of failure, behaves based on err:
63 * -1 don't send result
64 * LDAP_SUCCESS don't send result; may send referral if dosend
65 * any valid error send as error result if dosend
68 relay_back_select_backend( Operation *op, SlapReply *rs, slap_mask_t fail_mode )
70 relay_back_info *ri = (relay_back_info *)op->o_bd->be_private;
71 BackendDB *bd = ri->ri_bd;
72 int rc = ( fail_mode & RB_ERR_MASK );
74 if ( bd == NULL && !BER_BVISNULL( &op->o_req_ndn ) ) {
75 bd = select_backend( &op->o_req_ndn, 1 );
76 if ( bd == op->o_bd ) {
77 Debug( LDAP_DEBUG_ANY,
78 "%s: back-relay for DN=\"%s\" would call self.\n",
79 op->o_log_prefix, op->o_req_dn.bv_val, 0 );
80 if ( fail_mode & RB_ERR ) {
82 if ( fail_mode & RB_SEND ) {
83 send_ldap_result( op, rs );
92 if ( ( fail_mode & RB_REFERRAL )
93 && ( fail_mode & RB_SEND )
94 && !BER_BVISNULL( &op->o_req_ndn )
97 rs->sr_err = LDAP_REFERRAL;
99 /* if we set sr_err to LDAP_REFERRAL,
100 * we must provide one */
101 rs->sr_ref = referral_rewrite(
104 LDAP_SCOPE_DEFAULT );
106 rs->sr_ref = default_referral;
109 send_ldap_result( op, rs );
111 if ( rs->sr_ref != default_referral ) {
112 ber_bvarray_free( rs->sr_ref );
118 /* NOTE: err is LDAP_INVALID_CREDENTIALS for bind,
119 * LDAP_NO_SUCH_OBJECT for other operations.
120 * noSuchObject cannot be returned by bind */
122 if ( fail_mode & RB_SEND ) {
123 send_ldap_result( op, rs );
136 slap_mask_t fail_mode )
138 int rc = ( fail_mode & RB_ERR_MASK );
141 BackendDB *be = op->o_bd;
144 relay_back_add_cb( &cb, op );
150 if ( op->o_callback == &cb ) {
151 op->o_callback = op->o_callback->sc_next;
154 } else if ( fail_mode & RB_ERR ) {
156 if ( fail_mode & RB_UNSUPPORTED_FLAG ) {
157 rs->sr_text = "operation not supported within naming context";
160 if ( fail_mode & RB_SEND ) {
161 send_ldap_result( op, rs );
169 relay_back_op_bind( Operation *op, SlapReply *rs )
173 /* allow rootdn as a means to auth without the need to actually
174 * contact the proxied DSA */
175 switch ( be_rootdn_bind( op, rs ) ) {
176 case SLAP_CB_CONTINUE:
183 bd = relay_back_select_backend( op, rs,
184 ( LDAP_INVALID_CREDENTIALS | RB_ERR_SEND ) );
189 return relay_back_op( op, rs, bd, bd->be_bind,
190 ( LDAP_INVALID_CREDENTIALS | RB_ERR_SEND ) );
194 relay_back_op_unbind( Operation *op, SlapReply *rs )
198 bd = relay_back_select_backend( op, rs, 0 );
200 (void)relay_back_op( op, rs, bd, bd->be_unbind, 0 );
207 relay_back_op_search( Operation *op, SlapReply *rs )
211 bd = relay_back_select_backend( op, rs,
212 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
217 return relay_back_op( op, rs, bd, bd->be_search,
218 RB_UNSUPPORTED_SEND );
222 relay_back_op_compare( Operation *op, SlapReply *rs )
226 bd = relay_back_select_backend( op, rs,
227 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
232 return relay_back_op( op, rs, bd, bd->be_compare,
233 ( SLAP_CB_CONTINUE | RB_ERR ) );
237 relay_back_op_modify( Operation *op, SlapReply *rs )
241 bd = relay_back_select_backend( op, rs,
242 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
247 return relay_back_op( op, rs, bd, bd->be_modify,
248 RB_UNSUPPORTED_SEND );
252 relay_back_op_modrdn( Operation *op, SlapReply *rs )
256 bd = relay_back_select_backend( op, rs,
257 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
262 return relay_back_op( op, rs, bd, bd->be_modrdn,
263 RB_UNSUPPORTED_SEND );
267 relay_back_op_add( Operation *op, SlapReply *rs )
271 bd = relay_back_select_backend( op, rs,
272 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
277 return relay_back_op( op, rs, bd, bd->be_add,
278 RB_UNSUPPORTED_SEND );
282 relay_back_op_delete( Operation *op, SlapReply *rs )
286 bd = relay_back_select_backend( op, rs,
287 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
292 return relay_back_op( op, rs, bd, bd->be_delete,
293 RB_UNSUPPORTED_SEND );
297 relay_back_op_abandon( Operation *op, SlapReply *rs )
301 bd = relay_back_select_backend( op, rs, 0 );
306 return relay_back_op( op, rs, bd, bd->be_abandon, 0 );
310 relay_back_op_cancel( Operation *op, SlapReply *rs )
315 bd = relay_back_select_backend( op, rs,
316 ( LDAP_CANNOT_CANCEL | RB_ERR ) );
318 if ( op->o_cancel == SLAP_CANCEL_REQ ) {
319 op->o_cancel = LDAP_CANNOT_CANCEL;
324 rc = relay_back_op( op, rs, bd, bd->be_cancel,
325 ( LDAP_CANNOT_CANCEL | RB_ERR ) );
326 if ( rc == LDAP_CANNOT_CANCEL && op->o_cancel == SLAP_CANCEL_REQ )
328 op->o_cancel = LDAP_CANNOT_CANCEL;
335 relay_back_op_extended( Operation *op, SlapReply *rs )
339 bd = relay_back_select_backend( op, rs,
340 ( LDAP_NO_SUCH_OBJECT | RB_ERR | RB_REFERRAL ) );
345 return relay_back_op( op, rs, bd, bd->be_extended,
350 relay_back_entry_release_rw( Operation *op, Entry *e, int rw )
352 relay_back_info *ri = (relay_back_info *)op->o_bd->be_private;
358 bd = select_backend( &op->o_req_ndn, 1 );
364 if ( bd->be_release ) {
365 BackendDB *be = op->o_bd;
368 rc = bd->be_release( op, e, rw );
377 relay_back_entry_get_rw( Operation *op, struct berval *ndn,
378 ObjectClass *oc, AttributeDescription *at, int rw, Entry **e )
380 relay_back_info *ri = (relay_back_info *)op->o_bd->be_private;
386 bd = select_backend( &op->o_req_ndn, 1 );
392 if ( bd->be_fetch ) {
393 BackendDB *be = op->o_bd;
396 rc = bd->be_fetch( op, ndn, oc, at, rw, e );
405 * NOTE: even the existence of this function is questionable: we cannot
406 * pass the bi_chk_referrals() call thru the rwm overlay because there
407 * is no way to rewrite the req_dn back; but then relay_back_chk_referrals()
408 * is passing the target database a DN that likely does not belong to its
409 * naming context... mmmh.
412 relay_back_chk_referrals( Operation *op, SlapReply *rs )
416 bd = relay_back_select_backend( op, rs,
417 ( LDAP_SUCCESS | RB_ERR_REFERRAL_SEND ) );
418 /* FIXME: this test only works if there are no overlays, so
419 * it is nearly useless; if made stricter, no nested back-relays
420 * can be instantiated... too bad. */
421 if ( bd == NULL || bd == op->o_bd ) {
425 /* no nested back-relays... */
426 if ( overlay_is_over( bd ) ) {
427 slap_overinfo *oi = (slap_overinfo *)bd->bd_info->bi_private;
429 if ( oi->oi_orig == op->o_bd->bd_info ) {
434 return relay_back_op( op, rs, bd, bd->be_chk_referrals, 0 );
438 relay_back_operational( Operation *op, SlapReply *rs )
442 bd = relay_back_select_backend( op, rs,
443 ( LDAP_SUCCESS | RB_ERR ) );
444 /* FIXME: this test only works if there are no overlays, so
445 * it is nearly useless; if made stricter, no nested back-relays
446 * can be instantiated... too bad. */
447 if ( bd == NULL || bd == op->o_bd ) {
451 return relay_back_op( op, rs, bd, bd->be_operational, 0 );
455 relay_back_has_subordinates( Operation *op, Entry *e, int *hasSubs )
457 SlapReply rs = { 0 };
461 bd = relay_back_select_backend( op, &rs,
462 ( LDAP_SUCCESS | RB_ERR ) );
463 /* FIXME: this test only works if there are no overlays, so
464 * it is nearly useless; if made stricter, no nested back-relays
465 * can be instantiated... too bad. */
466 if ( bd == NULL || bd == op->o_bd ) {
470 if ( bd->be_has_subordinates ) {
471 BackendDB *be = op->o_bd;
474 rc = bd->be_has_subordinates( op, e, hasSubs );
483 relay_back_connection_init( BackendDB *bd, Connection *c )
485 relay_back_info *ri = (relay_back_info *)bd->be_private;
492 if ( bd->be_connection_init ) {
493 return bd->be_connection_init( bd, c );
500 relay_back_connection_destroy( BackendDB *bd, Connection *c )
502 relay_back_info *ri = (relay_back_info *)bd->be_private;
509 if ( bd->be_connection_destroy ) {
510 return bd->be_connection_destroy( bd, c );
518 * FIXME: must implement tools as well