]> git.sur5r.net Git - openldap/blob - servers/slapd/back-relay/op.c
Fix for dynamic adds
[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-2007 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                         if ( err > LDAP_SUCCESS && dosend ) {
67                                 send_ldap_error( op, rs,
68                                                 LDAP_UNWILLING_TO_PERFORM, 
69                                                 "back-relay would call self" );
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 rc;
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 1;
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 1;
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 1;
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 1;
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 1;
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 1;
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 1;
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 1;
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 1;
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 = 1;
457
458         bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 0 );
459         if ( bd == NULL ) {
460                 return 1;
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                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
479                                 "operation not supported "
480                                 "within naming context" );
481         }
482
483         return rc;
484
485 }
486
487 int
488 relay_back_entry_release_rw( Operation *op, Entry *e, int rw )
489 {
490         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
491         BackendDB               *bd;
492         int                     rc = 1;
493
494         bd = ri->ri_bd;
495         if ( bd == NULL) {
496                 bd = select_backend( &op->o_req_ndn, 1 );
497                 if ( bd == NULL ) {
498                         return 1;
499                 }
500         }
501
502         if ( bd->be_release ) {
503                 BackendDB       *be = op->o_bd;
504
505                 op->o_bd = bd;
506                 rc = bd->be_release( op, e, rw );
507                 op->o_bd = be;
508         }
509
510         return rc;
511
512 }
513
514 int
515 relay_back_entry_get_rw( Operation *op, struct berval *ndn,
516         ObjectClass *oc, AttributeDescription *at, int rw, Entry **e )
517 {
518         relay_back_info         *ri = (relay_back_info *)op->o_bd->be_private;
519         BackendDB               *bd;
520         int                     rc = 1;
521
522         bd = ri->ri_bd;
523         if ( bd == NULL) {
524                 bd = select_backend( &op->o_req_ndn, 1 );
525                 if ( bd == NULL ) {
526                         return 1;
527                 }
528         }
529
530         if ( bd->be_fetch ) {
531                 BackendDB       *be = op->o_bd;
532
533                 op->o_bd = bd;
534                 rc = bd->be_fetch( op, ndn, oc, at, rw, e );
535                 op->o_bd = be;
536         }
537
538         return rc;
539
540 }
541
542 /*
543  * NOTE: even the existence of this function is questionable: we cannot
544  * pass the bi_chk_referrals() call thru the rwm overlay because there
545  * is no way to rewrite the req_dn back; but then relay_back_chk_referrals()
546  * is passing the target database a DN that likely does not belong to its
547  * naming context... mmmh.
548  */
549 int
550 relay_back_chk_referrals( Operation *op, SlapReply *rs )
551 {
552         BackendDB               *bd;
553         int                     rc = 0;
554
555         bd = relay_back_select_backend( op, rs, LDAP_SUCCESS, 1 );
556         /* FIXME: this test only works if there are no overlays, so
557          * it is nearly useless; if made stricter, no nested back-relays
558          * can be instantiated... too bad. */
559         if ( bd == NULL || bd == op->o_bd ) {
560                 return 0;
561         }
562
563         /* no nested back-relays... */
564         if ( overlay_is_over( bd ) ) {
565                 slap_overinfo   *oi = (slap_overinfo *)bd->bd_info->bi_private;
566
567                 if ( oi->oi_orig == op->o_bd->bd_info ) {
568                         return 0;
569                 }
570         }
571
572         if ( bd->be_chk_referrals ) {
573                 BackendDB       *be = op->o_bd;
574                 slap_callback   cb;
575
576                 relay_back_add_cb( &cb, op );
577
578                 op->o_bd = bd;
579                 rc = bd->be_chk_referrals( op, rs );
580                 op->o_bd = be;
581
582                 if ( op->o_callback == &cb ) {
583                         op->o_callback = op->o_callback->sc_next;
584                 }
585         }
586
587         return rc;
588
589 }
590
591 int
592 relay_back_operational( Operation *op, SlapReply *rs )
593 {
594         BackendDB               *bd;
595         int                     rc = 1;
596
597         bd = relay_back_select_backend( op, rs, LDAP_SUCCESS, 0 );
598         /* FIXME: this test only works if there are no overlays, so
599          * it is nearly useless; if made stricter, no nested back-relays
600          * can be instantiated... too bad. */
601         if ( bd == NULL || bd == op->o_bd ) {
602                 return 0;
603         }
604
605         if ( bd->be_operational ) {
606                 BackendDB       *be = op->o_bd;
607                 slap_callback   cb;
608
609                 relay_back_add_cb( &cb, op );
610
611                 op->o_bd = bd;
612                 rc = bd->be_operational( op, rs );
613                 op->o_bd = be;
614
615                 if ( op->o_callback == &cb ) {
616                         op->o_callback = op->o_callback->sc_next;
617                 }
618         }
619
620         return rc;
621
622 }
623
624 int
625 relay_back_has_subordinates( Operation *op, Entry *e, int *hasSubs )
626 {
627         SlapReply               rs = { 0 };
628         BackendDB               *bd;
629         int                     rc = 1;
630
631         bd = relay_back_select_backend( op, &rs, LDAP_SUCCESS, 0 );
632         /* FIXME: this test only works if there are no overlays, so
633          * it is nearly useless; if made stricter, no nested back-relays
634          * can be instantiated... too bad. */
635         if ( bd == NULL || bd == op->o_bd ) {
636                 return 0;
637         }
638
639         if ( bd->be_has_subordinates ) {
640                 BackendDB       *be = op->o_bd;
641
642                 op->o_bd = bd;
643                 rc = bd->be_has_subordinates( op, e, hasSubs );
644                 op->o_bd = be;
645         }
646
647         return rc;
648
649 }
650
651 int
652 relay_back_connection_init( BackendDB *bd, Connection *c )
653 {
654         relay_back_info         *ri = (relay_back_info *)bd->be_private;
655
656         bd = ri->ri_bd;
657         if ( bd == NULL ) {
658                 return 0;
659         }
660
661         if ( bd->be_connection_init ) {
662                 return bd->be_connection_init( bd, c );
663         }
664
665         return 0;
666 }
667
668 int
669 relay_back_connection_destroy( BackendDB *bd, Connection *c )
670 {
671         relay_back_info         *ri = (relay_back_info *)bd->be_private;
672
673         bd = ri->ri_bd;
674         if ( bd == NULL ) {
675                 return 0;
676         }
677
678         if ( bd->be_connection_destroy ) {
679                 return bd->be_connection_destroy( bd, c );
680         }
681
682         return 0;
683
684 }
685
686 /*
687  * FIXME: must implement tools as well
688  */