1 /* op.c - relay backend operations */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/back-relay/op.c,v 1.15.2.6 2008/02/12 01:03:16 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2004-2008 The OpenLDAP Foundation.
6 * Portions Copyright 2004 Pierangelo Masarati.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This work was initially developed by Pierangelo Masarati for inclusion
19 * in OpenLDAP Software.
27 #include "back-relay.h"
29 #define RB_ERR_MASK (0x0000FFFFU)
30 #define RB_ERR (0x10000000U)
31 #define RB_UNSUPPORTED_FLAG (0x20000000U)
32 #define RB_REFERRAL (0x40000000U)
33 #define RB_SEND (0x80000000U)
34 #define RB_UNSUPPORTED (LDAP_UNWILLING_TO_PERFORM|RB_ERR|RB_UNSUPPORTED_FLAG)
35 #define RB_UNSUPPORTED_SEND (RB_UNSUPPORTED|RB_SEND)
36 #define RB_REFERRAL_SEND (RB_REFERRAL|RB_SEND)
37 #define RB_ERR_SEND (RB_ERR|RB_SEND)
38 #define RB_ERR_REFERRAL_SEND (RB_ERR|RB_REFERRAL|RB_SEND)
41 relay_back_swap_bd( Operation
*op
, SlapReply
*rs
)
43 slap_callback
*cb
= op
->o_callback
;
44 BackendDB
*be
= op
->o_bd
;
46 op
->o_bd
= cb
->sc_private
;
49 return SLAP_CB_CONTINUE
;
52 #define relay_back_add_cb( cb, op ) \
54 (cb)->sc_next = (op)->o_callback; \
55 (cb)->sc_response = relay_back_swap_bd; \
56 (cb)->sc_cleanup = relay_back_swap_bd; \
57 (cb)->sc_private = (op)->o_bd; \
58 (op)->o_callback = (cb); \
62 * selects the backend if not enforced at config;
63 * in case of failure, behaves based on err:
64 * -1 don't send result
65 * LDAP_SUCCESS don't send result; may send referral if dosend
66 * any valid error send as error result if dosend
69 relay_back_select_backend( Operation
*op
, SlapReply
*rs
, slap_mask_t fail_mode
)
71 relay_back_info
*ri
= (relay_back_info
*)op
->o_bd
->be_private
;
72 BackendDB
*bd
= ri
->ri_bd
;
73 int rc
= ( fail_mode
& RB_ERR_MASK
);
75 if ( bd
== NULL
&& !BER_BVISNULL( &op
->o_req_ndn
) ) {
76 bd
= select_backend( &op
->o_req_ndn
, 1 );
77 if ( bd
== op
->o_bd
) {
78 Debug( LDAP_DEBUG_ANY
,
79 "%s: back-relay for DN=\"%s\" would call self.\n",
80 op
->o_log_prefix
, op
->o_req_dn
.bv_val
, 0 );
81 if ( fail_mode
& RB_ERR
) {
83 if ( fail_mode
& RB_SEND
) {
84 send_ldap_result( op
, rs
);
93 if ( ( fail_mode
& RB_REFERRAL
)
94 && ( fail_mode
& RB_SEND
)
95 && !BER_BVISNULL( &op
->o_req_ndn
)
98 rs
->sr_err
= LDAP_REFERRAL
;
100 /* if we set sr_err to LDAP_REFERRAL,
101 * we must provide one */
102 rs
->sr_ref
= referral_rewrite(
105 LDAP_SCOPE_DEFAULT
);
107 rs
->sr_ref
= default_referral
;
110 send_ldap_result( op
, rs
);
112 if ( rs
->sr_ref
!= default_referral
) {
113 ber_bvarray_free( rs
->sr_ref
);
119 /* NOTE: err is LDAP_INVALID_CREDENTIALS for bind,
120 * LDAP_NO_SUCH_OBJECT for other operations.
121 * noSuchObject cannot be returned by bind */
123 if ( fail_mode
& RB_SEND
) {
124 send_ldap_result( op
, rs
);
137 slap_mask_t fail_mode
)
139 int rc
= ( fail_mode
& RB_ERR_MASK
);
142 BackendDB
*be
= op
->o_bd
;
145 relay_back_add_cb( &cb
, op
);
151 if ( op
->o_callback
== &cb
) {
152 op
->o_callback
= op
->o_callback
->sc_next
;
155 } else if ( fail_mode
& RB_ERR
) {
157 if ( fail_mode
& RB_UNSUPPORTED_FLAG
) {
158 rs
->sr_text
= "operation not supported within naming context";
161 if ( fail_mode
& RB_SEND
) {
162 send_ldap_result( op
, rs
);
170 relay_back_op_bind( Operation
*op
, SlapReply
*rs
)
174 /* allow rootdn as a means to auth without the need to actually
175 * contact the proxied DSA */
176 switch ( be_rootdn_bind( op
, rs
) ) {
177 case SLAP_CB_CONTINUE
:
184 bd
= relay_back_select_backend( op
, rs
,
185 ( LDAP_INVALID_CREDENTIALS
| RB_ERR_SEND
) );
190 return relay_back_op( op
, rs
, bd
, bd
->be_bind
,
191 ( LDAP_INVALID_CREDENTIALS
| RB_ERR_SEND
) );
195 relay_back_op_unbind( Operation
*op
, SlapReply
*rs
)
199 bd
= relay_back_select_backend( op
, rs
, 0 );
201 (void)relay_back_op( op
, rs
, bd
, bd
->be_unbind
, 0 );
208 relay_back_op_search( Operation
*op
, SlapReply
*rs
)
212 bd
= relay_back_select_backend( op
, rs
,
213 ( LDAP_NO_SUCH_OBJECT
| RB_ERR_REFERRAL_SEND
) );
218 return relay_back_op( op
, rs
, bd
, bd
->be_search
,
219 RB_UNSUPPORTED_SEND
);
223 relay_back_op_compare( Operation
*op
, SlapReply
*rs
)
227 bd
= relay_back_select_backend( op
, rs
,
228 ( LDAP_NO_SUCH_OBJECT
| RB_ERR_REFERRAL_SEND
) );
233 return relay_back_op( op
, rs
, bd
, bd
->be_compare
,
234 ( SLAP_CB_CONTINUE
| RB_ERR
) );
238 relay_back_op_modify( Operation
*op
, SlapReply
*rs
)
242 bd
= relay_back_select_backend( op
, rs
,
243 ( LDAP_NO_SUCH_OBJECT
| RB_ERR_REFERRAL_SEND
) );
248 return relay_back_op( op
, rs
, bd
, bd
->be_modify
,
249 RB_UNSUPPORTED_SEND
);
253 relay_back_op_modrdn( Operation
*op
, SlapReply
*rs
)
257 bd
= relay_back_select_backend( op
, rs
,
258 ( LDAP_NO_SUCH_OBJECT
| RB_ERR_REFERRAL_SEND
) );
263 return relay_back_op( op
, rs
, bd
, bd
->be_modrdn
,
264 RB_UNSUPPORTED_SEND
);
268 relay_back_op_add( Operation
*op
, SlapReply
*rs
)
272 bd
= relay_back_select_backend( op
, rs
,
273 ( LDAP_NO_SUCH_OBJECT
| RB_ERR_REFERRAL_SEND
) );
278 return relay_back_op( op
, rs
, bd
, bd
->be_add
,
279 RB_UNSUPPORTED_SEND
);
283 relay_back_op_delete( Operation
*op
, SlapReply
*rs
)
287 bd
= relay_back_select_backend( op
, rs
,
288 ( LDAP_NO_SUCH_OBJECT
| RB_ERR_REFERRAL_SEND
) );
293 return relay_back_op( op
, rs
, bd
, bd
->be_delete
,
294 RB_UNSUPPORTED_SEND
);
298 relay_back_op_abandon( Operation
*op
, SlapReply
*rs
)
302 bd
= relay_back_select_backend( op
, rs
, 0 );
307 return relay_back_op( op
, rs
, bd
, bd
->be_abandon
, 0 );
311 relay_back_op_cancel( Operation
*op
, SlapReply
*rs
)
316 bd
= relay_back_select_backend( op
, rs
,
317 ( LDAP_CANNOT_CANCEL
| RB_ERR
) );
319 if ( op
->o_cancel
== SLAP_CANCEL_REQ
) {
320 op
->o_cancel
= LDAP_CANNOT_CANCEL
;
325 rc
= relay_back_op( op
, rs
, bd
, bd
->be_cancel
,
326 ( LDAP_CANNOT_CANCEL
| RB_ERR
) );
327 if ( rc
== LDAP_CANNOT_CANCEL
&& op
->o_cancel
== SLAP_CANCEL_REQ
)
329 op
->o_cancel
= LDAP_CANNOT_CANCEL
;
336 relay_back_op_extended( Operation
*op
, SlapReply
*rs
)
340 bd
= relay_back_select_backend( op
, rs
,
341 ( LDAP_NO_SUCH_OBJECT
| RB_ERR
| RB_REFERRAL
) );
346 return relay_back_op( op
, rs
, bd
, bd
->be_extended
,
351 relay_back_entry_release_rw( Operation
*op
, Entry
*e
, int rw
)
353 relay_back_info
*ri
= (relay_back_info
*)op
->o_bd
->be_private
;
359 bd
= select_backend( &op
->o_req_ndn
, 1 );
365 if ( bd
->be_release
) {
366 BackendDB
*be
= op
->o_bd
;
369 rc
= bd
->be_release( op
, e
, rw
);
378 relay_back_entry_get_rw( Operation
*op
, struct berval
*ndn
,
379 ObjectClass
*oc
, AttributeDescription
*at
, int rw
, Entry
**e
)
381 relay_back_info
*ri
= (relay_back_info
*)op
->o_bd
->be_private
;
387 bd
= select_backend( &op
->o_req_ndn
, 1 );
393 if ( bd
->be_fetch
) {
394 BackendDB
*be
= op
->o_bd
;
397 rc
= bd
->be_fetch( op
, ndn
, oc
, at
, rw
, e
);
406 * NOTE: even the existence of this function is questionable: we cannot
407 * pass the bi_chk_referrals() call thru the rwm overlay because there
408 * is no way to rewrite the req_dn back; but then relay_back_chk_referrals()
409 * is passing the target database a DN that likely does not belong to its
410 * naming context... mmmh.
413 relay_back_chk_referrals( Operation
*op
, SlapReply
*rs
)
417 bd
= relay_back_select_backend( op
, rs
,
418 ( LDAP_SUCCESS
| RB_ERR_REFERRAL_SEND
) );
419 /* FIXME: this test only works if there are no overlays, so
420 * it is nearly useless; if made stricter, no nested back-relays
421 * can be instantiated... too bad. */
422 if ( bd
== NULL
|| bd
== op
->o_bd
) {
426 /* no nested back-relays... */
427 if ( overlay_is_over( bd
) ) {
428 slap_overinfo
*oi
= (slap_overinfo
*)bd
->bd_info
->bi_private
;
430 if ( oi
->oi_orig
== op
->o_bd
->bd_info
) {
435 return relay_back_op( op
, rs
, bd
, bd
->be_chk_referrals
, LDAP_SUCCESS
);
439 relay_back_operational( Operation
*op
, SlapReply
*rs
)
443 bd
= relay_back_select_backend( op
, rs
,
444 ( LDAP_SUCCESS
| RB_ERR
) );
445 /* FIXME: this test only works if there are no overlays, so
446 * it is nearly useless; if made stricter, no nested back-relays
447 * can be instantiated... too bad. */
448 if ( bd
== NULL
|| bd
== op
->o_bd
) {
452 return relay_back_op( op
, rs
, bd
, bd
->be_operational
, 0 );
456 relay_back_has_subordinates( Operation
*op
, Entry
*e
, int *hasSubs
)
458 SlapReply rs
= { 0 };
462 bd
= relay_back_select_backend( op
, &rs
,
463 ( LDAP_SUCCESS
| RB_ERR
) );
464 /* FIXME: this test only works if there are no overlays, so
465 * it is nearly useless; if made stricter, no nested back-relays
466 * can be instantiated... too bad. */
467 if ( bd
== NULL
|| bd
== op
->o_bd
) {
471 if ( bd
->be_has_subordinates
) {
472 BackendDB
*be
= op
->o_bd
;
475 rc
= bd
->be_has_subordinates( op
, e
, hasSubs
);
484 relay_back_connection_init( BackendDB
*bd
, Connection
*c
)
486 relay_back_info
*ri
= (relay_back_info
*)bd
->be_private
;
493 if ( bd
->be_connection_init
) {
494 return bd
->be_connection_init( bd
, c
);
501 relay_back_connection_destroy( BackendDB
*bd
, Connection
*c
)
503 relay_back_info
*ri
= (relay_back_info
*)bd
->be_private
;
510 if ( bd
->be_connection_destroy
) {
511 return bd
->be_connection_destroy( bd
, c
);
519 * FIXME: must implement tools as well