]> git.sur5r.net Git - openldap/blob - servers/slapd/back-relay/op.c
Fix missing CVS tag
[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-2008 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                 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 ) {
82                                 rs->sr_err = rc;
83                                 if ( fail_mode & RB_SEND ) {
84                                         send_ldap_result( op, rs );
85                                 }
86                         }
87
88                         return NULL;
89                 }
90         }
91
92         if ( bd == NULL ) {
93                 if ( ( fail_mode & RB_REFERRAL )
94                         && ( fail_mode & RB_SEND )
95                         && !BER_BVISNULL( &op->o_req_ndn )
96                         && default_referral )
97                 {
98                         rs->sr_err = LDAP_REFERRAL;
99
100                         /* if we set sr_err to LDAP_REFERRAL,
101                          * we must provide one */
102                         rs->sr_ref = referral_rewrite(
103                                 default_referral,
104                                 NULL, &op->o_req_dn,
105                                 LDAP_SCOPE_DEFAULT );
106                         if ( !rs->sr_ref ) {
107                                 rs->sr_ref = default_referral;
108                         }
109
110                         send_ldap_result( op, rs );
111
112                         if ( rs->sr_ref != default_referral ) {
113                                 ber_bvarray_free( rs->sr_ref );
114                         }
115
116                         return NULL;
117                 }
118
119                 /* NOTE: err is LDAP_INVALID_CREDENTIALS for bind,
120                  * LDAP_NO_SUCH_OBJECT for other operations.
121                  * noSuchObject cannot be returned by bind */
122                 rs->sr_err = rc;
123                 if ( fail_mode & RB_SEND ) {
124                         send_ldap_result( op, rs );
125                 }
126         }
127
128         return bd;
129 }
130
131 static int
132 relay_back_op(
133         Operation       *op,
134         SlapReply       *rs,
135         BackendDB       *bd,
136         BI_op_func      *func,
137         slap_mask_t     fail_mode )
138 {
139         int                     rc = ( fail_mode & RB_ERR_MASK );
140
141         if ( func ) {
142                 BackendDB       *be = op->o_bd;
143                 slap_callback   cb;
144
145                 relay_back_add_cb( &cb, op );
146
147                 op->o_bd = bd;
148                 rc = func( op, rs );
149                 op->o_bd = be;
150
151                 if ( op->o_callback == &cb ) {
152                         op->o_callback = op->o_callback->sc_next;
153                 }
154
155         } else if ( fail_mode & RB_ERR ) {
156                 rs->sr_err = rc;
157                 if ( fail_mode & RB_UNSUPPORTED_FLAG ) {
158                         rs->sr_text = "operation not supported within naming context";
159                 }
160
161                 if ( fail_mode & RB_SEND ) {
162                         send_ldap_result( op, rs );
163                 }
164         }
165
166         return rc;
167 }
168
169 int
170 relay_back_op_bind( Operation *op, SlapReply *rs )
171 {
172         BackendDB       *bd;
173
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:
178                 break;
179
180         default:
181                 return rs->sr_err;
182         }
183
184         bd = relay_back_select_backend( op, rs,
185                 ( LDAP_INVALID_CREDENTIALS | RB_ERR_SEND ) );
186         if ( bd == NULL ) {
187                 return rs->sr_err;
188         }
189
190         return relay_back_op( op, rs, bd, bd->be_bind,
191                 ( LDAP_INVALID_CREDENTIALS | RB_ERR_SEND ) );
192 }
193
194 int
195 relay_back_op_unbind( Operation *op, SlapReply *rs )
196 {
197         BackendDB               *bd;
198
199         bd = relay_back_select_backend( op, rs, 0 );
200         if ( bd != NULL ) {
201                 (void)relay_back_op( op, rs, bd, bd->be_unbind, 0 );
202         }
203
204         return 0;
205 }
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 int
298 relay_back_op_abandon( Operation *op, SlapReply *rs )
299 {
300         BackendDB               *bd;
301
302         bd = relay_back_select_backend( op, rs, 0 );
303         if ( bd == NULL ) {
304                 return rs->sr_err;
305         }
306
307         return relay_back_op( op, rs, bd, bd->be_abandon, 0 );
308 }
309
310 int
311 relay_back_op_cancel( Operation *op, SlapReply *rs )
312 {
313         BackendDB               *bd;
314         int                     rc;
315
316         bd = relay_back_select_backend( op, rs,
317                 ( LDAP_CANNOT_CANCEL | RB_ERR ) );
318         if ( bd == NULL ) {
319                 if ( op->o_cancel == SLAP_CANCEL_REQ ) {
320                         op->o_cancel = LDAP_CANNOT_CANCEL;
321                 }
322                 return rs->sr_err;
323         }
324
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 )
328         {
329                 op->o_cancel = LDAP_CANNOT_CANCEL;
330         }
331
332         return rc;
333 }
334
335 int
336 relay_back_op_extended( Operation *op, SlapReply *rs )
337 {
338         BackendDB               *bd;
339
340         bd = relay_back_select_backend( op, rs,
341                 ( LDAP_NO_SUCH_OBJECT | RB_ERR | RB_REFERRAL ) );
342         if ( bd == NULL ) {
343                 return rs->sr_err;
344         }
345
346         return relay_back_op( op, rs, bd, bd->be_extended,
347                 RB_UNSUPPORTED );
348 }
349
350 int
351 relay_back_entry_release_rw( Operation *op, Entry *e, int rw )
352 {
353         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
354         BackendDB               *bd;
355         int                     rc = 1;
356
357         bd = ri->ri_bd;
358         if ( bd == NULL) {
359                 bd = select_backend( &op->o_req_ndn, 1 );
360                 if ( bd == NULL ) {
361                         return 1;
362                 }
363         }
364
365         if ( bd->be_release ) {
366                 BackendDB       *be = op->o_bd;
367
368                 op->o_bd = bd;
369                 rc = bd->be_release( op, e, rw );
370                 op->o_bd = be;
371         }
372
373         return rc;
374
375 }
376
377 int
378 relay_back_entry_get_rw( Operation *op, struct berval *ndn,
379         ObjectClass *oc, AttributeDescription *at, int rw, Entry **e )
380 {
381         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
382         BackendDB               *bd;
383         int                     rc = 1;
384
385         bd = ri->ri_bd;
386         if ( bd == NULL) {
387                 bd = select_backend( &op->o_req_ndn, 1 );
388                 if ( bd == NULL ) {
389                         return 1;
390                 }
391         }
392
393         if ( bd->be_fetch ) {
394                 BackendDB       *be = op->o_bd;
395
396                 op->o_bd = bd;
397                 rc = bd->be_fetch( op, ndn, oc, at, rw, e );
398                 op->o_bd = be;
399         }
400
401         return rc;
402
403 }
404
405 /*
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.
411  */
412 int
413 relay_back_chk_referrals( Operation *op, SlapReply *rs )
414 {
415         BackendDB               *bd;
416
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 ) {
423                 return 0;
424         }
425
426         /* no nested back-relays... */
427         if ( overlay_is_over( bd ) ) {
428                 slap_overinfo   *oi = (slap_overinfo *)bd->bd_info->bi_private;
429
430                 if ( oi->oi_orig == op->o_bd->bd_info ) {
431                         return 0;
432                 }
433         }
434
435         return relay_back_op( op, rs, bd, bd->be_chk_referrals, LDAP_SUCCESS );
436 }
437
438 int
439 relay_back_operational( Operation *op, SlapReply *rs )
440 {
441         BackendDB               *bd;
442
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 ) {
449                 return 0;
450         }
451
452         return relay_back_op( op, rs, bd, bd->be_operational, 0 );
453 }
454
455 int
456 relay_back_has_subordinates( Operation *op, Entry *e, int *hasSubs )
457 {
458         SlapReply               rs = { 0 };
459         BackendDB               *bd;
460         int                     rc = 1;
461
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 ) {
468                 return 0;
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
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
518 /*
519  * FIXME: must implement tools as well
520  */