]> git.sur5r.net Git - openldap/blob - servers/slapd/back-relay/op.c
More ITS#5328 cleanup
[openldap] / servers / slapd / back-relay / op.c
1 /* op.c - relay backend operations */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2004-2008 The OpenLDAP Foundation.
5  * Portions Copyright 2004 Pierangelo Masarati.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
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>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by Pierangelo Masarati for inclusion
18  * in OpenLDAP Software.
19  */
20
21 #include "portable.h"
22
23 #include <stdio.h>
24
25 #include "slap.h"
26 #include "back-relay.h"
27
28 #define RB_ERR_MASK             (0x00FFU)
29 #define RB_ERR                  (0x1000U)
30 #define RB_UNSUPPORTED_FLAG     (0x2000U)
31 #define RB_REFERRAL             (0x4000U)
32 #define RB_SEND                 (0x8000U)
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
38 static int
39 relay_back_swap_bd( Operation *op, SlapReply *rs )
40 {
41         slap_callback   *cb = op->o_callback;
42         BackendDB       *be = op->o_bd;
43
44         op->o_bd = cb->sc_private;
45         cb->sc_private = be;
46
47         return SLAP_CB_CONTINUE;
48 }
49
50 #define relay_back_add_cb( cb, op ) \
51         {                                               \
52                 (cb)->sc_next = (op)->o_callback;       \
53                 (cb)->sc_response = relay_back_swap_bd; \
54                 (cb)->sc_cleanup = relay_back_swap_bd;  \
55                 (cb)->sc_private = (op)->o_bd;          \
56                 (op)->o_callback = (cb);                \
57         }
58
59 /*
60  * selects the backend if not enforced at config;
61  * in case of failure, behaves based on err:
62  *      -1                      don't send result
63  *      LDAP_SUCCESS            don't send result; may send referral if dosend
64  *      any valid error         send as error result if dosend
65  */
66 static BackendDB *
67 relay_back_select_backend( Operation *op, SlapReply *rs, slap_mask_t fail_mode )
68 {
69         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
70         BackendDB               *bd = ri->ri_bd;
71         int                     rc = ( fail_mode & RB_ERR_MASK );
72
73         if ( bd == NULL && !BER_BVISNULL( &op->o_req_ndn ) ) {
74                 bd = select_backend( &op->o_req_ndn, 1 );
75                 if ( bd == op->o_bd ) {
76                         Debug( LDAP_DEBUG_ANY,
77                                 "%s: back-relay for DN=\"%s\" would call self.\n",
78                                 op->o_log_prefix, op->o_req_dn.bv_val, 0 );
79                         if ( fail_mode & RB_ERR ) {
80                                 rs->sr_err = rc;
81                                 if ( fail_mode & RB_SEND ) {
82                                         send_ldap_result( op, rs );
83                                 }
84                         }
85
86                         return NULL;
87                 }
88         }
89
90         if ( bd == NULL && fail_mode & RB_REFERRAL ) {
91                 if ( default_referral ) {
92                         rs->sr_err = LDAP_REFERRAL;
93                         if ( fail_mode & RB_SEND ) {
94                                 rs->sr_ref = referral_rewrite(
95                                         default_referral,
96                                         NULL, &op->o_req_dn,
97                                         LDAP_SCOPE_DEFAULT );
98                                 if ( !rs->sr_ref ) {
99                                         rs->sr_ref = default_referral;
100                                 }
101
102                                 send_ldap_result( op, rs );
103
104                                 if ( rs->sr_ref != default_referral ) {
105                                         ber_bvarray_free( rs->sr_ref );
106                                 }
107                         }
108
109                 } else {
110                         /* NOTE: err is LDAP_INVALID_CREDENTIALS for bind,
111                          * LDAP_NO_SUCH_OBJECT for other operations.
112                          * noSuchObject cannot be returned by bind */
113                         rs->sr_err = rc;
114                         if ( fail_mode & RB_SEND ) {
115                                 send_ldap_result( op, rs );
116                         }
117                 }
118         }
119
120         return bd;
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_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_SEND ) );
221         if ( bd == NULL ) {
222                 return rs->sr_err;
223         }
224
225         return relay_back_op( op, rs, bd, bd->be_compare,
226                 RB_UNSUPPORTED_SEND );
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_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_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_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_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 int
290 relay_back_op_abandon( Operation *op, SlapReply *rs )
291 {
292         BackendDB               *bd;
293
294         bd = relay_back_select_backend( op, rs, 0 );
295         if ( bd == NULL ) {
296                 return rs->sr_err;
297         }
298
299         return relay_back_op( op, rs, bd, bd->be_abandon, 0 );
300 }
301
302 int
303 relay_back_op_cancel( Operation *op, SlapReply *rs )
304 {
305         BackendDB               *bd;
306         int                     rc;
307
308         bd = relay_back_select_backend( op, rs,
309                 ( LDAP_CANNOT_CANCEL | RB_ERR ) );
310         if ( bd == NULL ) {
311                 if ( op->o_cancel == SLAP_CANCEL_REQ ) {
312                         op->o_cancel = LDAP_CANNOT_CANCEL;
313                 }
314                 return rs->sr_err;
315         }
316
317         rc = relay_back_op( op, rs, bd, bd->be_cancel,
318                 ( LDAP_CANNOT_CANCEL | RB_ERR ) );
319         if ( rc == LDAP_CANNOT_CANCEL && op->o_cancel == SLAP_CANCEL_REQ )
320         {
321                 op->o_cancel = LDAP_CANNOT_CANCEL;
322         }
323
324         return rc;
325 }
326
327 int
328 relay_back_op_extended( Operation *op, SlapReply *rs )
329 {
330         BackendDB               *bd;
331
332         bd = relay_back_select_backend( op, rs,
333                 ( LDAP_NO_SUCH_OBJECT | RB_ERR ) );
334         if ( bd == NULL ) {
335                 return rs->sr_err;
336         }
337
338         return relay_back_op( op, rs, bd, bd->be_extended,
339                 RB_UNSUPPORTED );
340 }
341
342 int
343 relay_back_entry_release_rw( Operation *op, Entry *e, int rw )
344 {
345         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
346         BackendDB               *bd;
347         int                     rc = 1;
348
349         bd = ri->ri_bd;
350         if ( bd == NULL) {
351                 bd = select_backend( &op->o_req_ndn, 1 );
352                 if ( bd == NULL ) {
353                         return 1;
354                 }
355         }
356
357         if ( bd->be_release ) {
358                 BackendDB       *be = op->o_bd;
359
360                 op->o_bd = bd;
361                 rc = bd->be_release( op, e, rw );
362                 op->o_bd = be;
363         }
364
365         return rc;
366
367 }
368
369 int
370 relay_back_entry_get_rw( Operation *op, struct berval *ndn,
371         ObjectClass *oc, AttributeDescription *at, int rw, Entry **e )
372 {
373         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
374         BackendDB               *bd;
375         int                     rc = 1;
376
377         bd = ri->ri_bd;
378         if ( bd == NULL) {
379                 bd = select_backend( &op->o_req_ndn, 1 );
380                 if ( bd == NULL ) {
381                         return 1;
382                 }
383         }
384
385         if ( bd->be_fetch ) {
386                 BackendDB       *be = op->o_bd;
387
388                 op->o_bd = bd;
389                 rc = bd->be_fetch( op, ndn, oc, at, rw, e );
390                 op->o_bd = be;
391         }
392
393         return rc;
394
395 }
396
397 /*
398  * NOTE: even the existence of this function is questionable: we cannot
399  * pass the bi_chk_referrals() call thru the rwm overlay because there
400  * is no way to rewrite the req_dn back; but then relay_back_chk_referrals()
401  * is passing the target database a DN that likely does not belong to its
402  * naming context... mmmh.
403  */
404 int
405 relay_back_chk_referrals( Operation *op, SlapReply *rs )
406 {
407         BackendDB               *bd;
408
409         bd = relay_back_select_backend( op, rs,
410                 ( LDAP_SUCCESS | RB_ERR_SEND ) );
411         /* FIXME: this test only works if there are no overlays, so
412          * it is nearly useless; if made stricter, no nested back-relays
413          * can be instantiated... too bad. */
414         if ( bd == NULL || bd == op->o_bd ) {
415                 return 0;
416         }
417
418         /* no nested back-relays... */
419         if ( overlay_is_over( bd ) ) {
420                 slap_overinfo   *oi = (slap_overinfo *)bd->bd_info->bi_private;
421
422                 if ( oi->oi_orig == op->o_bd->bd_info ) {
423                         return 0;
424                 }
425         }
426
427         return relay_back_op( op, rs, bd, bd->be_chk_referrals, 0 );
428 }
429
430 int
431 relay_back_operational( Operation *op, SlapReply *rs )
432 {
433         BackendDB               *bd;
434
435         bd = relay_back_select_backend( op, rs,
436                 ( LDAP_SUCCESS | RB_ERR ) );
437         /* FIXME: this test only works if there are no overlays, so
438          * it is nearly useless; if made stricter, no nested back-relays
439          * can be instantiated... too bad. */
440         if ( bd == NULL || bd == op->o_bd ) {
441                 return 0;
442         }
443
444         return relay_back_op( op, rs, bd, bd->be_operational, 0 );
445 }
446
447 int
448 relay_back_has_subordinates( Operation *op, Entry *e, int *hasSubs )
449 {
450         SlapReply               rs = { 0 };
451         BackendDB               *bd;
452         int                     rc = 1;
453
454         bd = relay_back_select_backend( op, &rs,
455                 ( LDAP_SUCCESS | RB_ERR ) );
456         /* FIXME: this test only works if there are no overlays, so
457          * it is nearly useless; if made stricter, no nested back-relays
458          * can be instantiated... too bad. */
459         if ( bd == NULL || bd == op->o_bd ) {
460                 return 0;
461         }
462
463         if ( bd->be_has_subordinates ) {
464                 BackendDB       *be = op->o_bd;
465
466                 op->o_bd = bd;
467                 rc = bd->be_has_subordinates( op, e, hasSubs );
468                 op->o_bd = be;
469         }
470
471         return rc;
472
473 }
474
475 int
476 relay_back_connection_init( BackendDB *bd, Connection *c )
477 {
478         relay_back_info         *ri = (relay_back_info *)bd->be_private;
479
480         bd = ri->ri_bd;
481         if ( bd == NULL ) {
482                 return 0;
483         }
484
485         if ( bd->be_connection_init ) {
486                 return bd->be_connection_init( bd, c );
487         }
488
489         return 0;
490 }
491
492 int
493 relay_back_connection_destroy( BackendDB *bd, Connection *c )
494 {
495         relay_back_info         *ri = (relay_back_info *)bd->be_private;
496
497         bd = ri->ri_bd;
498         if ( bd == NULL ) {
499                 return 0;
500         }
501
502         if ( bd->be_connection_destroy ) {
503                 return bd->be_connection_destroy( bd, c );
504         }
505
506         return 0;
507
508 }
509
510 /*
511  * FIXME: must implement tools as well
512  */