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