]> git.sur5r.net Git - openldap/blob - servers/slapd/back-relay/op.c
Drop Unbind too for ITS#6133. Some cleanup. Add/fix comments.
[openldap] / servers / slapd / back-relay / op.c
1 /* op.c - relay backend operations */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2004-2009 The OpenLDAP Foundation.
6  * Portions Copyright 2004 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
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>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25
26 #include "slap.h"
27 #include "back-relay.h"
28
29 /* Flags for handling result codes and failures */
30 #define RB_ERR_MASK             (0x0000FFFFU)
31 #define RB_ERR                  (0x10000000U)
32 #define RB_UNSUPPORTED_FLAG     (0x20000000U)
33 #define RB_REFERRAL             (0x40000000U)
34 #define RB_SEND                 (0x80000000U)
35 #define RB_UNSUPPORTED          (LDAP_UNWILLING_TO_PERFORM|RB_ERR|RB_UNSUPPORTED_FLAG)
36 #define RB_UNSUPPORTED_SEND     (RB_UNSUPPORTED|RB_SEND)
37 #define RB_REFERRAL_SEND        (RB_REFERRAL|RB_SEND)
38 #define RB_ERR_SEND             (RB_ERR|RB_SEND)
39 #define RB_ERR_REFERRAL_SEND    (RB_ERR|RB_REFERRAL|RB_SEND)
40
41 /*
42  * Callbacks: Caller set op->o_bd to underlying BackendDB and sc_private
43  * to Relay BackendDB. sc_response swaps them, sc_cleanup swaps them back.
44  */
45 static int
46 relay_back_swap_bd( Operation *op, SlapReply *rs )
47 {
48         slap_callback   *cb = op->o_callback;
49         BackendDB       *be = op->o_bd;
50
51         op->o_bd = cb->sc_private;
52         cb->sc_private = be;
53
54         return SLAP_CB_CONTINUE;
55 }
56
57 #define relay_back_add_cb( cb, op ) \
58         {                                               \
59                 (cb)->sc_next = (op)->o_callback;       \
60                 (cb)->sc_response = relay_back_swap_bd; \
61                 (cb)->sc_cleanup = relay_back_swap_bd;  \
62                 (cb)->sc_private = (op)->o_bd;          \
63                 (op)->o_callback = (cb);                \
64         }
65
66 /*
67  * Select the backend database for the operation.  On failure, consult
68  * fail_mode for whether to set/send send a referral or error.
69  */
70 static BackendDB *
71 relay_back_select_backend( Operation *op, SlapReply *rs, slap_mask_t fail_mode )
72 {
73         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
74         BackendDB               *bd = ri->ri_bd;
75         int                     rc = ( fail_mode & RB_ERR_MASK );
76
77         if ( bd == NULL && !BER_BVISNULL( &op->o_req_ndn ) ) {
78                 bd = select_backend( &op->o_req_ndn, 1 );
79         }
80
81         if ( bd != NULL ) {
82                         if ( bd->be_private != op->o_bd->be_private ) {
83                                 return bd;
84                         }
85
86                         Debug( LDAP_DEBUG_ANY,
87                                 "%s: back-relay for DN=\"%s\" would call self.\n",
88                                 op->o_log_prefix, op->o_req_dn.bv_val, 0 );
89
90         } else if ( ( fail_mode & RB_REFERRAL_SEND ) == RB_REFERRAL_SEND
91                         && !BER_BVISNULL( &op->o_req_ndn )
92                         && default_referral )
93         {
94                         rs->sr_err = LDAP_REFERRAL;
95
96                         /* if we set sr_err to LDAP_REFERRAL,
97                          * we must provide one */
98                         rs->sr_ref = referral_rewrite(
99                                 default_referral,
100                                 NULL, &op->o_req_dn,
101                                 LDAP_SCOPE_DEFAULT );
102                         if ( !rs->sr_ref ) {
103                                 rs->sr_ref = default_referral;
104                         }
105
106                         send_ldap_result( op, rs );
107
108                         if ( rs->sr_ref != default_referral ) {
109                                 ber_bvarray_free( rs->sr_ref );
110                         }
111
112                         return NULL;
113         }
114
115         if ( fail_mode & RB_ERR ) {
116                 rs->sr_err = rc;
117                 if ( fail_mode & RB_SEND ) {
118                         send_ldap_result( op, rs );
119                 }
120         }
121
122         return NULL;
123 }
124
125 /*
126  * Call operation handler func(op,rs) with op->o_bd = bd,
127  * or if func==0 set/send results depending on fail_mode.
128  */
129 static int
130 relay_back_op(
131         Operation       *op,
132         SlapReply       *rs,
133         BackendDB       *bd,
134         BI_op_func      *func,
135         slap_mask_t     fail_mode )
136 {
137         int                     rc = ( fail_mode & RB_ERR_MASK );
138
139         if ( func ) {
140                 BackendDB       *be = op->o_bd;
141                 slap_callback   cb;
142
143                 relay_back_add_cb( &cb, op );
144
145                 op->o_bd = bd;
146                 rc = func( op, rs );
147                 op->o_bd = be;
148
149                 if ( op->o_callback == &cb ) {
150                         op->o_callback = op->o_callback->sc_next;
151                 }
152
153         } else if ( fail_mode & RB_ERR ) {
154                 rs->sr_err = rc;
155                 if ( fail_mode & RB_UNSUPPORTED_FLAG ) {
156                         rs->sr_text = "operation not supported within naming context";
157                 }
158
159                 if ( fail_mode & RB_SEND ) {
160                         send_ldap_result( op, rs );
161                 }
162         }
163
164         return rc;
165 }
166
167 int
168 relay_back_op_bind( Operation *op, SlapReply *rs )
169 {
170         BackendDB       *bd;
171
172         /* allow rootdn as a means to auth without the need to actually
173          * contact the proxied DSA */
174         switch ( be_rootdn_bind( op, rs ) ) {
175         case SLAP_CB_CONTINUE:
176                 break;
177
178         default:
179                 return rs->sr_err;
180         }
181
182         bd = relay_back_select_backend( op, rs,
183                 ( LDAP_INVALID_CREDENTIALS | RB_ERR_SEND ) );
184         if ( bd == NULL ) {
185                 return rs->sr_err;
186         }
187
188         return relay_back_op( op, rs, bd, bd->be_bind,
189                 ( LDAP_INVALID_CREDENTIALS | RB_ERR_SEND ) );
190 }
191
192 #if 0 /* Should not exist - see ITS#6133 */
193 int
194 relay_back_op_unbind( Operation *op, SlapReply *rs )
195 {
196         BackendDB               *bd;
197
198         bd = relay_back_select_backend( op, rs, 0 );
199         if ( bd != NULL ) {
200                 (void)relay_back_op( op, rs, bd, bd->be_unbind, 0 );
201         }
202
203         return 0;
204 }
205 #endif /*0*/
206
207 int
208 relay_back_op_search( Operation *op, SlapReply *rs )
209 {
210         BackendDB               *bd;
211
212         bd = relay_back_select_backend( op, rs,
213                 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
214         if ( bd == NULL ) {
215                 return rs->sr_err;
216         }
217
218         return relay_back_op( op, rs, bd, bd->be_search,
219                 RB_UNSUPPORTED_SEND );
220 }
221
222 int
223 relay_back_op_compare( Operation *op, SlapReply *rs )
224 {
225         BackendDB               *bd;
226
227         bd = relay_back_select_backend( op, rs,
228                 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
229         if ( bd == NULL ) {
230                 return rs->sr_err;
231         }
232
233         return relay_back_op( op, rs, bd, bd->be_compare,
234                 ( SLAP_CB_CONTINUE | RB_ERR ) );
235 }
236
237 int
238 relay_back_op_modify( Operation *op, SlapReply *rs )
239 {
240         BackendDB               *bd;
241
242         bd = relay_back_select_backend( op, rs,
243                 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
244         if ( bd == NULL ) {
245                 return rs->sr_err;
246         }
247
248         return relay_back_op( op, rs, bd, bd->be_modify,
249                 RB_UNSUPPORTED_SEND );
250 }
251
252 int
253 relay_back_op_modrdn( Operation *op, SlapReply *rs )
254 {
255         BackendDB               *bd;
256
257         bd = relay_back_select_backend( op, rs,
258                 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
259         if ( bd == NULL ) {
260                 return rs->sr_err;
261         }
262
263         return relay_back_op( op, rs, bd, bd->be_modrdn,
264                 RB_UNSUPPORTED_SEND );
265 }
266
267 int
268 relay_back_op_add( Operation *op, SlapReply *rs )
269 {
270         BackendDB               *bd;
271
272         bd = relay_back_select_backend( op, rs,
273                 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
274         if ( bd == NULL ) {
275                 return rs->sr_err;
276         }
277
278         return relay_back_op( op, rs, bd, bd->be_add,
279                 RB_UNSUPPORTED_SEND );
280 }
281
282 int
283 relay_back_op_delete( Operation *op, SlapReply *rs )
284 {
285         BackendDB               *bd;
286
287         bd = relay_back_select_backend( op, rs,
288                 ( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
289         if ( bd == NULL ) {
290                 return rs->sr_err;
291         }
292
293         return relay_back_op( op, rs, bd, bd->be_delete,
294                 RB_UNSUPPORTED_SEND );
295 }
296
297 #if 0 /* Should not exist - see ITS#6133 */
298 int
299 relay_back_op_abandon( Operation *op, SlapReply *rs )
300 {
301         BackendDB               *bd;
302
303         bd = relay_back_select_backend( op, rs, 0 );
304         if ( bd == NULL ) {
305                 return rs->sr_err;
306         }
307
308         return relay_back_op( op, rs, bd, bd->be_abandon, 0 );
309 }
310
311 int
312 relay_back_op_cancel( Operation *op, SlapReply *rs )
313 {
314         BackendDB               *bd;
315         int                     rc;
316
317         bd = relay_back_select_backend( op, rs,
318                 ( LDAP_CANNOT_CANCEL | RB_ERR ) );
319         if ( bd == NULL ) {
320                 if ( op->o_cancel == SLAP_CANCEL_REQ ) {
321                         op->o_cancel = LDAP_CANNOT_CANCEL;
322                 }
323                 return rs->sr_err;
324         }
325
326         rc = relay_back_op( op, rs, bd, bd->be_cancel,
327                 ( LDAP_CANNOT_CANCEL | RB_ERR ) );
328         if ( rc == LDAP_CANNOT_CANCEL && op->o_cancel == SLAP_CANCEL_REQ )
329         {
330                 op->o_cancel = LDAP_CANNOT_CANCEL;
331         }
332
333         return rc;
334 }
335 #endif /*0*/
336
337 int
338 relay_back_op_extended( Operation *op, SlapReply *rs )
339 {
340         BackendDB               *bd;
341
342         bd = relay_back_select_backend( op, rs,
343                 ( LDAP_NO_SUCH_OBJECT | RB_ERR | RB_REFERRAL ) );
344         if ( bd == NULL ) {
345                 return rs->sr_err;
346         }
347
348         return relay_back_op( op, rs, bd, bd->be_extended,
349                 RB_UNSUPPORTED );
350 }
351
352 int
353 relay_back_entry_release_rw( Operation *op, Entry *e, int rw )
354 {
355         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
356         BackendDB               *bd;
357         int                     rc = 1;
358
359         bd = ri->ri_bd;
360         if ( bd == NULL) {
361                 bd = select_backend( &op->o_req_ndn, 1 );
362                 if ( bd == NULL ) {
363                         return 1;
364                 }
365         }
366
367         if ( bd->be_release ) {
368                 BackendDB       *be = op->o_bd;
369
370                 op->o_bd = bd;
371                 rc = bd->be_release( op, e, rw );
372                 op->o_bd = be;
373         }
374
375         return rc;
376 }
377
378 int
379 relay_back_entry_get_rw( Operation *op, struct berval *ndn,
380         ObjectClass *oc, AttributeDescription *at, int rw, Entry **e )
381 {
382         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
383         BackendDB               *bd;
384         int                     rc = 1;
385
386         bd = ri->ri_bd;
387         if ( bd == NULL) {
388                 bd = select_backend( &op->o_req_ndn, 1 );
389                 if ( bd == NULL ) {
390                         return 1;
391                 }
392         }
393
394         if ( bd->be_fetch ) {
395                 BackendDB       *be = op->o_bd;
396
397                 op->o_bd = bd;
398                 rc = bd->be_fetch( op, ndn, oc, at, rw, e );
399                 op->o_bd = be;
400         }
401
402         return rc;
403 }
404
405 #if 0
406 /*
407  * NOTE: even the existence of this function is questionable: we cannot
408  * pass the bi_chk_referrals() call thru the rwm overlay because there
409  * is no way to rewrite the req_dn back; but then relay_back_chk_referrals()
410  * is passing the target database a DN that likely does not belong to its
411  * naming context... mmmh.
412  */
413 int
414 relay_back_chk_referrals( Operation *op, SlapReply *rs )
415 {
416         BackendDB               *bd;
417
418         /* FIXME: Can send success on failure. Should send referral or nothing. */
419         bd = relay_back_select_backend( op, rs,
420                 ( LDAP_SUCCESS | RB_ERR_REFERRAL_SEND ) );
421         /* FIXME: this test only works if there are no overlays, so
422          * it is nearly useless; if made stricter, no nested back-relays
423          * can be instantiated... too bad. */
424         if ( bd == NULL || bd == op->o_bd ) {
425                 return 0;
426         }
427
428         /* no nested back-relays... */
429         if ( overlay_is_over( bd ) ) {
430                 slap_overinfo   *oi = (slap_overinfo *)bd->bd_info->bi_private;
431
432                 if ( oi->oi_orig == op->o_bd->bd_info ) {
433                         return 0;
434                 }
435         }
436
437         return relay_back_op( op, rs, bd, bd->be_chk_referrals, LDAP_SUCCESS );
438 }
439 #endif /*0*/
440
441 int
442 relay_back_operational( Operation *op, SlapReply *rs )
443 {
444         BackendDB               *bd;
445
446         bd = relay_back_select_backend( op, rs, LDAP_SUCCESS );
447         /* FIXME: this test only works if there are no overlays, so
448          * it is nearly useless; if made stricter, no nested back-relays
449          * can be instantiated... too bad. */
450         if ( bd == NULL || bd == op->o_bd ) {
451                 return LDAP_SUCCESS;
452         }
453
454         return relay_back_op( op, rs, bd, bd->be_operational, LDAP_SUCCESS );
455 }
456
457 int
458 relay_back_has_subordinates( Operation *op, Entry *e, int *hasSubs )
459 {
460         BackendDB               *bd;
461         int                     rc = LDAP_OTHER;
462
463         bd = relay_back_select_backend( op, NULL, 0 );
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 ) {
468                 return LDAP_OTHER;
469         }
470
471         if ( bd->be_has_subordinates ) {
472                 BackendDB       *be = op->o_bd;
473
474                 op->o_bd = bd;
475                 rc = bd->be_has_subordinates( op, e, hasSubs );
476                 op->o_bd = be;
477         }
478
479         return rc;
480 }
481
482 #if 0 /* Should not exist - see ITS#6133 */
483 int
484 relay_back_connection_init( BackendDB *bd, Connection *c )
485 {
486         relay_back_info         *ri = (relay_back_info *)bd->be_private;
487
488         bd = ri->ri_bd;
489         if ( bd == NULL ) {
490                 return 0;
491         }
492
493         if ( bd->be_connection_init ) {
494                 return bd->be_connection_init( bd, c );
495         }
496
497         return 0;
498 }
499
500 int
501 relay_back_connection_destroy( BackendDB *bd, Connection *c )
502 {
503         relay_back_info         *ri = (relay_back_info *)bd->be_private;
504
505         bd = ri->ri_bd;
506         if ( bd == NULL ) {
507                 return 0;
508         }
509
510         if ( bd->be_connection_destroy ) {
511                 return bd->be_connection_destroy( bd, c );
512         }
513
514         return 0;
515
516 }
517 #endif /*0*/
518
519 /*
520  * Handlers that slapd calls for all databases are not set, as slapd
521  * would then call them twice for the underlying database:  Abandon,
522  * Cancel, Unbind and non-Operation handlers like be_connection_init.
523  */
524
525 /*
526  * FIXME: must implement tools as well
527  */