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