]> git.sur5r.net Git - openldap/blob - servers/slapd/back-relay/op.c
fix test; don't return error when relaying exops
[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 static int
29 relay_back_swap_bd( Operation *op, SlapReply *rs )
30 {
31         slap_callback   *cb = op->o_callback;
32         BackendDB       *be = op->o_bd;
33
34         op->o_bd = cb->sc_private;
35         cb->sc_private = be;
36
37         return SLAP_CB_CONTINUE;
38 }
39
40 static void
41 relay_back_add_cb( slap_callback *cb, Operation *op )
42 {
43         cb->sc_next = op->o_callback;
44         cb->sc_response = relay_back_swap_bd;
45         cb->sc_cleanup = relay_back_swap_bd;
46         cb->sc_private = op->o_bd;
47         op->o_callback = cb;
48 }
49
50 /*
51  * selects the backend if not enforced at config;
52  * in case of failure, behaves based on err:
53  *      -1                      don't send result
54  *      LDAP_SUCCESS            don't send result; may send referral
55  *      any valid error         send as error result
56  */
57 static BackendDB *
58 relay_back_select_backend( Operation *op, SlapReply *rs, int err, int dosend )
59 {
60         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
61         BackendDB               *bd = ri->ri_bd;
62
63         if ( bd == NULL && !BER_BVISNULL( &op->o_req_ndn ) ) {
64                 bd = select_backend( &op->o_req_ndn, 1 );
65                 if ( bd == op->o_bd ) {
66                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
67                         rs->sr_text = "back-relay would call self";
68                         if ( err > LDAP_SUCCESS && dosend ) {
69                                 send_ldap_result( op, rs );
70                         }
71                         return NULL;
72                 }
73         }
74
75         if ( bd == NULL && err > -1 ) {
76                 if ( default_referral ) {
77                         rs->sr_err = LDAP_REFERRAL;
78                         if ( dosend ) {
79                                 rs->sr_ref = referral_rewrite(
80                                         default_referral,
81                                         NULL, &op->o_req_dn,
82                                         LDAP_SCOPE_DEFAULT );
83                                 if ( !rs->sr_ref ) {
84                                         rs->sr_ref = default_referral;
85                                 }
86
87                                 send_ldap_result( op, rs );
88
89                                 if ( rs->sr_ref != default_referral ) {
90                                         ber_bvarray_free( rs->sr_ref );
91                                 }
92                         }
93
94                 } else {
95                         /* NOTE: err is LDAP_INVALID_CREDENTIALS for bind,
96                          * LDAP_NO_SUCH_OBJECT for other operations.
97                          * noSuchObject cannot be returned by bind */
98                         rs->sr_err = err;
99                         if ( dosend ) {
100                                 send_ldap_result( op, rs );
101                         }
102                 }
103         }
104
105         return bd;
106 }
107
108 int
109 relay_back_op_bind( Operation *op, SlapReply *rs )
110 {
111         BackendDB               *bd;
112         int                     rc = 1;
113
114         /* allow rootdn as a means to auth without the need to actually
115          * contact the proxied DSA */
116         switch ( be_rootdn_bind( op, rs ) ) {
117         case SLAP_CB_CONTINUE:
118                 break;
119
120         default:
121                 return rs->sr_err;
122         }
123
124         bd = relay_back_select_backend( op, rs, LDAP_INVALID_CREDENTIALS, 1 );
125         if ( bd == NULL ) {
126                 return rs->sr_err;
127         }
128
129         if ( bd->be_bind ) {
130                 BackendDB       *be = op->o_bd;
131                 slap_callback   cb;
132
133                 relay_back_add_cb( &cb, op );
134
135                 op->o_bd = bd;
136                 rc = bd->be_bind( op, rs );
137                 op->o_bd = be;
138
139                 if ( op->o_callback == &cb ) {
140                         op->o_callback = op->o_callback->sc_next;
141                 }
142
143         } else {
144                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
145                                 "operation not supported "
146                                 "within naming context" );
147         }
148
149         return rc;
150 }
151
152 int
153 relay_back_op_unbind( Operation *op, SlapReply *rs )
154 {
155         BackendDB               *bd;
156         int                     rc = 1;
157
158         bd = relay_back_select_backend( op, rs, LDAP_SUCCESS, 0 );
159         if ( bd == NULL ) {
160                 return rs->sr_err;
161         }
162
163         if ( bd && bd->be_unbind ) {
164                 BackendDB       *be = op->o_bd;
165                 slap_callback   cb;
166
167                 relay_back_add_cb( &cb, op );
168
169                 op->o_bd = bd;
170                 rc = bd->be_unbind( op, rs );
171                 op->o_bd = be;
172
173                 if ( op->o_callback == &cb ) {
174                         op->o_callback = op->o_callback->sc_next;
175                 }
176         }
177
178         return 0;
179
180 }
181
182 int
183 relay_back_op_search( Operation *op, SlapReply *rs )
184 {
185         BackendDB               *bd;
186         int                     rc = 1;
187
188         bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 );
189         if ( bd == NULL ) {
190                 return rs->sr_err;
191         }
192
193         if ( bd->be_search ) {
194                 BackendDB       *be = op->o_bd;
195                 slap_callback   cb;
196
197                 relay_back_add_cb( &cb, op );
198
199                 op->o_bd = bd;
200                 rc = bd->be_search( op, rs );
201                 op->o_bd = be;
202
203                 if ( op->o_callback == &cb ) {
204                         op->o_callback = op->o_callback->sc_next;
205                 }
206
207         } else {
208                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
209                                 "operation not supported "
210                                 "within naming context" );
211         }
212
213         return rc;
214
215 }
216
217 int
218 relay_back_op_compare( Operation *op, SlapReply *rs )
219 {
220         BackendDB               *bd;
221         int                     rc = 1;
222
223         bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 );
224         if ( bd == NULL ) {
225                 return rs->sr_err;
226         }
227
228         if ( bd->be_compare ) {
229                 BackendDB       *be = op->o_bd;
230                 slap_callback   cb;
231
232                 relay_back_add_cb( &cb, op );
233
234                 op->o_bd = bd;
235                 rc = bd->be_compare( op, rs );
236                 op->o_bd = be;
237
238                 if ( op->o_callback == &cb ) {
239                         op->o_callback = op->o_callback->sc_next;
240                 }
241
242         } else {
243                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
244                                 "operation not supported "
245                                 "within naming context" );
246         }
247
248         return rc;
249
250 }
251
252 int
253 relay_back_op_modify( Operation *op, SlapReply *rs )
254 {
255         BackendDB               *bd;
256         int                     rc = 1;
257
258         bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 );
259         if ( bd == NULL ) {
260                 return rs->sr_err;
261         }
262
263         if ( bd->be_modify ) {
264                 BackendDB       *be = op->o_bd;
265                 slap_callback   cb;
266
267                 relay_back_add_cb( &cb, op );
268
269                 op->o_bd = bd;
270                 rc = bd->be_modify( op, rs );
271                 op->o_bd = be;
272
273                 if ( op->o_callback == &cb ) {
274                         op->o_callback = op->o_callback->sc_next;
275                 }
276
277         } else {
278                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
279                                 "operation not supported "
280                                 "within naming context" );
281         }
282
283         return rc;
284
285 }
286
287 int
288 relay_back_op_modrdn( Operation *op, SlapReply *rs )
289 {
290         BackendDB               *bd;
291         int                     rc = 1;
292
293         bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 );
294         if ( bd == NULL ) {
295                 return rs->sr_err;
296         }
297
298         if ( bd->be_modrdn ) {
299                 BackendDB       *be = op->o_bd;
300                 slap_callback   cb;
301
302                 relay_back_add_cb( &cb, op );
303
304                 op->o_bd = bd;
305                 rc = bd->be_modrdn( op, rs );
306                 op->o_bd = be;
307
308                 if ( op->o_callback == &cb ) {
309                         op->o_callback = op->o_callback->sc_next;
310                 }
311
312         } else {
313                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
314                                 "operation not supported "
315                                 "within naming context" );
316         }
317
318         return rc;
319
320 }
321
322 int
323 relay_back_op_add( Operation *op, SlapReply *rs )
324 {
325         BackendDB               *bd;
326         int                     rc = 1;
327
328         bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 );
329         if ( bd == NULL ) {
330                 return rs->sr_err;
331         }
332
333         if ( bd->be_add ) {
334                 BackendDB       *be = op->o_bd;
335                 slap_callback   cb;
336
337                 relay_back_add_cb( &cb, op );
338
339                 op->o_bd = bd;
340                 rc = bd->be_add( op, rs );
341                 op->o_bd = be;
342
343                 if ( op->o_callback == &cb ) {
344                         op->o_callback = op->o_callback->sc_next;
345                 }
346
347         } else {
348                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
349                                 "operation not supported "
350                                 "within naming context" );
351         }
352
353         return rc;
354
355 }
356
357 int
358 relay_back_op_delete( Operation *op, SlapReply *rs )
359 {
360         BackendDB               *bd;
361         int                     rc = 1;
362
363         bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 );
364         if ( bd == NULL ) {
365                 return rs->sr_err;
366         }
367
368         if ( bd->be_delete ) {
369                 BackendDB       *be = op->o_bd;
370                 slap_callback   cb;
371
372                 relay_back_add_cb( &cb, op );
373
374                 op->o_bd = bd;
375                 rc = bd->be_delete( op, rs );
376                 op->o_bd = be;
377
378                 if ( op->o_callback == &cb ) {
379                         op->o_callback = op->o_callback->sc_next;
380                 }
381         }
382
383         return rc;
384
385 }
386
387 int
388 relay_back_op_abandon( Operation *op, SlapReply *rs )
389 {
390         BackendDB               *bd;
391         int                     rc = 1;
392
393         bd = relay_back_select_backend( op, rs, LDAP_SUCCESS, 0 );
394         if ( bd == NULL ) {
395                 return rs->sr_err;
396         }
397
398         if ( bd->be_abandon ) {
399                 BackendDB       *be = op->o_bd;
400                 slap_callback   cb;
401
402                 relay_back_add_cb( &cb, op );
403
404                 op->o_bd = bd;
405                 rc = bd->be_abandon( op, rs );
406                 op->o_bd = be;
407
408                 if ( op->o_callback == &cb ) {
409                         op->o_callback = op->o_callback->sc_next;
410                 }
411         }
412
413         return rc;
414
415 }
416
417 int
418 relay_back_op_cancel( Operation *op, SlapReply *rs )
419 {
420         BackendDB               *bd;
421         int                     rc = 1;
422
423         bd = relay_back_select_backend( op, rs, LDAP_CANNOT_CANCEL, 0 );
424         if ( bd == NULL ) {
425                 return rs->sr_err;
426         }
427
428         if ( bd->be_cancel ) {
429                 BackendDB       *be = op->o_bd;
430                 slap_callback   cb;
431
432                 relay_back_add_cb( &cb, op );
433
434                 op->o_bd = bd;
435                 rc = bd->be_cancel( op, rs );
436                 op->o_bd = be;
437
438                 if ( op->o_callback == &cb ) {
439                         op->o_callback = op->o_callback->sc_next;
440                 }
441
442         } else {
443                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
444                                 "operation not supported "
445                                 "within naming context" );
446         }
447
448         return rc;
449
450 }
451
452 int
453 relay_back_op_extended( Operation *op, SlapReply *rs )
454 {
455         BackendDB               *bd;
456         int                     rc;
457
458         bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 0 );
459         if ( bd == NULL ) {
460                 return rs->sr_err;
461         }
462
463         if ( bd->be_extended ) {
464                 BackendDB       *be = op->o_bd;
465                 slap_callback   cb;
466
467                 relay_back_add_cb( &cb, op );
468
469                 op->o_bd = bd;
470                 rc = bd->be_extended( op, rs );
471                 op->o_bd = be;
472
473                 if ( op->o_callback == &cb ) {
474                         op->o_callback = op->o_callback->sc_next;
475                 }
476
477         } else {
478                 rc = rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
479                 rs->sr_text = "operation not supported within naming context";
480         }
481
482         return rc;
483
484 }
485
486 int
487 relay_back_entry_release_rw( Operation *op, Entry *e, int rw )
488 {
489         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
490         BackendDB               *bd;
491         int                     rc = 1;
492
493         bd = ri->ri_bd;
494         if ( bd == NULL) {
495                 bd = select_backend( &op->o_req_ndn, 1 );
496                 if ( bd == NULL ) {
497                         return 1;
498                 }
499         }
500
501         if ( bd->be_release ) {
502                 BackendDB       *be = op->o_bd;
503
504                 op->o_bd = bd;
505                 rc = bd->be_release( op, e, rw );
506                 op->o_bd = be;
507         }
508
509         return rc;
510
511 }
512
513 int
514 relay_back_entry_get_rw( Operation *op, struct berval *ndn,
515         ObjectClass *oc, AttributeDescription *at, int rw, Entry **e )
516 {
517         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
518         BackendDB               *bd;
519         int                     rc = 1;
520
521         bd = ri->ri_bd;
522         if ( bd == NULL) {
523                 bd = select_backend( &op->o_req_ndn, 1 );
524                 if ( bd == NULL ) {
525                         return 1;
526                 }
527         }
528
529         if ( bd->be_fetch ) {
530                 BackendDB       *be = op->o_bd;
531
532                 op->o_bd = bd;
533                 rc = bd->be_fetch( op, ndn, oc, at, rw, e );
534                 op->o_bd = be;
535         }
536
537         return rc;
538
539 }
540
541 /*
542  * NOTE: even the existence of this function is questionable: we cannot
543  * pass the bi_chk_referrals() call thru the rwm overlay because there
544  * is no way to rewrite the req_dn back; but then relay_back_chk_referrals()
545  * is passing the target database a DN that likely does not belong to its
546  * naming context... mmmh.
547  */
548 int
549 relay_back_chk_referrals( Operation *op, SlapReply *rs )
550 {
551         BackendDB               *bd;
552         int                     rc = 0;
553
554         bd = relay_back_select_backend( op, rs, LDAP_SUCCESS, 1 );
555         /* FIXME: this test only works if there are no overlays, so
556          * it is nearly useless; if made stricter, no nested back-relays
557          * can be instantiated... too bad. */
558         if ( bd == NULL || bd == op->o_bd ) {
559                 return 0;
560         }
561
562         /* no nested back-relays... */
563         if ( overlay_is_over( bd ) ) {
564                 slap_overinfo   *oi = (slap_overinfo *)bd->bd_info->bi_private;
565
566                 if ( oi->oi_orig == op->o_bd->bd_info ) {
567                         return 0;
568                 }
569         }
570
571         if ( bd->be_chk_referrals ) {
572                 BackendDB       *be = op->o_bd;
573                 slap_callback   cb;
574
575                 relay_back_add_cb( &cb, op );
576
577                 op->o_bd = bd;
578                 rc = bd->be_chk_referrals( op, rs );
579                 op->o_bd = be;
580
581                 if ( op->o_callback == &cb ) {
582                         op->o_callback = op->o_callback->sc_next;
583                 }
584         }
585
586         return rc;
587
588 }
589
590 int
591 relay_back_operational( Operation *op, SlapReply *rs )
592 {
593         BackendDB               *bd;
594         int                     rc = 1;
595
596         bd = relay_back_select_backend( op, rs, LDAP_SUCCESS, 0 );
597         /* FIXME: this test only works if there are no overlays, so
598          * it is nearly useless; if made stricter, no nested back-relays
599          * can be instantiated... too bad. */
600         if ( bd == NULL || bd == op->o_bd ) {
601                 return 0;
602         }
603
604         if ( bd->be_operational ) {
605                 BackendDB       *be = op->o_bd;
606                 slap_callback   cb;
607
608                 relay_back_add_cb( &cb, op );
609
610                 op->o_bd = bd;
611                 rc = bd->be_operational( op, rs );
612                 op->o_bd = be;
613
614                 if ( op->o_callback == &cb ) {
615                         op->o_callback = op->o_callback->sc_next;
616                 }
617         }
618
619         return rc;
620
621 }
622
623 int
624 relay_back_has_subordinates( Operation *op, Entry *e, int *hasSubs )
625 {
626         SlapReply               rs = { 0 };
627         BackendDB               *bd;
628         int                     rc = 1;
629
630         bd = relay_back_select_backend( op, &rs, LDAP_SUCCESS, 0 );
631         /* FIXME: this test only works if there are no overlays, so
632          * it is nearly useless; if made stricter, no nested back-relays
633          * can be instantiated... too bad. */
634         if ( bd == NULL || bd == op->o_bd ) {
635                 return 0;
636         }
637
638         if ( bd->be_has_subordinates ) {
639                 BackendDB       *be = op->o_bd;
640
641                 op->o_bd = bd;
642                 rc = bd->be_has_subordinates( op, e, hasSubs );
643                 op->o_bd = be;
644         }
645
646         return rc;
647
648 }
649
650 int
651 relay_back_connection_init( BackendDB *bd, Connection *c )
652 {
653         relay_back_info         *ri = (relay_back_info *)bd->be_private;
654
655         bd = ri->ri_bd;
656         if ( bd == NULL ) {
657                 return 0;
658         }
659
660         if ( bd->be_connection_init ) {
661                 return bd->be_connection_init( bd, c );
662         }
663
664         return 0;
665 }
666
667 int
668 relay_back_connection_destroy( BackendDB *bd, Connection *c )
669 {
670         relay_back_info         *ri = (relay_back_info *)bd->be_private;
671
672         bd = ri->ri_bd;
673         if ( bd == NULL ) {
674                 return 0;
675         }
676
677         if ( bd->be_connection_destroy ) {
678                 return bd->be_connection_destroy( bd, c );
679         }
680
681         return 0;
682
683 }
684
685 /*
686  * FIXME: must implement tools as well
687  */