]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/chain.c
fix entry DN free
[openldap] / servers / slapd / back-ldap / chain.c
1 /* chain.c - chain LDAP operations */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2005 The OpenLDAP Foundation.
6  * Portions Copyright 2003 Howard Chu.
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 the Howard Chu for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25
26 #include <ac/string.h>
27 #include <ac/socket.h>
28
29 #include "slap.h"
30 #include "back-ldap.h"
31
32 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
33 #define SLAP_CHAINING_DEFAULT                           LDAP_CHAINING_PREFERRED
34 #define SLAP_CH_RESOLVE_SHIFT                           SLAP_CONTROL_SHIFT
35 #define SLAP_CH_RESOLVE_MASK                            (0x3 << SLAP_CH_RESOLVE_SHIFT)
36 #define SLAP_CH_RESOLVE_CHAINING_PREFERRED              (LDAP_CHAINING_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
37 #define SLAP_CH_RESOLVE_CHAINING_REQUIRED               (LDAP_CHAINING_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
38 #define SLAP_CH_RESOLVE_REFERRALS_PREFERRED             (LDAP_REFERRALS_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
39 #define SLAP_CH_RESOLVE_REFERRALS_REQUIRED              (LDAP_REFERRALS_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
40 #define SLAP_CH_RESOLVE_DEFAULT                         (SLAP_CHAINING_DEFAULT << SLAP_CH_RESOLVE_SHIFT)
41 #define SLAP_CH_CONTINUATION_SHIFT                      (SLAP_CH_RESOLVE_SHIFT + 2)
42 #define SLAP_CH_CONTINUATION_MASK                       (0x3 << SLAP_CH_CONTINUATION_SHIFT)
43 #define SLAP_CH_CONTINUATION_CHAINING_PREFERRED         (LDAP_CHAINING_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
44 #define SLAP_CH_CONTINUATION_CHAINING_REQUIRED          (LDAP_CHAINING_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
45 #define SLAP_CH_CONTINUATION_REFERRALS_PREFERRED        (LDAP_REFERRALS_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
46 #define SLAP_CH_CONTINUATION_REFERRALS_REQUIRED         (LDAP_REFERRALS_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
47 #define SLAP_CH_CONTINUATION_DEFAULT                    (SLAP_CHAINING_DEFAULT << SLAP_CH_CONTINUATION_SHIFT)
48
49 #define o_chaining                      o_ctrlflag[sc_chainingBehavior]
50 #define get_chaining(op)                ((op)->o_chaining & SLAP_CONTROL_MASK)
51 #define get_chainingBehavior(op)        ((op)->o_chaining & (SLAP_CH_RESOLVE_MASK|SLAP_CH_CONTINUATION_MASK))
52 #define get_resolveBehavior(op)         ((op)->o_chaining & SLAP_CH_RESOLVE_MASK)
53 #define get_continuationBehavior(op)    ((op)->o_chaining & SLAP_CH_CONTINUATION_MASK)
54
55 static int              sc_chainingBehavior;
56 #endif /*  LDAP_CONTROL_X_CHAINING_BEHAVIOR */
57
58 #define LDAP_CH_NONE                    ((void *)(0))
59 #define LDAP_CH_RES                     ((void *)(1))
60 #define LDAP_CH_ERR                     ((void *)(2))
61
62 static BackendInfo      *lback;
63
64 typedef struct ldap_chain_t {
65         struct ldapinfo         *lc_li;
66         unsigned                lc_flags;
67 #define LDAP_CHAIN_F_NONE               0x00U
68 #define LDAP_CHAIN_F_CHAINING           0x01U
69
70 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
71         LDAPControl             lc_chaining_ctrl;
72         char                    lc_chaining_ctrlflag;
73 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
74 } ldap_chain_t;
75
76 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
77 static int
78 chaining_control_add(
79                 ldap_chain_t    *lc,
80                 Operation       *op, 
81                 LDAPControl     ***oldctrlsp )
82 {
83         LDAPControl     **ctrls = NULL;
84         int             c = 0;
85
86         *oldctrlsp = op->o_ctrls;
87
88         /* default chaining control not defined */
89         if ( !( lc->lc_flags & LDAP_CHAIN_F_CHAINING ) ) {
90                 return 0;
91         }
92
93         /* already present */
94         if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
95                 return 0;
96         }
97
98         /* FIXME: check other incompatibilities */
99
100         /* add to other controls */
101         if ( op->o_ctrls ) {
102                 for ( c = 0; op->o_ctrls[ c ]; c++ )
103                         /* count them */ ;
104         }
105
106         ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
107         ctrls[ 0 ] = &lc->lc_chaining_ctrl;
108         if ( op->o_ctrls ) {
109                 for ( c = 0; op->o_ctrls[ c ]; c++ ) {
110                         ctrls[ c + 1 ] = op->o_ctrls[ c ];
111                 }
112         }
113         ctrls[ c + 1 ] = NULL;
114
115         op->o_ctrls = ctrls;
116
117         op->o_chaining = lc->lc_chaining_ctrlflag;
118
119         return 0;
120 }
121
122 static int
123 chaining_control_remove(
124                 Operation       *op, 
125                 LDAPControl     ***oldctrlsp )
126 {
127         LDAPControl     **oldctrls = *oldctrlsp;
128
129         /* we assume that the first control is the chaining control
130          * added by the chain overlay, so it's the only one we explicitly 
131          * free */
132         if ( op->o_ctrls != oldctrls ) {
133                 assert( op->o_ctrls );
134                 assert( op->o_ctrls[ 0 ] );
135
136                 free( op->o_ctrls );
137
138                 op->o_chaining = 0;
139                 op->o_ctrls = oldctrls;
140         } 
141
142         *oldctrlsp = NULL;
143
144         return 0;
145 }
146 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
147
148 static int
149 ldap_chain_operational( Operation *op, SlapReply *rs )
150 {
151         /* Trap entries generated by back-ldap.
152          * 
153          * FIXME: we need a better way to recognize them; a cleaner
154          * solution would be to be able to intercept the response
155          * of be_operational(), so that we can divert only those
156          * calls that fail because operational attributes were
157          * requested for entries that do not belong to the underlying
158          * database.  This fix is likely to intercept also entries
159          * generated by back-perl and so. */
160         if ( rs->sr_entry->e_private == NULL ) {
161                 return 0;
162         }
163
164         return SLAP_CB_CONTINUE;
165 }
166
167 /*
168  * Search specific response that strips entryDN from entries
169  */
170 static int
171 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
172 {
173         assert( op->o_tag == LDAP_REQ_SEARCH );
174
175         /* if in error, don't proceed any further */
176         if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
177                 return 0;
178         }
179
180         if ( rs->sr_type == REP_SEARCH ) {
181                 Attribute       **ap = &rs->sr_entry->e_attrs;
182
183                 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
184                         /* will be generated later by frontend
185                          * (a cleaner solution would be that
186                          * the frontend checks if it already exists */
187                         if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
188                         {
189                                 Attribute *a = *ap;
190
191                                 *ap = (*ap)->a_next;
192                                 attr_free( a );
193
194                                 /* there SHOULD be one only! */
195                                 break;
196                         }
197                 }
198                 
199                 return SLAP_CB_CONTINUE;
200
201         } else if ( rs->sr_type == REP_SEARCHREF ) {
202                 /* if we get it here, it means the library was unable
203                  * to chase the referral... */
204
205 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
206                 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
207                         switch ( get_continuationBehavior( op ) ) {
208                         case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
209                                 op->o_callback->sc_private = LDAP_CH_ERR;
210                                 return -1;
211
212                         default:
213                                 break;
214                         }
215                 }
216 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
217                 return SLAP_CB_CONTINUE;
218
219         } else if ( rs->sr_type == REP_RESULT ) {
220                 /* back-ldap tried to send result */
221                 op->o_callback->sc_private = LDAP_CH_RES;
222         }
223
224         return 0;
225 }
226
227 /*
228  * Dummy response that simply traces if back-ldap tried to send 
229  * anything to the client
230  */
231 static int
232 ldap_chain_cb_response( Operation *op, SlapReply *rs )
233 {
234         /* if in error, don't proceed any further */
235         if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
236                 return 0;
237         }
238
239         if ( rs->sr_type == REP_RESULT ) {
240                 op->o_callback->sc_private = LDAP_CH_RES;
241
242         } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
243         {
244                 /* strip the entryDN attribute, but keep returning results */
245                 (void)ldap_chain_cb_search_response( op, rs );
246         }
247
248         return SLAP_CB_CONTINUE;
249 }
250
251 static int
252 ldap_chain_op(
253         Operation       *op,
254         SlapReply       *rs,
255         int             ( *op_f )( Operation *op, SlapReply *rs ), 
256         BerVarray       ref )
257 {
258         slap_overinst   *on = (slap_overinst *) op->o_bd->bd_info;
259         ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
260         struct ldapinfo li, *lip = lc->lc_li;
261
262         /* NOTE: returned if ref is empty... */
263         int             rc = LDAP_OTHER;
264
265 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
266         LDAPControl     **ctrls = NULL;
267         
268         (void)chaining_control_add( lc, op, &ctrls );
269 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
270
271         if ( lip->url != NULL ) {
272                 op->o_bd->be_private = lip;
273                 rc = ( *op_f )( op, rs );
274                 goto done;
275         }
276
277         li = *lip;
278         op->o_bd->be_private = &li;
279
280         /* if we parse the URI then by no means 
281          * we can cache stuff or reuse connections, 
282          * because in back-ldap there's no caching
283          * based on the URI value, which is supposed
284          * to be set once for all (correct?) */
285         op->o_do_not_cache = 1;
286
287         for ( ; !BER_BVISNULL( ref ); ref++ ) {
288                 LDAPURLDesc     *srv;
289                 char            *save_dn;
290                         
291                 /* We're setting the URI of the first referral;
292                  * what if there are more?
293
294 Document: draft-ietf-ldapbis-protocol-27.txt
295
296 4.1.10. Referral 
297    ...
298    If the client wishes to progress the operation, it MUST follow the 
299    referral by contacting one of the supported services. If multiple 
300    URIs are present, the client assumes that any supported URI may be 
301    used to progress the operation. 
302
303                  * so we actually need to follow exactly one,
304                  * and we can assume any is fine.
305                  */
306         
307                 /* parse reference and use 
308                  * proto://[host][:port]/ only */
309                 rc = ldap_url_parse_ext( ref->bv_val, &srv );
310                 if ( rc != LDAP_URL_SUCCESS ) {
311                         /* try next */
312                         rc = LDAP_OTHER;
313                         continue;
314                 }
315
316                 /* remove DN essentially because later on 
317                  * ldap_initialize() will parse the URL 
318                  * as a comma-separated URL list */
319                 save_dn = srv->lud_dn;
320                 srv->lud_dn = "";
321                 srv->lud_scope = LDAP_SCOPE_DEFAULT;
322                 li.url = ldap_url_desc2str( srv );
323                 srv->lud_dn = save_dn;
324                 ldap_free_urldesc( srv );
325
326                 if ( li.url == NULL ) {
327                         /* try next */
328                         rc = LDAP_OTHER;
329                         continue;
330                 }
331
332                 rc = ( *op_f )( op, rs );
333
334                 ldap_memfree( li.url );
335                 li.url = NULL;
336                 
337                 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
338                         break;
339                 }
340         }
341
342 done:;
343 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
344         (void)chaining_control_remove( op, &ctrls );
345 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
346
347         return rc;
348 }
349
350 static int
351 ldap_chain_response( Operation *op, SlapReply *rs )
352 {
353         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
354         void            *private = op->o_bd->be_private;
355         slap_callback   *sc = op->o_callback,
356                         sc2 = { 0 };
357         int             rc = 0;
358         int             cache = op->o_do_not_cache;
359         BerVarray       ref;
360         struct berval   ndn = op->o_ndn;
361
362         ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
363         struct ldapinfo li, *lip = lc->lc_li;
364
365 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
366         int             sr_err = rs->sr_err;
367         slap_reply_t    sr_type = rs->sr_type;
368         slap_mask_t     chain_mask = 0;
369         ber_len_t       chain_shift = 0;
370 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
371
372         if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
373                 return SLAP_CB_CONTINUE;
374         }
375
376 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
377         if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
378                 switch ( get_resolveBehavior( op ) ) {
379                 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
380                 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
381                         return SLAP_CB_CONTINUE;
382
383                 default:
384                         chain_mask = SLAP_CH_RESOLVE_MASK;
385                         chain_shift = SLAP_CH_RESOLVE_SHIFT;
386                         break;
387                 }
388
389         } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
390                 switch ( get_continuationBehavior( op ) ) {
391                 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
392                 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
393                         return SLAP_CB_CONTINUE;
394
395                 default:
396                         chain_mask = SLAP_CH_CONTINUATION_MASK;
397                         chain_shift = SLAP_CH_CONTINUATION_SHIFT;
398                         break;
399                 }
400         }
401 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
402
403         /*
404          * TODO: add checks on who/when chain operations; e.g.:
405          *   a) what identities are authorized
406          *   b) what request DN (e.g. only chain requests rooted at <DN>)
407          *   c) what referral URIs
408          *   d) what protocol scheme (e.g. only ldaps://)
409          *   e) what ssf
410          */
411
412         ref = rs->sr_ref;
413         rs->sr_ref = NULL;
414
415         /* we need this to know if back-ldap returned any result */
416         sc2.sc_response = ldap_chain_cb_response;
417         op->o_callback = &sc2;
418
419         /* Chaining can be performed by a privileged user on behalf
420          * of normal users, using the ProxyAuthz control, by exploiting
421          * the identity assertion feature of back-ldap; see idassert-*
422          * directives in slapd-ldap(5).
423          *
424          * FIXME: the idassert-authcDN is one, will it be fine regardless
425          * of the URI we obtain from the referral?
426          */
427
428         switch ( op->o_tag ) {
429         case LDAP_REQ_BIND: {
430                 struct berval   rndn = op->o_req_ndn;
431                 Connection      *conn = op->o_conn;
432
433                 /* FIXME: can we really get a referral for binds? */
434                 op->o_req_ndn = slap_empty_bv;
435                 op->o_conn = NULL;
436                 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref );
437                 op->o_req_ndn = rndn;
438                 op->o_conn = conn;
439                 }
440                 break;
441         case LDAP_REQ_ADD:
442                 {
443                 int             cleanup_attrs = 0;
444
445                 if ( op->ora_e->e_attrs == NULL ) {
446                         char            textbuf[ SLAP_TEXT_BUFLEN ];
447                         size_t          textlen = sizeof( textbuf );
448
449 #if 0
450                         /* FIXME: op->o_bd is still set to the BackendDB 
451                          * structure of the database that tried to handle
452                          * the operation and actually returned a referral
453                          * ... */
454                         assert( SLAP_DBFLAGS( op->o_bd ) & SLAP_DBFLAG_GLOBAL_OVERLAY );
455 #endif
456
457                         /* global overlay: create entry */
458                         /* NOTE: this is a hack to use the chain overlay
459                          * as global.  I expect to be able to remove this
460                          * soon by using slap_mods2entry() earlier in
461                          * do_add(), adding the operational attrs later
462                          * if required. */
463                         rs->sr_err = slap_mods2entry( op->ora_modlist,
464                                         &op->ora_e, 0, 1,
465                                         &rs->sr_text, textbuf, textlen );
466                         if ( rs->sr_err != LDAP_SUCCESS ) {
467                                 send_ldap_result( op, rs );
468                                 rc = 1;
469                                 break;
470                         }
471                 }
472                 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref );
473                 if ( cleanup_attrs ) {
474                         attrs_free( op->ora_e->e_attrs );
475                         op->ora_e->e_attrs = NULL;
476                 }
477                 break;
478                 }
479         case LDAP_REQ_DELETE:
480                 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref );
481                 break;
482         case LDAP_REQ_MODRDN:
483                 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref );
484                 break;
485         case LDAP_REQ_MODIFY:
486                 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref );
487                 break;
488         case LDAP_REQ_COMPARE:
489                 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref );
490                 break;
491         case LDAP_REQ_SEARCH:
492                 if ( rs->sr_type == REP_SEARCHREF ) {
493                         struct berval   *curr = ref,
494                                         odn = op->o_req_dn,
495                                         ondn = op->o_req_ndn;
496
497 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
498                         LDAPControl     **ctrls = NULL;
499         
500                         (void)chaining_control_add( lc, op, &ctrls );
501 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
502
503                         rs->sr_type = REP_SEARCH;
504
505                         sc2.sc_response = ldap_chain_cb_search_response;
506
507                         li = *lip;
508                         li.url = NULL;
509                         op->o_bd->be_private = &li;
510                         
511                         /* if we parse the URI then by no means 
512                          * we can cache stuff or reuse connections, 
513                          * because in back-ldap there's no caching
514                          * based on the URI value, which is supposed
515                          * to be set once for all (correct?) */
516                         op->o_do_not_cache = 1;
517
518                         /* copy the private info because we need to modify it */
519                         for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) {
520                                 LDAPURLDesc     *srv;
521                                 char            *save_dn;
522
523                                 /* parse reference and use
524                                  * proto://[host][:port]/ only */
525                                 rc = ldap_url_parse_ext( curr[0].bv_val, &srv );
526                                 if ( rc != LDAP_URL_SUCCESS ) {
527                                         /* try next */
528                                         rs->sr_err = LDAP_OTHER;
529                                         continue;
530                                 }
531
532                                 /* remove DN essentially because later on 
533                                  * ldap_initialize() will parse the URL 
534                                  * as a comma-separated URL list */
535                                 save_dn = srv->lud_dn;
536                                 srv->lud_dn = "";
537                                 srv->lud_scope = LDAP_SCOPE_DEFAULT;
538                                 li.url = ldap_url_desc2str( srv );
539                                 if ( li.url != NULL ) {
540                                         ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
541                                                         op->o_tmpmemctx );
542                                         ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
543                                                         op->o_tmpmemctx );
544                                 }
545
546                                 srv->lud_dn = save_dn;
547                                 ldap_free_urldesc( srv );
548
549                                 if ( li.url == NULL ) {
550                                         /* try next */
551                                         rs->sr_err = LDAP_OTHER;
552                                         continue;
553                                 }
554
555
556                                 /* FIXME: should we also copy filter and scope?
557                                  * according to RFC3296, no */
558                                 rc = lback->bi_op_search( op, rs );
559
560                                 ldap_memfree( li.url );
561                                 li.url = NULL;
562
563                                 op->o_tmpfree( op->o_req_dn.bv_val,
564                                                 op->o_tmpmemctx );
565                                 op->o_tmpfree( op->o_req_ndn.bv_val,
566                                                 op->o_tmpmemctx );
567
568                                 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
569                                         break;
570                                 }
571
572                                 rc = rs->sr_err;
573                         }
574
575 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
576                         (void)chaining_control_remove( op, &ctrls );
577 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
578
579                         op->o_req_dn = odn;
580                         op->o_req_ndn = ondn;
581                         rs->sr_type = REP_SEARCHREF;
582                         rs->sr_entry = NULL;
583
584                         if ( rc != LDAP_SUCCESS ) {
585                                 /* couldn't chase any of the referrals */
586                                 rc = SLAP_CB_CONTINUE;
587                         }
588                         
589                 } else {
590                         rc = ldap_chain_op( op, rs, lback->bi_op_search, ref );
591                 }
592                 break;
593         case LDAP_REQ_EXTENDED:
594                 rc = ldap_chain_op( op, rs, lback->bi_extended, ref );
595                 /* FIXME: ldap_back_extended() by design 
596                  * doesn't send result; frontend is expected
597                  * to send it... */
598                 if ( rc != SLAPD_ABANDON ) {
599                         send_ldap_extended( op, rs );
600                         rc = LDAP_SUCCESS;
601                 }
602                 break;
603         default:
604                 rc = SLAP_CB_CONTINUE;
605                 break;
606         }
607
608 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
609         if ( rc != LDAP_SUCCESS || sc2.sc_private == LDAP_CH_ERR ) {
610                 if ( rs->sr_err == LDAP_CANNOT_CHAIN ) {
611                         goto cannot_chain;
612                 }
613
614                 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
615                 case LDAP_CHAINING_REQUIRED:
616 cannot_chain:;
617                         op->o_callback = NULL;
618                         send_ldap_error( op, rs, LDAP_CANNOT_CHAIN, "operation cannot be completed without chaining" );
619                         break;
620
621                 default:
622                         rc = SLAP_CB_CONTINUE;
623                         rs->sr_err = sr_err;
624                         rs->sr_type = sr_type;
625                         break;
626                 }
627                 goto dont_chain;
628         }
629 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
630
631         if ( sc2.sc_private == LDAP_CH_NONE ) {
632                 op->o_callback = NULL;
633                 rc = rs->sr_err = slap_map_api2result( rs );
634                 send_ldap_result( op, rs );
635         }
636
637 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
638 dont_chain:;
639 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
640         op->o_do_not_cache = cache;
641         op->o_bd->be_private = private;
642         op->o_callback = sc;
643         op->o_ndn = ndn;
644         rs->sr_ref = ref;
645
646         return rc;
647 }
648
649 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
650 static int
651 ldap_chain_parse_ctrl(
652         Operation       *op,
653         SlapReply       *rs,
654         LDAPControl     *ctrl );
655
656 static int
657 str2chain( const char *s )
658 {
659         if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
660                 return LDAP_CHAINING_PREFERRED;
661                 
662         } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
663                 return LDAP_CHAINING_REQUIRED;
664
665         } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
666                 return LDAP_REFERRALS_PREFERRED;
667                 
668         } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
669                 return LDAP_REFERRALS_REQUIRED;
670         }
671
672         return -1;
673 }
674 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
675
676 static int
677 ldap_chain_db_config(
678         BackendDB       *be,
679         const char      *fname,
680         int             lineno,
681         int             argc,
682         char    **argv
683 )
684 {
685         slap_overinst   *on = (slap_overinst *) be->bd_info;
686         ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
687         void            *private = be->be_private;
688         char            *argv0 = NULL;
689         int             rc;
690
691         if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
692                 argv0 = argv[ 0 ];
693                 argv[ 0 ] = &argv[ 0 ][ STRLENOF( "chain-" ) ];
694
695 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
696                 if ( strcasecmp( argv[ 0 ], "chaining" ) == 0 ) {
697                         char                    **tmpargv = argv;
698                         BerElementBuffer        berbuf;
699                         BerElement              *ber = (BerElement *)&berbuf;
700                         int                     resolve = -1,
701                                                 continuation = -1,
702                                                 iscritical = 0;
703                         Operation               op = { 0 };
704                         SlapReply               rs = { 0 };
705
706                         lc->lc_chaining_ctrlflag = 0;
707
708                         for ( argc--, tmpargv++; argc > 0; argc--, tmpargv++ ) {
709                                 if ( strncasecmp( tmpargv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
710                                         resolve = str2chain( tmpargv[ 0 ] + STRLENOF( "resolve=" ) );
711                                         if ( resolve == -1 ) {
712                                                 fprintf( stderr, "%s line %d: "
713                                                         "illegal <resolve> value %s "
714                                                         "in \"chain-chaining>\"\n",
715                                                         fname, lineno, tmpargv[ 0 ] );
716                                                 return 1;
717                                         }
718
719                                 } else if ( strncasecmp( tmpargv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
720                                         continuation = str2chain( tmpargv[ 0 ] + STRLENOF( "continuation=" ) );
721                                         if ( continuation == -1 ) {
722                                                 fprintf( stderr, "%s line %d: "
723                                                         "illegal <continuation> value %s "
724                                                         "in \"chain-chaining\"\n",
725                                                         fname, lineno, tmpargv[ 0 ] );
726                                                 return 1;
727                                         }
728
729                                 } else if ( strcasecmp( tmpargv[ 0 ], "critical" ) == 0 ) {
730                                         iscritical = 1;
731
732                                 } else {
733                                         fprintf( stderr, "%s line %d: "
734                                                 "unknown option in \"chain-chaining\"\n",
735                                                 fname, lineno );
736                                         return 1;
737                                 }
738                         }
739
740                         if ( resolve != -1 || continuation != -1 ) {
741                                 int     err;
742
743                                 if ( resolve == -1 ) {
744                                         /* default */
745                                         resolve = SLAP_CHAINING_DEFAULT;
746                                 }
747
748                                 ber_init2( ber, NULL, LBER_USE_DER );
749
750                                 err = ber_printf( ber, "{e" /* } */, resolve );
751                                 if ( err == -1 ) {
752                                         ber_free( ber, 1 );
753                                         fprintf( stderr, "%s line %d: "
754                                                 "chaining behavior control encoding error!\n",
755                                                 fname, lineno );
756                                         return 1;
757                                 }
758
759                                 if ( continuation > -1 ) {
760                                         err = ber_printf( ber, "e", continuation );
761                                         if ( err == -1 ) {
762                                                 ber_free( ber, 1 );
763                                                 fprintf( stderr, "%s line %d: "
764                                                         "chaining behavior control encoding error!\n",
765                                                         fname, lineno );
766                                                 return 1;
767                                         }
768                                 }
769
770                                 err = ber_printf( ber, /* { */ "N}" );
771                                 if ( err == -1 ) {
772                                         ber_free( ber, 1 );
773                                         fprintf( stderr, "%s line %d: "
774                                                 "chaining behavior control encoding error!\n",
775                                                 fname, lineno );
776                                         return 1;
777                                 }
778
779                                 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
780                                         exit( EXIT_FAILURE );
781                                 }
782
783                         } else {
784                                 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
785                         }
786
787                         lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
788                         lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
789
790                         if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
791                         {
792                                 fprintf( stderr, "%s line %d: "
793                                         "unable to parse chaining control%s%s\n",
794                                         fname, lineno,
795                                         rs.sr_text ? ": " : "",
796                                         rs.sr_text ? rs.sr_text : "" );
797                                 return 1;
798                         }
799
800                         lc->lc_chaining_ctrlflag = op.o_chaining;
801
802                         lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
803
804                         rc = 0;
805                         goto done;
806                 }
807 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
808         }
809
810
811         be->be_private = lc->lc_li;
812         rc = lback->bi_db_config( be, fname, lineno, argc, argv );
813         be->be_private = private;
814
815 done:;
816         if ( argv0 ) {
817                 argv[ 0 ] = argv0;
818         }
819
820         return rc;
821 }
822
823 static int
824 ldap_chain_db_init(
825         BackendDB *be
826 )
827 {
828         slap_overinst   *on = (slap_overinst *)be->bd_info;
829         ldap_chain_t    *lc = NULL;
830         int             rc;
831         BackendDB       bd = *be;
832
833         if ( lback == NULL ) {
834                 lback = backend_info( "ldap" );
835
836                 if ( lback == NULL ) {
837                         return -1;
838                 }
839         }
840
841         lc = ch_malloc( sizeof( ldap_chain_t ) );
842         memset( lc, 0, sizeof( ldap_chain_t ) );
843
844         bd.be_private = NULL;
845         rc = lback->bi_db_init( &bd );
846         lc->lc_li = (struct ldapinfo *)bd.be_private;
847         on->on_bi.bi_private = (void *)lc;
848
849         return rc;
850 }
851
852 static int
853 ldap_chain_db_open(
854         BackendDB *be
855 )
856 {
857         int     rc = 0;
858
859 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
860         rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
861 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
862
863         return rc;
864 }
865
866 static int
867 ldap_chain_db_destroy(
868         BackendDB *be
869 )
870 {
871         slap_overinst   *on = (slap_overinst *) be->bd_info;
872         ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
873         void            *private = be->be_private;
874         int             rc;
875
876         be->be_private = (void *)lc->lc_li;
877         rc = lback->bi_db_destroy( be );
878         lc->lc_li = be->be_private;
879         ch_free( lc );
880         on->on_bi.bi_private = NULL;
881         be->be_private = private;
882         return rc;
883 }
884
885 static int
886 ldap_chain_connection_destroy(
887         BackendDB *be,
888         Connection *conn
889 )
890 {
891         slap_overinst   *on = (slap_overinst *) be->bd_info;
892         ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
893         void            *private = be->be_private;
894         int             rc;
895
896         be->be_private = (void *)lc->lc_li;
897         rc = lback->bi_connection_destroy( be, conn );
898         be->be_private = private;
899
900         return rc;
901 }
902
903 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
904 static int
905 ldap_chain_parse_ctrl(
906         Operation       *op,
907         SlapReply       *rs,
908         LDAPControl     *ctrl )
909 {
910         ber_tag_t       tag;
911         BerElement      *ber;
912         ber_int_t       mode,
913                         behavior;
914
915         if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
916                 rs->sr_text = "Chaining behavior control specified multiple times";
917                 return LDAP_PROTOCOL_ERROR;
918         }
919
920         if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
921                 rs->sr_text = "Chaining behavior control specified with pagedResults control";
922                 return LDAP_PROTOCOL_ERROR;
923         }
924
925         if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
926                 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
927
928         } else {
929                 ber_len_t       len;
930
931                 /* Parse the control value
932                  *      ChainingBehavior ::= SEQUENCE { 
933                  *           resolveBehavior         Behavior OPTIONAL, 
934                  *           continuationBehavior    Behavior OPTIONAL } 
935                  *                             
936                  *      Behavior :: = ENUMERATED { 
937                  *           chainingPreferred       (0), 
938                  *           chainingRequired        (1), 
939                  *           referralsPreferred      (2), 
940                  *           referralsRequired       (3) } 
941                  */
942
943                 ber = ber_init( &ctrl->ldctl_value );
944                 if( ber == NULL ) {
945                         rs->sr_text = "internal error";
946                         return LDAP_OTHER;
947                 }
948
949                 tag = ber_scanf( ber, "{e" /* } */, &behavior );
950                 /* FIXME: since the whole SEQUENCE is optional,
951                  * should we accept no enumerations at all? */
952                 if ( tag != LBER_ENUMERATED ) {
953                         rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
954                         return LDAP_PROTOCOL_ERROR;
955                 }
956
957                 switch ( behavior ) {
958                 case LDAP_CHAINING_PREFERRED:
959                         mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
960                         break;
961
962                 case LDAP_CHAINING_REQUIRED:
963                         mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
964                         break;
965
966                 case LDAP_REFERRALS_PREFERRED:
967                         mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
968                         break;
969
970                 case LDAP_REFERRALS_REQUIRED:
971                         mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
972                         break;
973
974                 default:
975                         rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
976                         return LDAP_PROTOCOL_ERROR;
977                 }
978
979                 tag = ber_peek_tag( ber, &len );
980                 if ( tag == LBER_ENUMERATED ) {
981                         tag = ber_scanf( ber, "e", &behavior );
982                         if ( tag == LBER_ERROR ) {
983                                 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
984                                 return LDAP_PROTOCOL_ERROR;
985                         }
986                 }
987
988                 if ( tag == LBER_DEFAULT ) {
989                         mode |= SLAP_CH_CONTINUATION_DEFAULT;
990
991                 } else {
992                         switch ( behavior ) {
993                         case LDAP_CHAINING_PREFERRED:
994                                 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
995                                 break;
996
997                         case LDAP_CHAINING_REQUIRED:
998                                 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
999                                 break;
1000
1001                         case LDAP_REFERRALS_PREFERRED:
1002                                 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
1003                                 break;
1004
1005                         case LDAP_REFERRALS_REQUIRED:
1006                                 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
1007                                 break;
1008
1009                         default:
1010                                 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
1011                                 return LDAP_PROTOCOL_ERROR;
1012                         }
1013                 }
1014
1015                 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
1016                         rs->sr_text = "Chaining behavior control: decoding error";
1017                         return LDAP_PROTOCOL_ERROR;
1018                 }
1019
1020                 (void) ber_free( ber, 1 );
1021         }
1022
1023         op->o_chaining = mode | ( ctrl->ldctl_iscritical
1024                         ? SLAP_CONTROL_CRITICAL
1025                         : SLAP_CONTROL_NONCRITICAL );
1026
1027         return LDAP_SUCCESS;
1028 }
1029 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1030
1031 static slap_overinst ldapchain;
1032
1033 int
1034 chain_init( void )
1035 {
1036 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1037         int     rc;
1038
1039         rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
1040                         /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
1041                         ldap_chain_parse_ctrl, &sc_chainingBehavior );
1042         if ( rc != LDAP_SUCCESS ) {
1043                 fprintf( stderr, "Failed to register chaining behavior control: %d\n", rc );
1044                 return rc;
1045         }
1046 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1047
1048         ldapchain.on_bi.bi_type = "chain";
1049         ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
1050         ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
1051         ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
1052         ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
1053
1054         /* ... otherwise the underlying backend's function would be called,
1055          * likely passing an invalid entry; on the contrary, the requested
1056          * operational attributes should have been returned while chasing
1057          * the referrals.  This all in all is a bit messy, because part
1058          * of the operational attributes are generated by the backend;
1059          * part by the frontend; back-ldap should receive all the available
1060          * ones from the remote server, but then, on its own, it strips those
1061          * it assumes will be (re)generated by the frontend (e.g.
1062          * subschemaSubentry.) */
1063         ldapchain.on_bi.bi_operational = ldap_chain_operational;
1064         
1065         ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
1066
1067         ldapchain.on_response = ldap_chain_response;
1068
1069         return overlay_register( &ldapchain );
1070 }
1071