No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / openldap / dist / servers / slapd / back-ldap / chain.c
blobb12d0c3f5f1949be05241dc217cd94f7c4ef332a
1 /* chain.c - chain LDAP operations */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/chain.c,v 1.52.2.7 2008/02/11 23:26:46 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2008 The OpenLDAP Foundation.
6 * Portions Copyright 2003 Howard Chu.
7 * All rights reserved.
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.
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>.
17 /* ACKNOWLEDGEMENTS:
18 * This work was initially developed by the Howard Chu for inclusion
19 * in OpenLDAP Software.
20 * This work was subsequently modified by Pierangelo Masarati.
23 #include "portable.h"
25 #include <stdio.h>
27 #include <ac/string.h>
28 #include <ac/socket.h>
30 #include "lutil.h"
31 #include "slap.h"
32 #include "back-ldap.h"
33 #include "config.h"
35 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
36 #define SLAP_CHAINING_DEFAULT LDAP_CHAINING_PREFERRED
37 #define SLAP_CH_RESOLVE_SHIFT SLAP_CONTROL_SHIFT
38 #define SLAP_CH_RESOLVE_MASK (0x3 << SLAP_CH_RESOLVE_SHIFT)
39 #define SLAP_CH_RESOLVE_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
40 #define SLAP_CH_RESOLVE_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
41 #define SLAP_CH_RESOLVE_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
42 #define SLAP_CH_RESOLVE_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
43 #define SLAP_CH_RESOLVE_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_RESOLVE_SHIFT)
44 #define SLAP_CH_CONTINUATION_SHIFT (SLAP_CH_RESOLVE_SHIFT + 2)
45 #define SLAP_CH_CONTINUATION_MASK (0x3 << SLAP_CH_CONTINUATION_SHIFT)
46 #define SLAP_CH_CONTINUATION_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
47 #define SLAP_CH_CONTINUATION_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
48 #define SLAP_CH_CONTINUATION_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
49 #define SLAP_CH_CONTINUATION_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
50 #define SLAP_CH_CONTINUATION_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_CONTINUATION_SHIFT)
52 #define o_chaining o_ctrlflag[sc_chainingBehavior]
53 #define get_chaining(op) ((op)->o_chaining & SLAP_CONTROL_MASK)
54 #define get_chainingBehavior(op) ((op)->o_chaining & (SLAP_CH_RESOLVE_MASK|SLAP_CH_CONTINUATION_MASK))
55 #define get_resolveBehavior(op) ((op)->o_chaining & SLAP_CH_RESOLVE_MASK)
56 #define get_continuationBehavior(op) ((op)->o_chaining & SLAP_CH_CONTINUATION_MASK)
58 static int sc_chainingBehavior;
59 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
61 typedef enum {
62 LDAP_CH_NONE = 0,
63 LDAP_CH_RES,
64 LDAP_CH_ERR
65 } ldap_chain_status_t;
66 static BackendInfo *lback;
68 typedef struct ldap_chain_t {
70 * A "template" ldapinfo_t gets all common configuration items;
71 * then, for each configured URI, an entry is created in the tree;
72 * all the specific configuration items get in the current URI
73 * structure.
75 * Then, for each referral, extract the URI and lookup the
76 * related structure. If configured to do so, allow URIs
77 * not found in the structure to create a temporary one
78 * that chains anonymously; maybe it can also be added to
79 * the tree? Should be all configurable.
82 /* "common" configuration info (anything occurring before an "uri") */
83 ldapinfo_t *lc_common_li;
85 /* current configuration info */
86 ldapinfo_t *lc_cfg_li;
88 /* tree of configured[/generated?] "uri" info */
89 ldap_avl_info_t lc_lai;
91 /* max depth in nested referrals chaining */
92 int lc_max_depth;
94 unsigned lc_flags;
95 #define LDAP_CHAIN_F_NONE (0x00U)
96 #define LDAP_CHAIN_F_CHAINING (0x01U)
97 #define LDAP_CHAIN_F_CACHE_URI (0x02U)
98 #define LDAP_CHAIN_F_RETURN_ERR (0x04U)
100 #define LDAP_CHAIN_ISSET(lc, f) ( ( (lc)->lc_flags & (f) ) == (f) )
101 #define LDAP_CHAIN_CHAINING( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CHAINING )
102 #define LDAP_CHAIN_CACHE_URI( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CACHE_URI )
103 #define LDAP_CHAIN_RETURN_ERR( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_RETURN_ERR )
105 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
106 LDAPControl lc_chaining_ctrl;
107 char lc_chaining_ctrlflag;
108 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
109 } ldap_chain_t;
111 static int ldap_chain_db_init_common( BackendDB *be );
112 static int ldap_chain_db_init_one( BackendDB *be );
113 static int ldap_chain_db_open_one( BackendDB *be );
114 #define ldap_chain_db_close_one(be) (0)
115 #define ldap_chain_db_destroy_one(be, rs) (lback)->bi_db_destroy( (be), (rs) )
117 typedef struct ldap_chain_cb_t {
118 ldap_chain_status_t lb_status;
119 ldap_chain_t *lb_lc;
120 BI_op_func *lb_op_f;
121 int lb_depth;
122 } ldap_chain_cb_t;
124 static int
125 ldap_chain_op(
126 Operation *op,
127 SlapReply *rs,
128 BI_op_func *op_f,
129 BerVarray ref,
130 int depth );
132 static int
133 ldap_chain_search(
134 Operation *op,
135 SlapReply *rs,
136 BerVarray ref,
137 int depth );
139 static slap_overinst ldapchain;
141 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
142 static int
143 chaining_control_add(
144 ldap_chain_t *lc,
145 Operation *op,
146 LDAPControl ***oldctrlsp )
148 LDAPControl **ctrls = NULL;
149 int c = 0;
151 *oldctrlsp = op->o_ctrls;
153 /* default chaining control not defined */
154 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
155 return 0;
158 /* already present */
159 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
160 return 0;
163 /* FIXME: check other incompatibilities */
165 /* add to other controls */
166 if ( op->o_ctrls ) {
167 for ( c = 0; op->o_ctrls[ c ]; c++ )
168 /* count them */ ;
171 ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
172 ctrls[ 0 ] = &lc->lc_chaining_ctrl;
173 if ( op->o_ctrls ) {
174 for ( c = 0; op->o_ctrls[ c ]; c++ ) {
175 ctrls[ c + 1 ] = op->o_ctrls[ c ];
178 ctrls[ c + 1 ] = NULL;
180 op->o_ctrls = ctrls;
182 op->o_chaining = lc->lc_chaining_ctrlflag;
184 return 0;
187 static int
188 chaining_control_remove(
189 Operation *op,
190 LDAPControl ***oldctrlsp )
192 LDAPControl **oldctrls = *oldctrlsp;
194 /* we assume that the first control is the chaining control
195 * added by the chain overlay, so it's the only one we explicitly
196 * free */
197 if ( op->o_ctrls != oldctrls ) {
198 assert( op->o_ctrls != NULL );
199 assert( op->o_ctrls[ 0 ] != NULL );
201 free( op->o_ctrls );
203 op->o_chaining = 0;
204 op->o_ctrls = oldctrls;
207 *oldctrlsp = NULL;
209 return 0;
211 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
213 static int
214 ldap_chain_uri_cmp( const void *c1, const void *c2 )
216 const ldapinfo_t *li1 = (const ldapinfo_t *)c1;
217 const ldapinfo_t *li2 = (const ldapinfo_t *)c2;
219 assert( li1->li_bvuri != NULL );
220 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
221 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
223 assert( li2->li_bvuri != NULL );
224 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
225 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
227 /* If local DNs don't match, it is definitely not a match */
228 return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
231 static int
232 ldap_chain_uri_dup( void *c1, void *c2 )
234 ldapinfo_t *li1 = (ldapinfo_t *)c1;
235 ldapinfo_t *li2 = (ldapinfo_t *)c2;
237 assert( li1->li_bvuri != NULL );
238 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
239 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
241 assert( li2->li_bvuri != NULL );
242 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
243 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
245 /* Cannot have more than one shared session with same DN */
246 if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
247 return -1;
250 return 0;
254 * Search specific response that strips entryDN from entries
256 static int
257 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
259 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
261 assert( op->o_tag == LDAP_REQ_SEARCH );
263 /* if in error, don't proceed any further */
264 if ( lb->lb_status == LDAP_CH_ERR ) {
265 return 0;
268 if ( rs->sr_type == REP_SEARCH ) {
269 Attribute **ap = &rs->sr_entry->e_attrs;
271 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
272 /* will be generated later by frontend
273 * (a cleaner solution would be that
274 * the frontend checks if it already exists */
275 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
277 Attribute *a = *ap;
279 *ap = (*ap)->a_next;
280 attr_free( a );
282 /* there SHOULD be one only! */
283 break;
287 /* tell the frontend not to add generated
288 * operational attributes */
289 rs->sr_flags |= REP_NO_OPERATIONALS;
291 return SLAP_CB_CONTINUE;
293 } else if ( rs->sr_type == REP_SEARCHREF ) {
294 /* if we get it here, it means the library was unable
295 * to chase the referral... */
296 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
297 rs->sr_err = ldap_chain_search( op, rs, rs->sr_ref, lb->lb_depth );
300 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
301 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
302 switch ( get_continuationBehavior( op ) ) {
303 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
304 lb->lb_status = LDAP_CH_ERR;
305 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
307 default:
308 break;
311 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
312 return SLAP_CB_CONTINUE;
314 } else if ( rs->sr_type == REP_RESULT ) {
315 if ( rs->sr_err == LDAP_REFERRAL
316 && lb->lb_depth < lb->lb_lc->lc_max_depth
317 && rs->sr_ref != NULL )
319 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
322 /* back-ldap tried to send result */
323 lb->lb_status = LDAP_CH_RES;
326 return 0;
330 * Dummy response that simply traces if back-ldap tried to send
331 * anything to the client
333 static int
334 ldap_chain_cb_response( Operation *op, SlapReply *rs )
336 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
338 /* if in error, don't proceed any further */
339 if ( lb->lb_status == LDAP_CH_ERR ) {
340 return 0;
343 if ( rs->sr_type == REP_RESULT ) {
344 retry:;
345 switch ( rs->sr_err ) {
346 case LDAP_COMPARE_TRUE:
347 case LDAP_COMPARE_FALSE:
348 if ( op->o_tag != LDAP_REQ_COMPARE ) {
349 return rs->sr_err;
351 /* fallthru */
353 case LDAP_SUCCESS:
354 lb->lb_status = LDAP_CH_RES;
355 break;
357 case LDAP_REFERRAL:
358 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
359 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
360 goto retry;
363 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
364 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
365 switch ( get_continuationBehavior( op ) ) {
366 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
367 lb->lb_status = LDAP_CH_ERR;
368 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
370 default:
371 break;
374 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
375 break;
377 default:
378 return rs->sr_err;
381 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
383 /* strip the entryDN attribute, but keep returning results */
384 (void)ldap_chain_cb_search_response( op, rs );
387 return SLAP_CB_CONTINUE;
390 static int
391 ldap_chain_op(
392 Operation *op,
393 SlapReply *rs,
394 BI_op_func *op_f,
395 BerVarray ref,
396 int depth )
398 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
399 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
400 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
401 ldapinfo_t li = { 0 }, *lip = NULL;
402 struct berval bvuri[ 2 ] = { { 0 } };
404 /* NOTE: returned if ref is empty... */
405 int rc = LDAP_OTHER,
406 first_rc;
408 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
409 LDAPControl **ctrls = NULL;
411 (void)chaining_control_add( lc, op, &ctrls );
412 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
414 li.li_bvuri = bvuri;
415 first_rc = -1;
416 for ( ; !BER_BVISNULL( ref ); ref++ ) {
417 SlapReply rs2 = { 0 };
418 LDAPURLDesc *srv = NULL;
419 struct berval save_req_dn = op->o_req_dn,
420 save_req_ndn = op->o_req_ndn,
421 dn = BER_BVNULL,
422 pdn = BER_BVNULL,
423 ndn = BER_BVNULL;
424 int temporary = 0;
426 /* We're setting the URI of the first referral;
427 * what if there are more?
429 Document: RFC 4511
431 4.1.10. Referral
433 If the client wishes to progress the operation, it MUST follow the
434 referral by contacting one of the supported services. If multiple
435 URIs are present, the client assumes that any supported URI may be
436 used to progress the operation.
438 * so we actually need to follow exactly one,
439 * and we can assume any is fine.
442 /* parse reference and use
443 * proto://[host][:port]/ only */
444 rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
445 if ( rc != LDAP_URL_SUCCESS ) {
446 /* try next */
447 rc = LDAP_OTHER;
448 continue;
451 /* normalize DN */
452 rc = LDAP_SUCCESS;
453 srv->lud_scope = LDAP_SCOPE_DEFAULT;
454 if ( srv->lud_dn != NULL ) {
455 ber_str2bv( srv->lud_dn, 0, 0, &dn );
456 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
457 if ( rc == LDAP_SUCCESS ) {
458 /* remove DN essentially because later on
459 * ldap_initialize() will parse the URL
460 * as a comma-separated URL list */
461 srv->lud_dn = "";
464 } else {
465 srv->lud_dn = "";
468 li.li_uri = ldap_url_desc2str( srv );
469 srv->lud_dn = dn.bv_val;
470 ldap_free_urldesc( srv );
472 if ( rc != LDAP_SUCCESS ) {
473 /* try next */
474 rc = LDAP_OTHER;
475 continue;
478 if ( li.li_uri == NULL ) {
479 /* try next */
480 rc = LDAP_OTHER;
481 goto further_cleanup;
484 op->o_req_dn = pdn;
485 op->o_req_ndn = ndn;
487 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
489 /* Searches for a ldapinfo in the avl tree */
490 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
491 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
492 (caddr_t)&li, ldap_chain_uri_cmp );
493 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
495 if ( lip != NULL ) {
496 op->o_bd->be_private = (void *)lip;
498 } else {
499 rc = ldap_chain_db_init_one( op->o_bd );
500 if ( rc != 0 ) {
501 goto cleanup;
503 lip = (ldapinfo_t *)op->o_bd->be_private;
504 lip->li_uri = li.li_uri;
505 lip->li_bvuri = bvuri;
506 rc = ldap_chain_db_open_one( op->o_bd );
507 if ( rc != 0 ) {
508 lip->li_uri = NULL;
509 lip->li_bvuri = NULL;
510 (void)ldap_chain_db_destroy_one( op->o_bd, NULL);
511 goto cleanup;
514 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
515 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
516 if ( avl_insert( &lc->lc_lai.lai_tree,
517 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
519 /* someone just inserted another;
520 * don't bother, use this and then
521 * just free it */
522 temporary = 1;
524 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
526 } else {
527 temporary = 1;
531 lb->lb_op_f = op_f;
532 lb->lb_depth = depth + 1;
534 rc = op_f( op, &rs2 );
536 /* note the first error */
537 if ( first_rc == -1 ) {
538 first_rc = rc;
541 cleanup:;
542 ldap_memfree( li.li_uri );
543 li.li_uri = NULL;
545 if ( temporary ) {
546 lip->li_uri = NULL;
547 lip->li_bvuri = NULL;
548 (void)ldap_chain_db_close_one( op->o_bd );
549 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
552 further_cleanup:;
553 if ( !BER_BVISNULL( &pdn ) ) {
554 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
556 op->o_req_dn = save_req_dn;
558 if ( !BER_BVISNULL( &ndn ) ) {
559 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
561 op->o_req_ndn = save_req_ndn;
563 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
564 *rs = rs2;
565 break;
568 rc = rs2.sr_err;
571 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
572 (void)chaining_control_remove( op, &ctrls );
573 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
575 if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
576 rc = first_rc;
579 return rc;
582 static int
583 ldap_chain_search(
584 Operation *op,
585 SlapReply *rs,
586 BerVarray ref,
587 int depth )
590 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
591 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
592 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
593 ldapinfo_t li = { 0 }, *lip = NULL;
594 struct berval bvuri[ 2 ] = { { 0 } };
596 struct berval odn = op->o_req_dn,
597 ondn = op->o_req_ndn;
598 slap_response *save_response = op->o_callback->sc_response;
600 int rc = LDAP_OTHER,
601 first_rc = -1;
603 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
604 LDAPControl **ctrls = NULL;
606 (void)chaining_control_add( lc, op, &ctrls );
607 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
609 rs->sr_type = REP_SEARCH;
611 op->o_callback->sc_response = ldap_chain_cb_search_response;
613 /* if we parse the URI then by no means
614 * we can cache stuff or reuse connections,
615 * because in back-ldap there's no caching
616 * based on the URI value, which is supposed
617 * to be set once for all (correct?) */
618 li.li_bvuri = bvuri;
619 for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
620 SlapReply rs2 = { 0 };
621 LDAPURLDesc *srv;
622 struct berval save_req_dn = op->o_req_dn,
623 save_req_ndn = op->o_req_ndn,
625 pdn = BER_BVNULL,
626 ndn = BER_BVNULL;
627 int temporary = 0;
629 /* parse reference and use
630 * proto://[host][:port]/ only */
631 rc = ldap_url_parse_ext( ref[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
632 if ( rc != LDAP_URL_SUCCESS ) {
633 /* try next */
634 rs->sr_err = LDAP_OTHER;
635 continue;
638 /* normalize DN */
639 rc = LDAP_INVALID_SYNTAX;
640 if ( srv->lud_dn != NULL ) {
641 ber_str2bv( srv->lud_dn, 0, 0, &dn );
642 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
643 if ( rc == LDAP_SUCCESS ) {
644 /* remove DN essentially because later on
645 * ldap_initialize() will parse the URL
646 * as a comma-separated URL list */
647 srv->lud_dn = "";
648 srv->lud_scope = LDAP_SCOPE_DEFAULT;
649 li.li_uri = ldap_url_desc2str( srv );
650 srv->lud_dn = dn.bv_val;
653 ldap_free_urldesc( srv );
655 if ( rc != LDAP_SUCCESS ) {
656 /* try next */
657 rc = LDAP_OTHER;
658 continue;
661 if ( li.li_uri == NULL ) {
662 /* try next */
663 rc = LDAP_OTHER;
664 goto further_cleanup;
667 op->o_req_dn = pdn;
668 op->o_req_ndn = ndn;
670 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
672 /* Searches for a ldapinfo in the avl tree */
673 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
674 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
675 (caddr_t)&li, ldap_chain_uri_cmp );
676 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
678 if ( lip != NULL ) {
679 op->o_bd->be_private = (void *)lip;
681 } else {
682 /* if none is found, create a temporary... */
683 rc = ldap_chain_db_init_one( op->o_bd );
684 if ( rc != 0 ) {
685 goto cleanup;
687 lip = (ldapinfo_t *)op->o_bd->be_private;
688 lip->li_uri = li.li_uri;
689 lip->li_bvuri = bvuri;
690 rc = ldap_chain_db_open_one( op->o_bd );
691 if ( rc != 0 ) {
692 lip->li_uri = NULL;
693 lip->li_bvuri = NULL;
694 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
695 goto cleanup;
698 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
699 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
700 if ( avl_insert( &lc->lc_lai.lai_tree,
701 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
703 /* someone just inserted another;
704 * don't bother, use this and then
705 * just free it */
706 temporary = 1;
708 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
710 } else {
711 temporary = 1;
715 lb->lb_op_f = lback->bi_op_search;
716 lb->lb_depth = depth + 1;
718 /* FIXME: should we also copy filter and scope?
719 * according to RFC3296, no */
720 rc = lback->bi_op_search( op, &rs2 );
721 if ( first_rc == -1 ) {
722 first_rc = rc;
725 cleanup:;
726 ldap_memfree( li.li_uri );
727 li.li_uri = NULL;
729 if ( temporary ) {
730 lip->li_uri = NULL;
731 lip->li_bvuri = NULL;
732 (void)ldap_chain_db_close_one( op->o_bd );
733 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
736 further_cleanup:;
737 if ( !BER_BVISNULL( &pdn ) ) {
738 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
740 op->o_req_dn = save_req_dn;
742 if ( !BER_BVISNULL( &ndn ) ) {
743 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
745 op->o_req_ndn = save_req_ndn;
747 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
748 *rs = rs2;
749 break;
752 rc = rs2.sr_err;
755 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
756 (void)chaining_control_remove( op, &ctrls );
757 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
759 op->o_req_dn = odn;
760 op->o_req_ndn = ondn;
761 op->o_callback->sc_response = save_response;
762 rs->sr_type = REP_SEARCHREF;
763 rs->sr_entry = NULL;
765 if ( rc != LDAP_SUCCESS ) {
766 /* couldn't chase any of the referrals */
767 if ( first_rc != -1 ) {
768 rc = first_rc;
770 } else {
771 rc = SLAP_CB_CONTINUE;
775 return rc;
778 static int
779 ldap_chain_response( Operation *op, SlapReply *rs )
781 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
782 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
783 BackendDB db, *bd = op->o_bd;
784 ldap_chain_cb_t lb = { 0 };
785 slap_callback *sc = op->o_callback,
786 sc2 = { 0 };
787 int rc = 0;
788 const char *text = NULL;
789 const char *matched;
790 BerVarray ref;
791 struct berval ndn = op->o_ndn;
793 int sr_err = rs->sr_err;
794 slap_reply_t sr_type = rs->sr_type;
795 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
796 slap_mask_t chain_mask = 0;
797 ber_len_t chain_shift = 0;
798 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
800 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
801 return SLAP_CB_CONTINUE;
804 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
805 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
806 switch ( get_resolveBehavior( op ) ) {
807 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
808 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
809 return SLAP_CB_CONTINUE;
811 default:
812 chain_mask = SLAP_CH_RESOLVE_MASK;
813 chain_shift = SLAP_CH_RESOLVE_SHIFT;
814 break;
817 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
818 switch ( get_continuationBehavior( op ) ) {
819 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
820 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
821 return SLAP_CB_CONTINUE;
823 default:
824 chain_mask = SLAP_CH_CONTINUATION_MASK;
825 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
826 break;
829 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
832 * TODO: add checks on who/when chain operations; e.g.:
833 * a) what identities are authorized
834 * b) what request DN (e.g. only chain requests rooted at <DN>)
835 * c) what referral URIs
836 * d) what protocol scheme (e.g. only ldaps://)
837 * e) what ssf
840 db = *op->o_bd;
841 SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
842 op->o_bd = &db;
844 text = rs->sr_text;
845 rs->sr_text = NULL;
846 matched = rs->sr_matched;
847 rs->sr_matched = NULL;
848 ref = rs->sr_ref;
849 rs->sr_ref = NULL;
851 /* we need this to know if back-ldap returned any result */
852 lb.lb_lc = lc;
853 sc2.sc_private = &lb;
854 sc2.sc_response = ldap_chain_cb_response;
855 op->o_callback = &sc2;
857 /* Chaining can be performed by a privileged user on behalf
858 * of normal users, using the ProxyAuthz control, by exploiting
859 * the identity assertion feature of back-ldap; see idassert-*
860 * directives in slapd-ldap(5).
862 * FIXME: the idassert-authcDN is one, will it be fine regardless
863 * of the URI we obtain from the referral?
866 switch ( op->o_tag ) {
867 case LDAP_REQ_BIND: {
868 struct berval rndn = op->o_req_ndn;
869 Connection *conn = op->o_conn;
871 /* FIXME: can we really get a referral for binds? */
872 op->o_req_ndn = slap_empty_bv;
873 op->o_conn = NULL;
874 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
875 op->o_req_ndn = rndn;
876 op->o_conn = conn;
878 break;
880 case LDAP_REQ_ADD:
881 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
882 break;
884 case LDAP_REQ_DELETE:
885 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
886 break;
888 case LDAP_REQ_MODRDN:
889 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
890 break;
892 case LDAP_REQ_MODIFY:
893 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
894 break;
896 case LDAP_REQ_COMPARE:
897 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
898 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
899 rc = LDAP_SUCCESS;
901 break;
903 case LDAP_REQ_SEARCH:
904 if ( rs->sr_type == REP_SEARCHREF ) {
905 rc = ldap_chain_search( op, rs, ref, 0 );
907 } else {
908 /* we might get here before any database actually
909 * performed a search; in those cases, we need
910 * to check limits, to make sure safe defaults
911 * are in place */
912 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
913 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
915 } else {
916 rc = SLAP_CB_CONTINUE;
919 break;
921 case LDAP_REQ_EXTENDED:
922 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
923 /* FIXME: ldap_back_extended() by design
924 * doesn't send result; frontend is expected
925 * to send it... */
926 /* FIXME: what about chaining? */
927 if ( rc != SLAPD_ABANDON ) {
928 rs->sr_err = rc;
929 send_ldap_extended( op, rs );
930 rc = LDAP_SUCCESS;
932 lb.lb_status = LDAP_CH_RES;
933 break;
935 default:
936 rc = SLAP_CB_CONTINUE;
937 break;
940 switch ( rc ) {
941 case SLAPD_ABANDON:
942 goto dont_chain;
944 case LDAP_SUCCESS:
945 case LDAP_REFERRAL:
946 /* slapd-ldap sent response */
947 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
948 /* FIXME: should we send response? */
949 Debug( LDAP_DEBUG_ANY,
950 "%s: ldap_chain_response: "
951 "overlay should have sent result.\n",
952 op->o_log_prefix, 0, 0 );
954 break;
956 default:
957 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
958 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
959 goto cannot_chain;
962 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
963 case LDAP_CHAINING_REQUIRED:
964 cannot_chain:;
965 op->o_callback = NULL;
966 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
967 "operation cannot be completed without chaining" );
968 goto dont_chain;
970 default:
971 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
972 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
973 rs->sr_err = rc;
974 rs->sr_type = sr_type;
976 } else {
977 rc = SLAP_CB_CONTINUE;
978 rs->sr_err = sr_err;
979 rs->sr_type = sr_type;
980 rs->sr_text = text;
981 rs->sr_matched = matched;
982 rs->sr_ref = ref;
984 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
985 break;
987 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
990 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
991 op->o_callback = NULL;
992 rc = rs->sr_err = slap_map_api2result( rs );
993 send_ldap_result( op, rs );
996 dont_chain:;
997 rs->sr_err = sr_err;
998 rs->sr_type = sr_type;
999 rs->sr_text = text;
1000 rs->sr_matched = matched;
1001 rs->sr_ref = ref;
1002 op->o_bd = bd;
1003 op->o_callback = sc;
1004 op->o_ndn = ndn;
1006 return rc;
1009 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1010 static int
1011 ldap_chain_parse_ctrl(
1012 Operation *op,
1013 SlapReply *rs,
1014 LDAPControl *ctrl );
1016 static int
1017 str2chain( const char *s )
1019 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
1020 return LDAP_CHAINING_PREFERRED;
1022 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
1023 return LDAP_CHAINING_REQUIRED;
1025 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
1026 return LDAP_REFERRALS_PREFERRED;
1028 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
1029 return LDAP_REFERRALS_REQUIRED;
1032 return -1;
1034 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1037 * configuration...
1040 enum {
1041 CH_CHAINING = 1,
1042 CH_CACHE_URI,
1043 CH_MAX_DEPTH,
1044 CH_RETURN_ERR,
1046 CH_LAST
1049 static ConfigDriver chain_cf_gen;
1050 static ConfigCfAdd chain_cfadd;
1051 static ConfigLDAPadd chain_ldadd;
1053 static ConfigTable chaincfg[] = {
1054 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1055 { "chain-chaining", "args",
1056 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
1057 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
1058 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
1059 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
1060 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1061 { "chain-cache-uri", "TRUE/FALSE",
1062 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
1063 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
1064 "DESC 'Enables caching of URIs not present in configuration' "
1065 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1066 { "chain-max-depth", "args",
1067 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
1068 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
1069 "DESC 'max referral depth' "
1070 "SYNTAX OMsInteger "
1071 "EQUALITY integerMatch "
1072 "SINGLE-VALUE )", NULL, NULL },
1073 { "chain-return-error", "TRUE/FALSE",
1074 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1075 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1076 "DESC 'Errors are returned instead of the original referral' "
1077 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1078 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1081 static ConfigOCs chainocs[] = {
1082 { "( OLcfgOvOc:3.1 "
1083 "NAME 'olcChainConfig' "
1084 "DESC 'Chain configuration' "
1085 "SUP olcOverlayConfig "
1086 "MAY ( "
1087 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1088 "olcChainingBehavior $ "
1089 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1090 "olcChainCacheURI $ "
1091 "olcChainMaxReferralDepth $ "
1092 "olcChainReturnError "
1093 ") )",
1094 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1095 { "( OLcfgOvOc:3.2 "
1096 "NAME 'olcChainDatabase' "
1097 "DESC 'Chain remote server configuration' "
1098 "AUXILIARY )",
1099 Cft_Misc, chaincfg, chain_ldadd },
1100 { NULL, 0, NULL }
1103 static int
1104 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1106 slap_overinst *on;
1107 ldap_chain_t *lc;
1109 ldapinfo_t *li;
1111 AttributeDescription *ad = NULL;
1112 Attribute *at;
1113 const char *text;
1115 int rc;
1117 if ( p->ce_type != Cft_Overlay
1118 || !p->ce_bi
1119 || p->ce_bi->bi_cf_ocs != chainocs )
1121 return LDAP_CONSTRAINT_VIOLATION;
1124 on = (slap_overinst *)p->ce_bi;
1125 lc = (ldap_chain_t *)on->on_bi.bi_private;
1127 assert( ca->be == NULL );
1128 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1130 ca->be->bd_info = (BackendInfo *)on;
1132 rc = slap_str2ad( "olcDbURI", &ad, &text );
1133 assert( rc == LDAP_SUCCESS );
1135 at = attr_find( e->e_attrs, ad );
1136 if ( lc->lc_common_li == NULL && at != NULL ) {
1137 /* FIXME: we should generate an empty default entry
1138 * if none is supplied */
1139 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1140 "first underlying database \"%s\" "
1141 "cannot contain attribute \"%s\".\n",
1142 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1143 rc = LDAP_CONSTRAINT_VIOLATION;
1144 goto done;
1146 } else if ( lc->lc_common_li != NULL && at == NULL ) {
1147 /* FIXME: we should generate an empty default entry
1148 * if none is supplied */
1149 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1150 "subsequent underlying database \"%s\" "
1151 "must contain attribute \"%s\".\n",
1152 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1153 rc = LDAP_CONSTRAINT_VIOLATION;
1154 goto done;
1157 if ( lc->lc_common_li == NULL ) {
1158 rc = ldap_chain_db_init_common( ca->be );
1160 } else {
1161 rc = ldap_chain_db_init_one( ca->be );
1164 if ( rc != 0 ) {
1165 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1166 "unable to init %sunderlying database \"%s\".\n",
1167 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
1168 return LDAP_CONSTRAINT_VIOLATION;
1171 li = ca->be->be_private;
1173 if ( lc->lc_common_li == NULL ) {
1174 lc->lc_common_li = li;
1176 } else {
1177 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
1178 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
1179 if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1180 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1182 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1183 "database \"%s\" insert failed.\n",
1184 e->e_name.bv_val, 0, 0 );
1185 rc = LDAP_CONSTRAINT_VIOLATION;
1186 goto done;
1190 done:;
1191 if ( rc != LDAP_SUCCESS ) {
1192 (void)ldap_chain_db_destroy_one( ca->be, NULL );
1193 ch_free( ca->be );
1194 ca->be = NULL;
1197 return rc;
1200 typedef struct ldap_chain_cfadd_apply_t {
1201 Operation *op;
1202 SlapReply *rs;
1203 Entry *p;
1204 ConfigArgs *ca;
1205 int count;
1206 } ldap_chain_cfadd_apply_t;
1208 static int
1209 ldap_chain_cfadd_apply( void *datum, void *arg )
1211 ldapinfo_t *li = (ldapinfo_t *)datum;
1212 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1214 struct berval bv;
1216 /* FIXME: should not hardcode "olcDatabase" here */
1217 bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
1218 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1219 bv.bv_val = lca->ca->cr_msg;
1221 lca->ca->be->be_private = (void *)li;
1222 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1223 &bv, lback->bi_cf_ocs, &chainocs[1] );
1225 lca->count++;
1227 return 0;
1230 static int
1231 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1233 CfEntryInfo *pe = p->e_private;
1234 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1235 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1236 void *priv = (void *)ca->be->be_private;
1238 if ( lback->bi_cf_ocs ) {
1239 ldap_chain_cfadd_apply_t lca = { 0 };
1241 lca.op = op;
1242 lca.rs = rs;
1243 lca.p = p;
1244 lca.ca = ca;
1245 lca.count = 0;
1247 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1249 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1250 &lca, 1, AVL_INORDER );
1252 ca->be->be_private = priv;
1255 return 0;
1258 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1259 static slap_verbmasks chaining_mode[] = {
1260 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1261 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1262 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1263 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1264 { BER_BVNULL, 0 }
1266 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1268 static int
1269 chain_cf_gen( ConfigArgs *c )
1271 slap_overinst *on = (slap_overinst *)c->bi;
1272 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1274 int rc = 0;
1276 if ( c->op == SLAP_CONFIG_EMIT ) {
1277 switch( c->type ) {
1278 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1279 case CH_CHAINING: {
1280 struct berval resolve = BER_BVNULL,
1281 continuation = BER_BVNULL;
1283 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1284 return 1;
1287 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1288 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1290 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1291 + STRLENOF( " " )
1292 + STRLENOF( "continuation=" ) + continuation.bv_len;
1293 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1294 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1295 "resolve=%s continuation=%s",
1296 resolve.bv_val, continuation.bv_val );
1298 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1299 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1300 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1301 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1302 " critical", STRLENOF( " critical" ) + 1 );
1303 c->value_bv.bv_len += STRLENOF( " critical" );
1306 break;
1308 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1310 case CH_CACHE_URI:
1311 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1312 break;
1314 case CH_MAX_DEPTH:
1315 c->value_int = lc->lc_max_depth;
1316 break;
1318 case CH_RETURN_ERR:
1319 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1320 break;
1322 default:
1323 assert( 0 );
1324 rc = 1;
1326 return rc;
1328 } else if ( c->op == LDAP_MOD_DELETE ) {
1329 switch( c->type ) {
1330 case CH_CHAINING:
1331 return 1;
1333 case CH_CACHE_URI:
1334 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1335 break;
1337 case CH_MAX_DEPTH:
1338 c->value_int = 0;
1339 break;
1341 case CH_RETURN_ERR:
1342 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1343 break;
1345 default:
1346 return 1;
1348 return rc;
1351 switch( c->type ) {
1352 case CH_CHAINING: {
1353 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1354 char **argv = c->argv;
1355 int argc = c->argc;
1356 BerElementBuffer berbuf;
1357 BerElement *ber = (BerElement *)&berbuf;
1358 int resolve = -1,
1359 continuation = -1,
1360 iscritical = 0;
1361 Operation op = { 0 };
1362 SlapReply rs = { 0 };
1364 lc->lc_chaining_ctrlflag = 0;
1366 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1367 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1368 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1369 if ( resolve == -1 ) {
1370 Debug( LDAP_DEBUG_ANY, "%s: "
1371 "illegal <resolve> value %s "
1372 "in \"chain-chaining>\".\n",
1373 c->log, argv[ 0 ], 0 );
1374 return 1;
1377 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1378 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1379 if ( continuation == -1 ) {
1380 Debug( LDAP_DEBUG_ANY, "%s: "
1381 "illegal <continuation> value %s "
1382 "in \"chain-chaining\".\n",
1383 c->log, argv[ 0 ], 0 );
1384 return 1;
1387 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1388 iscritical = 1;
1390 } else {
1391 Debug( LDAP_DEBUG_ANY, "%s: "
1392 "unknown option in \"chain-chaining\".\n",
1393 c->log, 0, 0 );
1394 return 1;
1398 if ( resolve != -1 || continuation != -1 ) {
1399 int err;
1401 if ( resolve == -1 ) {
1402 /* default */
1403 resolve = SLAP_CHAINING_DEFAULT;
1406 ber_init2( ber, NULL, LBER_USE_DER );
1408 err = ber_printf( ber, "{e" /* } */, resolve );
1409 if ( err == -1 ) {
1410 ber_free( ber, 1 );
1411 Debug( LDAP_DEBUG_ANY, "%s: "
1412 "chaining behavior control encoding error!\n",
1413 c->log, 0, 0 );
1414 return 1;
1417 if ( continuation > -1 ) {
1418 err = ber_printf( ber, "e", continuation );
1419 if ( err == -1 ) {
1420 ber_free( ber, 1 );
1421 Debug( LDAP_DEBUG_ANY, "%s: "
1422 "chaining behavior control encoding error!\n",
1423 c->log, 0, 0 );
1424 return 1;
1428 err = ber_printf( ber, /* { */ "N}" );
1429 if ( err == -1 ) {
1430 ber_free( ber, 1 );
1431 Debug( LDAP_DEBUG_ANY, "%s: "
1432 "chaining behavior control encoding error!\n",
1433 c->log, 0, 0 );
1434 return 1;
1437 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1438 exit( EXIT_FAILURE );
1441 } else {
1442 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1445 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1446 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1448 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1450 Debug( LDAP_DEBUG_ANY, "%s: "
1451 "unable to parse chaining control%s%s.\n",
1452 c->log, rs.sr_text ? ": " : "",
1453 rs.sr_text ? rs.sr_text : "" );
1454 return 1;
1457 lc->lc_chaining_ctrlflag = op.o_chaining;
1459 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1461 rc = 0;
1462 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1463 Debug( LDAP_DEBUG_ANY, "%s: "
1464 "\"chaining\" control unsupported (ignored).\n",
1465 c->log, 0, 0 );
1466 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1467 } break;
1469 case CH_CACHE_URI:
1470 if ( c->value_int ) {
1471 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1472 } else {
1473 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1475 break;
1477 case CH_MAX_DEPTH:
1478 if ( c->value_int < 0 ) {
1479 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1480 "<%s> invalid max referral depth %d",
1481 c->argv[0], c->value_int );
1482 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1483 c->log, c->cr_msg, 0 );
1484 rc = 1;
1485 break;
1487 lc->lc_max_depth = c->value_int;
1489 case CH_RETURN_ERR:
1490 if ( c->value_int ) {
1491 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1492 } else {
1493 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1495 break;
1497 default:
1498 assert( 0 );
1499 return 1;
1501 return rc;
1504 static int
1505 ldap_chain_db_init(
1506 BackendDB *be,
1507 ConfigReply *cr )
1509 slap_overinst *on = (slap_overinst *)be->bd_info;
1510 ldap_chain_t *lc = NULL;
1512 if ( lback == NULL ) {
1513 static BackendInfo lback2;
1515 lback = backend_info( "ldap" );
1517 if ( lback == NULL ) {
1518 return 1;
1521 lback2 = *lback;
1522 lback2.bi_type = ldapchain.on_bi.bi_type;
1523 lback = &lback2;
1526 lc = ch_malloc( sizeof( ldap_chain_t ) );
1527 if ( lc == NULL ) {
1528 return 1;
1530 memset( lc, 0, sizeof( ldap_chain_t ) );
1531 lc->lc_max_depth = 1;
1532 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1534 on->on_bi.bi_private = (void *)lc;
1536 return 0;
1539 static int
1540 ldap_chain_db_config(
1541 BackendDB *be,
1542 const char *fname,
1543 int lineno,
1544 int argc,
1545 char **argv )
1547 slap_overinst *on = (slap_overinst *)be->bd_info;
1548 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1550 int rc = SLAP_CONF_UNKNOWN;
1552 if ( lc->lc_common_li == NULL ) {
1553 void *be_private = be->be_private;
1554 ldap_chain_db_init_common( be );
1555 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1556 be->be_private = be_private;
1559 /* Something for the chain database? */
1560 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1561 char *save_argv0 = argv[ 0 ];
1562 BackendInfo *bd_info = be->bd_info;
1563 void *be_private = be->be_private;
1564 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1565 static char *allowed_argv[] = {
1566 /* special: put URI here, so in the meanwhile
1567 * it detects whether a new URI is being provided */
1568 "uri",
1569 "nretries",
1570 "timeout",
1571 /* flags */
1572 "tls",
1573 /* FIXME: maybe rebind-as-user should be allowed
1574 * only within known URIs... */
1575 "rebind-as-user",
1576 "chase-referrals",
1577 "t-f-support",
1578 "proxy-whoami",
1579 NULL
1581 int which_argv = -1;
1583 argv[ 0 ] += STRLENOF( "chain-" );
1585 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1586 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1587 break;
1591 if ( allowed_argv[ which_argv ] == NULL ) {
1592 which_argv = -1;
1594 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1595 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1596 "\"%s\" only allowed within a URI directive.\n.",
1597 fname, lineno, argv[ 0 ] );
1598 return 1;
1602 if ( which_argv == 0 ) {
1603 rc = ldap_chain_db_init_one( be );
1604 if ( rc != 0 ) {
1605 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1606 "underlying slapd-ldap initialization failed.\n.",
1607 fname, lineno, 0 );
1608 return 1;
1610 lc->lc_cfg_li = be->be_private;
1613 /* TODO: add checks on what other slapd-ldap(5) args
1614 * should be put in the template; this is not quite
1615 * harmful, because attributes that shouldn't don't
1616 * get actually used, but the user should at least
1617 * be warned.
1620 be->bd_info = lback;
1621 be->be_private = (void *)lc->lc_cfg_li;
1622 be->be_cf_ocs = lback->bi_cf_ocs;
1624 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1626 argv[ 0 ] = save_argv0;
1627 be->be_cf_ocs = be_cf_ocs;
1628 be->be_private = be_private;
1629 be->bd_info = bd_info;
1631 if ( which_argv == 0 ) {
1632 private_destroy:;
1633 if ( rc != 0 ) {
1634 BackendDB db = *be;
1636 db.bd_info = lback;
1637 db.be_private = (void *)lc->lc_cfg_li;
1638 ldap_chain_db_destroy_one( &db, NULL );
1639 lc->lc_cfg_li = NULL;
1641 } else {
1642 if ( lc->lc_cfg_li->li_bvuri == NULL
1643 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1644 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1646 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1647 "no URI list allowed in slapo-chain.\n",
1648 fname, lineno, 0 );
1649 rc = 1;
1650 goto private_destroy;
1653 if ( avl_insert( &lc->lc_lai.lai_tree,
1654 (caddr_t)lc->lc_cfg_li,
1655 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1657 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1658 "duplicate URI in slapo-chain.\n",
1659 fname, lineno, 0 );
1660 rc = 1;
1661 goto private_destroy;
1667 return rc;
1670 enum db_which {
1671 db_open = 0,
1672 db_close,
1673 db_destroy,
1675 db_last
1678 typedef struct ldap_chain_db_apply_t {
1679 BackendDB *be;
1680 BI_db_func *func;
1681 } ldap_chain_db_apply_t;
1683 static int
1684 ldap_chain_db_apply( void *datum, void *arg )
1686 ldapinfo_t *li = (ldapinfo_t *)datum;
1687 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1689 lca->be->be_private = (void *)li;
1691 return lca->func( lca->be, NULL );
1694 static int
1695 ldap_chain_db_func(
1696 BackendDB *be,
1697 enum db_which which
1700 slap_overinst *on = (slap_overinst *)be->bd_info;
1701 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1703 int rc = 0;
1705 if ( lc ) {
1706 BI_db_func *func = (&lback->bi_db_open)[ which ];
1708 if ( func != NULL && lc->lc_common_li != NULL ) {
1709 BackendDB db = *be;
1711 db.bd_info = lback;
1712 db.be_private = lc->lc_common_li;
1714 rc = func( &db, NULL );
1716 if ( rc != 0 ) {
1717 return rc;
1720 if ( lc->lc_lai.lai_tree != NULL ) {
1721 ldap_chain_db_apply_t lca;
1723 lca.be = &db;
1724 lca.func = func;
1726 rc = avl_apply( lc->lc_lai.lai_tree,
1727 ldap_chain_db_apply, (void *)&lca,
1728 1, AVL_INORDER ) != AVL_NOMORE;
1733 return rc;
1736 static int
1737 ldap_chain_db_open(
1738 BackendDB *be,
1739 ConfigReply *cr )
1741 slap_overinst *on = (slap_overinst *) be->bd_info;
1742 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1743 slap_mask_t monitoring;
1744 int rc = 0;
1746 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1747 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1748 if ( rc != 0 ) {
1749 return rc;
1751 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1753 if ( lc->lc_common_li == NULL ) {
1754 void *be_private = be->be_private;
1755 ldap_chain_db_init_common( be );
1756 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1757 be->be_private = be_private;
1760 /* filter out and restore monitoring */
1761 monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING );
1762 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING;
1763 rc = ldap_chain_db_func( be, db_open );
1764 SLAP_DBFLAGS( be ) |= monitoring;
1766 return rc;
1769 static int
1770 ldap_chain_db_close(
1771 BackendDB *be,
1772 ConfigReply *cr )
1774 return ldap_chain_db_func( be, db_close );
1777 static int
1778 ldap_chain_db_destroy(
1779 BackendDB *be,
1780 ConfigReply *cr )
1782 slap_overinst *on = (slap_overinst *) be->bd_info;
1783 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1785 int rc;
1787 rc = ldap_chain_db_func( be, db_destroy );
1789 if ( lc ) {
1790 avl_free( lc->lc_lai.lai_tree, NULL );
1791 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1792 ch_free( lc );
1795 return rc;
1799 * inits one instance of the slapd-ldap backend, and stores
1800 * the private info in be_private of the arg
1802 static int
1803 ldap_chain_db_init_common(
1804 BackendDB *be )
1806 BackendInfo *bi = be->bd_info;
1807 ldapinfo_t *li;
1808 int rc;
1810 be->bd_info = lback;
1811 be->be_private = NULL;
1812 rc = lback->bi_db_init( be, NULL );
1813 if ( rc != 0 ) {
1814 return rc;
1816 li = (ldapinfo_t *)be->be_private;
1817 li->li_urllist_f = NULL;
1818 li->li_urllist_p = NULL;
1820 be->bd_info = bi;
1822 return 0;
1826 * inits one instance of the slapd-ldap backend, stores
1827 * the private info in be_private of the arg and fills
1828 * selected fields with data from the template.
1830 * NOTE: add checks about the other fields of the template,
1831 * which are ignored and SHOULD NOT be configured by the user.
1833 static int
1834 ldap_chain_db_init_one(
1835 BackendDB *be )
1837 slap_overinst *on = (slap_overinst *)be->bd_info;
1838 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1840 BackendInfo *bi = be->bd_info;
1841 ldapinfo_t *li;
1843 slap_op_t t;
1845 be->bd_info = lback;
1846 be->be_private = NULL;
1847 t = lback->bi_db_init( be, NULL );
1848 if ( t != 0 ) {
1849 return t;
1851 li = (ldapinfo_t *)be->be_private;
1852 li->li_urllist_f = NULL;
1853 li->li_urllist_p = NULL;
1855 /* copy common data */
1856 li->li_nretries = lc->lc_common_li->li_nretries;
1857 li->li_flags = lc->lc_common_li->li_flags;
1858 li->li_version = lc->lc_common_li->li_version;
1859 for ( t = 0; t < SLAP_OP_LAST; t++ ) {
1860 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1862 be->bd_info = bi;
1864 return 0;
1867 static int
1868 ldap_chain_db_open_one(
1869 BackendDB *be )
1871 if ( SLAP_DBMONITORING( be ) ) {
1872 ldapinfo_t *li = (ldapinfo_t *)be->be_private;
1874 if ( li->li_uri == NULL ) {
1875 ber_str2bv( "cn=Common Connections", 0, 1,
1876 &li->li_monitor_info.lmi_rdn );
1878 } else {
1879 char *ptr;
1881 li->li_monitor_info.lmi_rdn.bv_len
1882 = STRLENOF( "cn=" ) + strlen( li->li_uri );
1883 ptr = li->li_monitor_info.lmi_rdn.bv_val
1884 = ch_malloc( li->li_monitor_info.lmi_rdn.bv_len + 1 );
1885 ptr = lutil_strcopy( ptr, "cn=" );
1886 ptr = lutil_strcopy( ptr, li->li_uri );
1887 ptr[ 0 ] = '\0';
1891 return lback->bi_db_open( be, NULL );
1894 typedef struct ldap_chain_conn_apply_t {
1895 BackendDB *be;
1896 Connection *conn;
1897 } ldap_chain_conn_apply_t;
1899 static int
1900 ldap_chain_conn_apply( void *datum, void *arg )
1902 ldapinfo_t *li = (ldapinfo_t *)datum;
1903 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1905 lca->be->be_private = (void *)li;
1907 return lback->bi_connection_destroy( lca->be, lca->conn );
1910 static int
1911 ldap_chain_connection_destroy(
1912 BackendDB *be,
1913 Connection *conn
1916 slap_overinst *on = (slap_overinst *) be->bd_info;
1917 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1918 void *private = be->be_private;
1919 ldap_chain_conn_apply_t lca;
1920 int rc;
1922 be->be_private = NULL;
1923 lca.be = be;
1924 lca.conn = conn;
1925 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1926 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1927 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1928 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1929 be->be_private = private;
1931 return rc;
1934 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1935 static int
1936 ldap_chain_parse_ctrl(
1937 Operation *op,
1938 SlapReply *rs,
1939 LDAPControl *ctrl )
1941 ber_tag_t tag;
1942 BerElement *ber;
1943 ber_int_t mode,
1944 behavior;
1946 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1947 rs->sr_text = "Chaining behavior control specified multiple times";
1948 return LDAP_PROTOCOL_ERROR;
1951 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1952 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1953 return LDAP_PROTOCOL_ERROR;
1956 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1957 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1959 } else {
1960 ber_len_t len;
1962 /* Parse the control value
1963 * ChainingBehavior ::= SEQUENCE {
1964 * resolveBehavior Behavior OPTIONAL,
1965 * continuationBehavior Behavior OPTIONAL }
1967 * Behavior :: = ENUMERATED {
1968 * chainingPreferred (0),
1969 * chainingRequired (1),
1970 * referralsPreferred (2),
1971 * referralsRequired (3) }
1974 ber = ber_init( &ctrl->ldctl_value );
1975 if( ber == NULL ) {
1976 rs->sr_text = "internal error";
1977 return LDAP_OTHER;
1980 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1981 /* FIXME: since the whole SEQUENCE is optional,
1982 * should we accept no enumerations at all? */
1983 if ( tag != LBER_ENUMERATED ) {
1984 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1985 return LDAP_PROTOCOL_ERROR;
1988 switch ( behavior ) {
1989 case LDAP_CHAINING_PREFERRED:
1990 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1991 break;
1993 case LDAP_CHAINING_REQUIRED:
1994 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1995 break;
1997 case LDAP_REFERRALS_PREFERRED:
1998 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
1999 break;
2001 case LDAP_REFERRALS_REQUIRED:
2002 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
2003 break;
2005 default:
2006 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
2007 return LDAP_PROTOCOL_ERROR;
2010 tag = ber_peek_tag( ber, &len );
2011 if ( tag == LBER_ENUMERATED ) {
2012 tag = ber_scanf( ber, "e", &behavior );
2013 if ( tag == LBER_ERROR ) {
2014 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
2015 return LDAP_PROTOCOL_ERROR;
2019 if ( tag == LBER_DEFAULT ) {
2020 mode |= SLAP_CH_CONTINUATION_DEFAULT;
2022 } else {
2023 switch ( behavior ) {
2024 case LDAP_CHAINING_PREFERRED:
2025 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
2026 break;
2028 case LDAP_CHAINING_REQUIRED:
2029 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
2030 break;
2032 case LDAP_REFERRALS_PREFERRED:
2033 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
2034 break;
2036 case LDAP_REFERRALS_REQUIRED:
2037 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
2038 break;
2040 default:
2041 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
2042 return LDAP_PROTOCOL_ERROR;
2046 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
2047 rs->sr_text = "Chaining behavior control: decoding error";
2048 return LDAP_PROTOCOL_ERROR;
2051 (void) ber_free( ber, 1 );
2054 op->o_chaining = mode | ( ctrl->ldctl_iscritical
2055 ? SLAP_CONTROL_CRITICAL
2056 : SLAP_CONTROL_NONCRITICAL );
2058 return LDAP_SUCCESS;
2060 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2063 chain_initialize( void )
2065 int rc;
2067 /* Make sure we don't exceed the bits reserved for userland */
2068 config_check_userland( CH_LAST );
2070 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2071 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
2072 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
2073 ldap_chain_parse_ctrl, &sc_chainingBehavior );
2074 if ( rc != LDAP_SUCCESS ) {
2075 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
2076 "unable to register chaining behavior control: %d.\n",
2077 rc, 0, 0 );
2078 return rc;
2080 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2082 ldapchain.on_bi.bi_type = "chain";
2083 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
2084 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
2085 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
2086 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
2087 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
2089 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2091 ldapchain.on_response = ldap_chain_response;
2093 ldapchain.on_bi.bi_cf_ocs = chainocs;
2095 rc = config_register_schema( chaincfg, chainocs );
2096 if ( rc ) {
2097 return rc;
2100 return overlay_register( &ldapchain );