1 /* $NetBSD: chain.c,v 1.3 2021/08/14 16:14:59 christos Exp $ */
2
3 /* chain.c - chain LDAP operations */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2003-2021 The OpenLDAP Foundation.
8 * Portions Copyright 2003 Howard Chu.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted only as authorized by the OpenLDAP
13 * Public License.
14 *
15 * A copy of this license is available in the file LICENSE in the
16 * top-level directory of the distribution or, alternatively, at
17 * <http://www.OpenLDAP.org/license.html>.
18 */
19 /* ACKNOWLEDGEMENTS:
20 * This work was initially developed by the Howard Chu for inclusion
21 * in OpenLDAP Software.
22 * This work was subsequently modified by Pierangelo Masarati.
23 */
24
25 #include <sys/cdefs.h>
26 __RCSID("$NetBSD: chain.c,v 1.3 2021/08/14 16:14:59 christos Exp $");
27
28 #include "portable.h"
29
30 #include <stdio.h>
31
32 #include <ac/string.h>
33 #include <ac/socket.h>
34
35 #include "lutil.h"
36 #include "slap.h"
37 #include "back-ldap.h"
38 #include "slap-config.h"
39
40 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
41 #define SLAP_CHAINING_DEFAULT LDAP_CHAINING_PREFERRED
42 #define SLAP_CH_RESOLVE_SHIFT SLAP_CONTROL_SHIFT
43 #define SLAP_CH_RESOLVE_MASK (0x3 << SLAP_CH_RESOLVE_SHIFT)
44 #define SLAP_CH_RESOLVE_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
45 #define SLAP_CH_RESOLVE_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
46 #define SLAP_CH_RESOLVE_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
47 #define SLAP_CH_RESOLVE_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
48 #define SLAP_CH_RESOLVE_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_RESOLVE_SHIFT)
49 #define SLAP_CH_CONTINUATION_SHIFT (SLAP_CH_RESOLVE_SHIFT + 2)
50 #define SLAP_CH_CONTINUATION_MASK (0x3 << SLAP_CH_CONTINUATION_SHIFT)
51 #define SLAP_CH_CONTINUATION_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
52 #define SLAP_CH_CONTINUATION_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
53 #define SLAP_CH_CONTINUATION_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
54 #define SLAP_CH_CONTINUATION_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
55 #define SLAP_CH_CONTINUATION_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_CONTINUATION_SHIFT)
56
57 #define o_chaining o_ctrlflag[sc_chainingBehavior]
58 #define get_chaining(op) ((op)->o_chaining & SLAP_CONTROL_MASK)
59 #define get_chainingBehavior(op) ((op)->o_chaining & (SLAP_CH_RESOLVE_MASK|SLAP_CH_CONTINUATION_MASK))
60 #define get_resolveBehavior(op) ((op)->o_chaining & SLAP_CH_RESOLVE_MASK)
61 #define get_continuationBehavior(op) ((op)->o_chaining & SLAP_CH_CONTINUATION_MASK)
62
63 static int sc_chainingBehavior;
64 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
65
66 typedef enum {
67 LDAP_CH_NONE = 0,
68 LDAP_CH_RES,
69 LDAP_CH_ERR
70 } ldap_chain_status_t;
71
72 static BackendInfo *lback;
73
74 typedef struct ldap_chain_t {
75 /*
76 * A "template" ldapinfo_t gets all common configuration items;
77 * then, for each configured URI, an entry is created in the tree;
78 * all the specific configuration items get in the current URI
79 * structure.
80 *
81 * Then, for each referral, extract the URI and lookup the
82 * related structure. If configured to do so, allow URIs
83 * not found in the structure to create a temporary one
84 * that chains anonymously; maybe it can also be added to
85 * the tree? Should be all configurable.
86 */
87
88 /* "common" configuration info (anything occurring before an "uri") */
89 ldapinfo_t *lc_common_li;
90
91 /* current configuration info */
92 ldapinfo_t *lc_cfg_li;
93
94 /* tree of configured[/generated?] "uri" info */
95 ldap_avl_info_t lc_lai;
96
97 /* max depth in nested referrals chaining */
98 int lc_max_depth;
99
100 unsigned lc_flags;
101 #define LDAP_CHAIN_F_NONE (0x00U)
102 #define LDAP_CHAIN_F_CHAINING (0x01U)
103 #define LDAP_CHAIN_F_CACHE_URI (0x02U)
104 #define LDAP_CHAIN_F_RETURN_ERR (0x04U)
105
106 #define LDAP_CHAIN_ISSET(lc, f) ( ( (lc)->lc_flags & (f) ) == (f) )
107 #define LDAP_CHAIN_CHAINING( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CHAINING )
108 #define LDAP_CHAIN_CACHE_URI( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CACHE_URI )
109 #define LDAP_CHAIN_RETURN_ERR( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_RETURN_ERR )
110
111 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
112 LDAPControl lc_chaining_ctrl;
113 char lc_chaining_ctrlflag;
114 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
115 } ldap_chain_t;
116
117 static int ldap_chain_db_init_common( BackendDB *be );
118 static int ldap_chain_db_init_one( BackendDB *be );
119 static int ldap_chain_db_open_one( BackendDB *be );
120 #define ldap_chain_db_close_one(be) (0)
121 #define ldap_chain_db_destroy_one(be, rs) (lback)->bi_db_destroy( (be), (rs) )
122
123 typedef struct ldap_chain_cb_t {
124 ldap_chain_status_t lb_status;
125 ldap_chain_t *lb_lc;
126 slap_operation_t lb_op_type;
127 char *lb_text;
128 int lb_depth;
129 } ldap_chain_cb_t;
130
131 static int
132 ldap_chain_op(
133 Operation *op,
134 SlapReply *rs,
135 slap_operation_t op_type,
136 BerVarray ref,
137 int depth );
138
139 static int
140 ldap_chain_search(
141 Operation *op,
142 SlapReply *rs,
143 BerVarray ref,
144 int depth );
145
146 static slap_overinst ldapchain;
147
148 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
149 static int
chaining_control_add(ldap_chain_t * lc,Operation * op,LDAPControl *** oldctrlsp)150 chaining_control_add(
151 ldap_chain_t *lc,
152 Operation *op,
153 LDAPControl ***oldctrlsp )
154 {
155 LDAPControl **ctrls = NULL;
156 int c = 0;
157
158 *oldctrlsp = op->o_ctrls;
159
160 /* default chaining control not defined */
161 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
162 return 0;
163 }
164
165 /* already present */
166 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
167 return 0;
168 }
169
170 /* FIXME: check other incompatibilities */
171
172 /* add to other controls */
173 if ( op->o_ctrls ) {
174 for ( c = 0; op->o_ctrls[ c ]; c++ )
175 /* count them */ ;
176 }
177
178 ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
179 ctrls[ 0 ] = &lc->lc_chaining_ctrl;
180 if ( op->o_ctrls ) {
181 for ( c = 0; op->o_ctrls[ c ]; c++ ) {
182 ctrls[ c + 1 ] = op->o_ctrls[ c ];
183 }
184 }
185 ctrls[ c + 1 ] = NULL;
186
187 op->o_ctrls = ctrls;
188
189 op->o_chaining = lc->lc_chaining_ctrlflag;
190
191 return 0;
192 }
193
194 static int
chaining_control_remove(Operation * op,LDAPControl *** oldctrlsp)195 chaining_control_remove(
196 Operation *op,
197 LDAPControl ***oldctrlsp )
198 {
199 LDAPControl **oldctrls = *oldctrlsp;
200
201 /* we assume that the first control is the chaining control
202 * added by the chain overlay, so it's the only one we explicitly
203 * free */
204 if ( op->o_ctrls != oldctrls ) {
205 if ( op->o_ctrls != NULL ) {
206 assert( op->o_ctrls[ 0 ] != NULL );
207
208 free( op->o_ctrls );
209
210 op->o_chaining = 0;
211 }
212 op->o_ctrls = oldctrls;
213 }
214
215 *oldctrlsp = NULL;
216
217 return 0;
218 }
219 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
220
221 static int
ldap_chain_uri_cmp(const void * c1,const void * c2)222 ldap_chain_uri_cmp( const void *c1, const void *c2 )
223 {
224 const ldapinfo_t *li1 = (const ldapinfo_t *)c1;
225 const ldapinfo_t *li2 = (const ldapinfo_t *)c2;
226
227 assert( li1->li_bvuri != NULL );
228 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
229 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
230
231 assert( li2->li_bvuri != NULL );
232 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
233 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
234
235 return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
236 }
237
238 static int
ldap_chain_uri_dup(void * c1,void * c2)239 ldap_chain_uri_dup( void *c1, void *c2 )
240 {
241 ldapinfo_t *li1 = (ldapinfo_t *)c1;
242 ldapinfo_t *li2 = (ldapinfo_t *)c2;
243
244 assert( li1->li_bvuri != NULL );
245 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
246 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
247
248 assert( li2->li_bvuri != NULL );
249 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
250 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
251
252 if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
253 return -1;
254 }
255
256 return 0;
257 }
258
259 /*
260 * Search specific response that strips entryDN from entries
261 */
262 static int
ldap_chain_cb_search_response(Operation * op,SlapReply * rs)263 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
264 {
265 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
266
267 assert( op->o_tag == LDAP_REQ_SEARCH );
268
269 /* if in error, don't proceed any further */
270 if ( lb->lb_status == LDAP_CH_ERR ) {
271 return 0;
272 }
273
274 if ( rs->sr_type == REP_SEARCH ) {
275 Attribute **ap = &rs->sr_entry->e_attrs;
276
277 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
278 /* will be generated later by frontend
279 * (a cleaner solution would be that
280 * the frontend checks if it already exists */
281 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
282 {
283 Attribute *a = *ap;
284
285 *ap = (*ap)->a_next;
286 attr_free( a );
287
288 /* there SHOULD be one only! */
289 break;
290 }
291 }
292
293 /* tell the frontend not to add generated
294 * operational attributes */
295 rs->sr_flags |= REP_NO_OPERATIONALS;
296
297 return SLAP_CB_CONTINUE;
298
299 } else if ( rs->sr_type == REP_SEARCHREF ) {
300 /* if we get it here, it means the library was unable
301 * to chase the referral... */
302 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
303 rs->sr_err = ldap_chain_search( op, rs, rs->sr_ref, lb->lb_depth );
304 }
305
306 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
307 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
308 switch ( get_continuationBehavior( op ) ) {
309 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
310 lb->lb_status = LDAP_CH_ERR;
311 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
312
313 default:
314 break;
315 }
316 }
317 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
318 return SLAP_CB_CONTINUE;
319
320 } else if ( rs->sr_type == REP_RESULT ) {
321 if ( rs->sr_err == LDAP_REFERRAL
322 && lb->lb_depth < lb->lb_lc->lc_max_depth
323 && rs->sr_ref != NULL )
324 {
325 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_type,
326 rs->sr_ref, lb->lb_depth );
327 }
328
329 /* back-ldap tried to send result */
330 lb->lb_status = LDAP_CH_RES;
331 /* don't let other callbacks run, this isn't
332 * the real result for this op.
333 */
334 op->o_callback->sc_next = NULL;
335 }
336
337 return 0;
338 }
339
340 /*
341 * Dummy response that simply traces if back-ldap tried to send
342 * anything to the client
343 */
344 static int
ldap_chain_cb_response(Operation * op,SlapReply * rs)345 ldap_chain_cb_response( Operation *op, SlapReply *rs )
346 {
347 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
348
349 /* if in error, don't proceed any further */
350 if ( lb->lb_status == LDAP_CH_ERR ) {
351 return 0;
352 }
353
354 if ( rs->sr_type == REP_RESULT ) {
355 retry:;
356 switch ( rs->sr_err ) {
357 case LDAP_COMPARE_TRUE:
358 case LDAP_COMPARE_FALSE:
359 if ( op->o_tag != LDAP_REQ_COMPARE ) {
360 return rs->sr_err;
361 }
362 /* fallthru */
363
364 case LDAP_SUCCESS:
365 lb->lb_status = LDAP_CH_RES;
366 break;
367
368 case LDAP_REFERRAL:
369 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
370 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_type,
371 rs->sr_ref, lb->lb_depth );
372 goto retry;
373 }
374
375 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
376 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
377 switch ( get_continuationBehavior( op ) ) {
378 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
379 lb->lb_status = LDAP_CH_ERR;
380 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
381
382 default:
383 break;
384 }
385 }
386 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
387 break;
388
389 default:
390 /* remember the text before it's freed in ldap_back_op_result */
391 if ( lb->lb_text ) {
392 ber_memfree_x( lb->lb_text, op->o_tmpmemctx );
393 }
394 lb->lb_text = ber_strdup_x( rs->sr_text, op->o_tmpmemctx );
395 return rs->sr_err;
396 }
397
398 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
399 {
400 /* strip the entryDN attribute, but keep returning results */
401 (void)ldap_chain_cb_search_response( op, rs );
402 }
403
404 return SLAP_CB_CONTINUE;
405 }
406
407 static int
ldap_chain_op(Operation * op,SlapReply * rs,slap_operation_t op_type,BerVarray ref,int depth)408 ldap_chain_op(
409 Operation *op,
410 SlapReply *rs,
411 slap_operation_t op_type,
412 BerVarray ref,
413 int depth )
414 {
415 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
416 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
417 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
418 struct berval odn = op->o_req_dn,
419 ondn = op->o_req_ndn;
420 ldapinfo_t li = { 0 }, *lip = NULL;
421 struct berval bvuri[ 2 ] = { { 0 } };
422
423 /* NOTE: returned if ref is empty... */
424 int rc = LDAP_OTHER,
425 first_rc;
426
427 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
428 LDAPControl **ctrls = NULL;
429
430 (void)chaining_control_add( lc, op, &ctrls );
431 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
432
433 li.li_bvuri = bvuri;
434 first_rc = -1;
435 for ( ; !BER_BVISNULL( ref ); ref++ ) {
436 SlapReply rs2 = { 0 };
437 LDAPURLDesc *srv = NULL;
438 req_search_s save_oq_search = op->oq_search,
439 tmp_oq_search = { 0 };
440 struct berval dn = BER_BVNULL,
441 pdn = odn,
442 ndn = ondn;
443 char *filter = NULL;
444 int temporary = 0;
445 int free_dn = 0;
446
447 /* We're setting the URI of the first referral;
448 * what if there are more?
449
450 Document: RFC 4511
451
452 4.1.10. Referral
453 ...
454 If the client wishes to progress the operation, it MUST follow the
455 referral by contacting one of the supported services. If multiple
456 URIs are present, the client assumes that any supported URI may be
457 used to progress the operation.
458
459 * so we actually need to follow exactly one,
460 * and we can assume any is fine.
461 */
462
463 /* parse reference and use
464 * proto://[host][:port]/ only */
465 rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
466 if ( rc != LDAP_URL_SUCCESS ) {
467 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: unable to parse ref=\"%s\"\n",
468 op->o_log_prefix, ref->bv_val );
469
470 /* try next */
471 rc = LDAP_OTHER;
472 continue;
473 }
474
475 if ( op->o_tag == LDAP_REQ_SEARCH ) {
476 if ( srv->lud_scope != LDAP_SCOPE_DEFAULT ) {
477 /* RFC 4511: if scope is present, use it */
478 tmp_oq_search.rs_scope = srv->lud_scope;
479
480 } else {
481 /* RFC 4511: if scope is absent, use original */
482 tmp_oq_search.rs_scope = op->ors_scope;
483 }
484 }
485
486 rc = LDAP_SUCCESS;
487 srv->lud_scope = LDAP_SCOPE_DEFAULT;
488 dn.bv_val = srv->lud_dn;
489 filter = srv->lud_filter;
490
491 /* normalize DN */
492 if ( srv->lud_dn == NULL || srv->lud_dn[0] == '\0' ) {
493 if ( srv->lud_dn == NULL ) {
494 srv->lud_dn = "";
495 }
496
497 } else {
498 ber_str2bv( srv->lud_dn, 0, 0, &dn );
499 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
500 if ( rc == LDAP_SUCCESS ) {
501 /* remove DN essentially because later on
502 * ldap_initialize() will parse the URL
503 * as a comma-separated URL list */
504 srv->lud_dn = "";
505 free_dn = 1;
506 }
507 }
508
509 /* prepare filter */
510 if ( rc == LDAP_SUCCESS && op->o_tag == LDAP_REQ_SEARCH ) {
511 /* filter */
512 if ( srv->lud_filter != NULL
513 && srv->lud_filter[0] != '\0'
514 && strcasecmp( srv->lud_filter, "(objectClass=*)" ) != 0 )
515 {
516 /* RFC 4511: if filter is present, use it;
517 * otherwise, use original */
518 tmp_oq_search.rs_filter = str2filter_x( op, srv->lud_filter );
519 if ( tmp_oq_search.rs_filter != NULL ) {
520 filter2bv_x( op, tmp_oq_search.rs_filter, &tmp_oq_search.rs_filterstr );
521
522 } else {
523 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\": unable to parse filter=\"%s\"\n",
524 op->o_log_prefix, ref->bv_val, srv->lud_filter );
525 rc = LDAP_OTHER;
526 }
527 }
528 }
529 srv->lud_filter = NULL;
530
531 if ( rc == LDAP_SUCCESS ) {
532 li.li_uri = ldap_url_desc2str( srv );
533 }
534
535 srv->lud_dn = dn.bv_val;
536 srv->lud_filter = filter;
537 ldap_free_urldesc( srv );
538
539 if ( rc != LDAP_SUCCESS ) {
540 /* try next */
541 rc = LDAP_OTHER;
542 continue;
543 }
544
545 if ( li.li_uri == NULL ) {
546 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" unable to reconstruct URI\n",
547 op->o_log_prefix, ref->bv_val );
548
549 /* try next */
550 rc = LDAP_OTHER;
551 goto further_cleanup;
552 }
553
554 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" -> \"%s\"\n",
555 op->o_log_prefix, ref->bv_val, li.li_uri );
556
557 op->o_req_dn = pdn;
558 op->o_req_ndn = ndn;
559
560 if ( op->o_tag == LDAP_REQ_SEARCH ) {
561 op->ors_scope = tmp_oq_search.rs_scope;
562 if ( tmp_oq_search.rs_filter != NULL ) {
563 op->ors_filter = tmp_oq_search.rs_filter;
564 op->ors_filterstr = tmp_oq_search.rs_filterstr;
565 }
566 }
567
568 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
569
570 /* Searches for a ldapinfo in the avl tree */
571 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
572 lip = (ldapinfo_t *)ldap_tavl_find( lc->lc_lai.lai_tree,
573 (caddr_t)&li, ldap_chain_uri_cmp );
574 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
575
576 if ( lip != NULL ) {
577 op->o_bd->be_private = (void *)lip;
578
579 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\": URI=\"%s\" found in cache\n",
580 op->o_log_prefix, ref->bv_val, li.li_uri );
581
582 } else {
583 rc = ldap_chain_db_init_one( op->o_bd );
584 if ( rc != 0 ) {
585 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" unable to init back-ldap for URI=\"%s\"\n",
586 op->o_log_prefix, ref->bv_val, li.li_uri );
587 goto cleanup;
588 }
589 lip = (ldapinfo_t *)op->o_bd->be_private;
590 lip->li_uri = li.li_uri;
591 lip->li_bvuri = bvuri;
592 rc = ldap_chain_db_open_one( op->o_bd );
593 if ( rc != 0 ) {
594 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" unable to open back-ldap for URI=\"%s\"\n",
595 op->o_log_prefix, ref->bv_val, li.li_uri );
596 lip->li_uri = NULL;
597 lip->li_bvuri = NULL;
598 (void)ldap_chain_db_destroy_one( op->o_bd, NULL);
599 goto cleanup;
600 }
601
602 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
603 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
604 if ( ldap_tavl_insert( &lc->lc_lai.lai_tree,
605 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
606 {
607 /* someone just inserted another;
608 * don't bother, use this and then
609 * just free it */
610 temporary = 1;
611 }
612 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
613
614 } else {
615 temporary = 1;
616 }
617
618 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" %s\n",
619 op->o_log_prefix, ref->bv_val, temporary ? "temporary" : "caching" );
620 }
621
622 lb->lb_op_type = op_type;
623 lb->lb_depth = depth + 1;
624
625 rc = (&lback->bi_op_bind)[ op_type ]( op, &rs2 );
626
627 /* note the first error */
628 if ( first_rc == -1 ) {
629 first_rc = rc;
630 }
631
632 cleanup:;
633 ldap_memfree( li.li_uri );
634 li.li_uri = NULL;
635
636 if ( temporary ) {
637 lip->li_uri = NULL;
638 lip->li_bvuri = NULL;
639 (void)ldap_chain_db_close_one( op->o_bd );
640 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
641 }
642
643 further_cleanup:;
644 if ( op->o_req_dn.bv_val == pdn.bv_val ) {
645 op->o_req_dn = odn;
646 op->o_req_ndn = ondn;
647 }
648
649 if ( free_dn ) {
650 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
651 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
652 }
653
654 if ( op->o_tag == LDAP_REQ_SEARCH ) {
655 if ( tmp_oq_search.rs_filter != NULL ) {
656 filter_free_x( op, tmp_oq_search.rs_filter, 1 );
657 }
658
659 if ( !BER_BVISNULL( &tmp_oq_search.rs_filterstr ) ) {
660 slap_sl_free( tmp_oq_search.rs_filterstr.bv_val, op->o_tmpmemctx );
661 }
662
663 op->oq_search = save_oq_search;
664 }
665
666 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
667 *rs = rs2;
668 break;
669 }
670
671 rc = rs2.sr_err;
672 }
673
674 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
675 (void)chaining_control_remove( op, &ctrls );
676 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
677
678 if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
679 rc = first_rc;
680 }
681
682 return rc;
683 }
684
685 static int
ldap_chain_search(Operation * op,SlapReply * rs,BerVarray ref,int depth)686 ldap_chain_search(
687 Operation *op,
688 SlapReply *rs,
689 BerVarray ref,
690 int depth )
691
692 {
693 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
694 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
695 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
696 ldapinfo_t li = { 0 }, *lip = NULL;
697 struct berval bvuri[ 2 ] = { { 0 } };
698
699 struct berval odn = op->o_req_dn,
700 ondn = op->o_req_ndn;
701 Entry *save_entry = rs->sr_entry;
702 slap_mask_t save_flags = rs->sr_flags;
703
704 int rc = LDAP_OTHER,
705 first_rc = -1;
706
707 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
708 LDAPControl **ctrls = NULL;
709
710 (void)chaining_control_add( lc, op, &ctrls );
711 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
712
713 assert( rs->sr_type == REP_SEARCHREF );
714
715 rs->sr_type = REP_SEARCH;
716
717 /* if we parse the URI then by no means
718 * we can cache stuff or reuse connections,
719 * because in back-ldap there's no caching
720 * based on the URI value, which is supposed
721 * to be set once for all (correct?) */
722 li.li_bvuri = bvuri;
723 for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
724 SlapReply rs2 = { REP_RESULT };
725 LDAPURLDesc *srv;
726 req_search_s save_oq_search = op->oq_search,
727 tmp_oq_search = { 0 };
728 struct berval dn,
729 pdn = op->o_req_dn,
730 ndn = op->o_req_ndn;
731 char *filter = NULL;
732 int temporary = 0;
733 int free_dn = 0;
734
735 /* parse reference and use
736 * proto://[host][:port]/ only */
737 rc = ldap_url_parse_ext( ref[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
738 if ( rc != LDAP_URL_SUCCESS ) {
739 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: unable to parse ref=\"%s\"\n",
740 op->o_log_prefix, ref->bv_val );
741
742 /* try next */
743 rs->sr_err = LDAP_OTHER;
744 continue;
745 }
746
747 if ( srv->lud_scope != LDAP_SCOPE_DEFAULT ) {
748 /* RFC 4511: if scope is present, use it */
749 tmp_oq_search.rs_scope = srv->lud_scope;
750
751 } else {
752 /* RFC 4511: if scope is absent, use original */
753 /* Section 4.5.3: if scope is onelevel, use base */
754 if ( op->ors_scope == LDAP_SCOPE_ONELEVEL )
755 tmp_oq_search.rs_scope = LDAP_SCOPE_BASE;
756 else
757 tmp_oq_search.rs_scope = op->ors_scope;
758 }
759
760 rc = LDAP_SUCCESS;
761 srv->lud_scope = LDAP_SCOPE_DEFAULT;
762 dn.bv_val = srv->lud_dn;
763 filter = srv->lud_filter;
764
765 /* normalize DN */
766 if ( srv->lud_dn == NULL || srv->lud_dn[0] == '\0' ) {
767 if ( srv->lud_dn == NULL ) {
768 srv->lud_dn = "";
769 }
770
771 if ( save_entry != NULL ) {
772 /* use the "right" DN, if available */
773 pdn = save_entry->e_name;
774 ndn = save_entry->e_nname;
775 } /* else leave the original req DN in place, if any RFC 4511 */
776
777 } else {
778 /* RFC 4511: if DN is present, use it */
779 ber_str2bv( srv->lud_dn, 0, 0, &dn );
780 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
781 if ( rc == LDAP_SUCCESS ) {
782 /* remove DN essentially because later on
783 * ldap_initialize() will parse the URL
784 * as a comma-separated URL list */
785 srv->lud_dn = "";
786 free_dn = 1;
787 }
788 }
789
790 /* prepare filter */
791 if ( rc == LDAP_SUCCESS ) {
792 /* filter */
793 if ( srv->lud_filter != NULL
794 && srv->lud_filter[0] != '\0'
795 && strcasecmp( srv->lud_filter, "(objectClass=*)" ) != 0 )
796 {
797 /* RFC 4511: if filter is present, use it;
798 * otherwise, use original */
799 tmp_oq_search.rs_filter = str2filter_x( op, srv->lud_filter );
800 if ( tmp_oq_search.rs_filter != NULL ) {
801 filter2bv_x( op, tmp_oq_search.rs_filter, &tmp_oq_search.rs_filterstr );
802
803 } else {
804 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\": unable to parse filter=\"%s\"\n",
805 op->o_log_prefix, ref->bv_val, srv->lud_filter );
806 rc = LDAP_OTHER;
807 }
808 }
809 }
810 srv->lud_filter = NULL;
811
812 if ( rc == LDAP_SUCCESS ) {
813 li.li_uri = ldap_url_desc2str( srv );
814 }
815
816 srv->lud_dn = dn.bv_val;
817 srv->lud_filter = filter;
818 ldap_free_urldesc( srv );
819
820 if ( rc != LDAP_SUCCESS || li.li_uri == NULL ) {
821 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" unable to reconstruct URI\n",
822 op->o_log_prefix, ref->bv_val );
823
824 /* try next */
825 rc = LDAP_OTHER;
826 goto further_cleanup;
827 }
828
829 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" -> \"%s\"\n",
830 op->o_log_prefix, ref->bv_val, li.li_uri );
831
832 op->o_req_dn = pdn;
833 op->o_req_ndn = ndn;
834 op->ors_scope = tmp_oq_search.rs_scope;
835 if ( tmp_oq_search.rs_filter != NULL ) {
836 op->ors_filter = tmp_oq_search.rs_filter;
837 op->ors_filterstr = tmp_oq_search.rs_filterstr;
838 }
839
840 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
841
842 /* Searches for a ldapinfo in the avl tree */
843 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
844 lip = (ldapinfo_t *)ldap_tavl_find( lc->lc_lai.lai_tree,
845 (caddr_t)&li, ldap_chain_uri_cmp );
846 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
847
848 if ( lip != NULL ) {
849 op->o_bd->be_private = (void *)lip;
850
851 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\": URI=\"%s\" found in cache\n",
852 op->o_log_prefix, ref->bv_val, li.li_uri );
853
854 } else {
855 /* if none is found, create a temporary... */
856 rc = ldap_chain_db_init_one( op->o_bd );
857 if ( rc != 0 ) {
858 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" unable to init back-ldap for URI=\"%s\"\n",
859 op->o_log_prefix, ref->bv_val, li.li_uri );
860 goto cleanup;
861 }
862 lip = (ldapinfo_t *)op->o_bd->be_private;
863 lip->li_uri = li.li_uri;
864 lip->li_bvuri = bvuri;
865 rc = ldap_chain_db_open_one( op->o_bd );
866 if ( rc != 0 ) {
867 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" unable to open back-ldap for URI=\"%s\"\n",
868 op->o_log_prefix, ref->bv_val, li.li_uri );
869 lip->li_uri = NULL;
870 lip->li_bvuri = NULL;
871 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
872 goto cleanup;
873 }
874
875 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
876 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
877 if ( ldap_tavl_insert( &lc->lc_lai.lai_tree,
878 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
879 {
880 /* someone just inserted another;
881 * don't bother, use this and then
882 * just free it */
883 temporary = 1;
884 }
885 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
886
887 } else {
888 temporary = 1;
889 }
890
891 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" %s\n",
892 op->o_log_prefix, ref->bv_val, temporary ? "temporary" : "caching" );
893 }
894
895 lb->lb_op_type = op_search;
896 lb->lb_depth = depth + 1;
897
898 /* FIXME: should we also copy filter and scope?
899 * according to RFC3296, no */
900 rc = lback->bi_op_search( op, &rs2 );
901 if ( first_rc == -1 ) {
902 first_rc = rc;
903 }
904
905 cleanup:;
906 ldap_memfree( li.li_uri );
907 li.li_uri = NULL;
908
909 if ( temporary ) {
910 lip->li_uri = NULL;
911 lip->li_bvuri = NULL;
912 (void)ldap_chain_db_close_one( op->o_bd );
913 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
914 }
915
916 further_cleanup:;
917 if ( op->o_req_dn.bv_val == pdn.bv_val ) {
918 op->o_req_dn = odn;
919 op->o_req_ndn = ondn;
920 }
921
922 if ( free_dn ) {
923 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
924 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
925 }
926
927 if ( tmp_oq_search.rs_filter != NULL ) {
928 filter_free_x( op, tmp_oq_search.rs_filter, 1 );
929 }
930
931 if ( !BER_BVISNULL( &tmp_oq_search.rs_filterstr ) ) {
932 slap_sl_free( tmp_oq_search.rs_filterstr.bv_val, op->o_tmpmemctx );
933 }
934
935 op->oq_search = save_oq_search;
936
937 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
938 *rs = rs2;
939 break;
940 }
941
942 rc = rs2.sr_err;
943 }
944
945 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
946 (void)chaining_control_remove( op, &ctrls );
947 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
948
949 rs->sr_type = REP_SEARCHREF;
950 rs->sr_entry = save_entry;
951 rs->sr_flags = save_flags;
952
953 if ( rc != LDAP_SUCCESS ) {
954 /* couldn't chase any of the referrals */
955 if ( first_rc != -1 ) {
956 rc = first_rc;
957
958 } else {
959 rc = SLAP_CB_CONTINUE;
960 }
961 }
962
963 return rc;
964 }
965
966 static int
ldap_chain_response(Operation * op,SlapReply * rs)967 ldap_chain_response( Operation *op, SlapReply *rs )
968 {
969 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
970 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
971 BackendDB db, *bd = op->o_bd;
972 ldap_chain_cb_t lb = { 0 };
973 slap_callback *sc = op->o_callback,
974 sc2 = { 0 };
975 int rc = 0;
976 const char *text = NULL;
977 const char *matched;
978 BerVarray ref;
979 slap_mask_t flags = 0;
980 struct berval ndn = op->o_ndn;
981
982 int sr_err = rs->sr_err;
983 slap_reply_t sr_type = rs->sr_type;
984 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
985 slap_mask_t chain_mask = 0;
986 ber_len_t chain_shift = 0;
987 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
988
989 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
990 return SLAP_CB_CONTINUE;
991 }
992 if ( !rs->sr_ref ) {
993 return SLAP_CB_CONTINUE;
994 }
995
996 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
997 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
998 switch ( get_resolveBehavior( op ) ) {
999 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
1000 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
1001 return SLAP_CB_CONTINUE;
1002
1003 default:
1004 chain_mask = SLAP_CH_RESOLVE_MASK;
1005 chain_shift = SLAP_CH_RESOLVE_SHIFT;
1006 break;
1007 }
1008
1009 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
1010 switch ( get_continuationBehavior( op ) ) {
1011 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
1012 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
1013 return SLAP_CB_CONTINUE;
1014
1015 default:
1016 chain_mask = SLAP_CH_CONTINUATION_MASK;
1017 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
1018 break;
1019 }
1020 }
1021 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1022
1023 /*
1024 * TODO: add checks on who/when chain operations; e.g.:
1025 * a) what identities are authorized
1026 * b) what request DN (e.g. only chain requests rooted at <DN>)
1027 * c) what referral URIs
1028 * d) what protocol scheme (e.g. only ldaps://)
1029 * e) what ssf
1030 */
1031
1032 db = *op->o_bd;
1033 SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
1034 op->o_bd = &db;
1035
1036 text = rs->sr_text;
1037 rs->sr_text = NULL;
1038 matched = rs->sr_matched;
1039 rs->sr_matched = NULL;
1040 ref = rs->sr_ref;
1041 rs->sr_ref = NULL;
1042
1043 flags = rs->sr_flags & (REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED);
1044 rs->sr_flags &= ~flags;
1045
1046 /* we need this to know if back-ldap returned any result */
1047 lb.lb_lc = lc;
1048 sc2.sc_next = sc->sc_next;
1049 sc2.sc_private = &lb;
1050 sc2.sc_response = ldap_chain_cb_response;
1051 op->o_callback = &sc2;
1052
1053 /* Chaining can be performed by a privileged user on behalf
1054 * of normal users, using the ProxyAuthz control, by exploiting
1055 * the identity assertion feature of back-ldap; see idassert-*
1056 * directives in slapd-ldap(5).
1057 *
1058 * FIXME: the idassert-authcDN is one, will it be fine regardless
1059 * of the URI we obtain from the referral?
1060 */
1061
1062 switch ( op->o_tag ) {
1063 case LDAP_REQ_BIND: {
1064 struct berval rndn = op->o_req_ndn;
1065 Connection *conn = op->o_conn;
1066
1067 /* FIXME: can we really get a referral for binds? */
1068 op->o_req_ndn = slap_empty_bv;
1069 op->o_conn = NULL;
1070 rc = ldap_chain_op( op, rs, op_bind, ref, 0 );
1071 op->o_req_ndn = rndn;
1072 op->o_conn = conn;
1073 }
1074 break;
1075
1076 case LDAP_REQ_ADD:
1077 rc = ldap_chain_op( op, rs, op_add, ref, 0 );
1078 break;
1079
1080 case LDAP_REQ_DELETE:
1081 rc = ldap_chain_op( op, rs, op_delete, ref, 0 );
1082 break;
1083
1084 case LDAP_REQ_MODRDN:
1085 rc = ldap_chain_op( op, rs, op_modrdn, ref, 0 );
1086 break;
1087
1088 case LDAP_REQ_MODIFY:
1089 rc = ldap_chain_op( op, rs, op_modify, ref, 0 );
1090 break;
1091
1092 case LDAP_REQ_COMPARE:
1093 rc = ldap_chain_op( op, rs, op_compare, ref, 0 );
1094 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
1095 rc = LDAP_SUCCESS;
1096 }
1097 break;
1098
1099 case LDAP_REQ_SEARCH:
1100 if ( rs->sr_type == REP_SEARCHREF ) {
1101 sc2.sc_response = ldap_chain_cb_search_response;
1102 rc = ldap_chain_search( op, rs, ref, 0 );
1103
1104 } else {
1105 /* we might get here before any database actually
1106 * performed a search; in those cases, we need
1107 * to check limits, to make sure safe defaults
1108 * are in place */
1109 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
1110 rc = ldap_chain_op( op, rs, op_search, ref, 0 );
1111 } else {
1112 rc = SLAP_CB_CONTINUE;
1113 }
1114 }
1115 break;
1116
1117 case LDAP_REQ_EXTENDED:
1118 rc = ldap_chain_op( op, rs, op_extended, ref, 0 );
1119 /* FIXME: ldap_back_extended() by design
1120 * doesn't send result; frontend is expected
1121 * to send it... */
1122 /* FIXME: what about chaining? */
1123 if ( rc != SLAPD_ABANDON ) {
1124 rs->sr_err = rc;
1125 send_ldap_extended( op, rs );
1126 rc = LDAP_SUCCESS;
1127 }
1128 lb.lb_status = LDAP_CH_RES;
1129 break;
1130
1131 default:
1132 rc = SLAP_CB_CONTINUE;
1133 break;
1134 }
1135
1136 switch ( rc ) {
1137 case SLAPD_ABANDON:
1138 goto dont_chain;
1139
1140 case LDAP_SUCCESS:
1141 case LDAP_REFERRAL:
1142 sr_err = rs->sr_err;
1143 /* slapd-ldap sent response */
1144 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
1145 /* FIXME: should we send response? */
1146 Debug( LDAP_DEBUG_ANY,
1147 "%s: ldap_chain_response: "
1148 "overlay should have sent result.\n",
1149 op->o_log_prefix );
1150 }
1151 break;
1152
1153 default:
1154 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1155 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
1156 goto cannot_chain;
1157 }
1158
1159 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
1160 case LDAP_CHAINING_REQUIRED:
1161 cannot_chain:;
1162 op->o_callback = NULL;
1163 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
1164 "operation cannot be completed without chaining" );
1165 goto dont_chain;
1166
1167 default:
1168 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1169 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
1170 sr_err = rs->sr_err = rc;
1171 rs->sr_text = lb.lb_text;
1172 rs->sr_type = sr_type;
1173
1174 } else {
1175 rc = SLAP_CB_CONTINUE;
1176 rs->sr_err = sr_err;
1177 rs->sr_type = sr_type;
1178 rs->sr_text = text;
1179 rs->sr_matched = matched;
1180 rs->sr_ref = ref;
1181 rs->sr_flags |= flags;
1182 }
1183 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1184 break;
1185 }
1186 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1187 }
1188
1189 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
1190 /* give the remaining callbacks a chance */
1191 op->o_callback = sc->sc_next;
1192 rc = rs->sr_err = slap_map_api2result( rs );
1193 send_ldap_result( op, rs );
1194 }
1195
1196 dont_chain:;
1197 rs->sr_err = sr_err;
1198 rs->sr_type = sr_type;
1199 rs->sr_text = text;
1200 rs->sr_matched = matched;
1201 rs->sr_ref = ref;
1202 rs->sr_flags |= flags;
1203
1204 op->o_bd = bd;
1205 op->o_callback = sc;
1206 op->o_ndn = ndn;
1207
1208 if ( rs->sr_text == lb.lb_text ) {
1209 rs->sr_text = NULL;
1210 }
1211 if ( lb.lb_text ) {
1212 ber_memfree_x( lb.lb_text, op->o_tmpmemctx );
1213 }
1214
1215 return rc;
1216 }
1217
1218 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1219 static int
1220 ldap_chain_parse_ctrl(
1221 Operation *op,
1222 SlapReply *rs,
1223 LDAPControl *ctrl );
1224
1225 static int
str2chain(const char * s)1226 str2chain( const char *s )
1227 {
1228 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
1229 return LDAP_CHAINING_PREFERRED;
1230
1231 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
1232 return LDAP_CHAINING_REQUIRED;
1233
1234 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
1235 return LDAP_REFERRALS_PREFERRED;
1236
1237 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
1238 return LDAP_REFERRALS_REQUIRED;
1239 }
1240
1241 return -1;
1242 }
1243 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1244
1245 /*
1246 * configuration...
1247 */
1248
1249 enum {
1250 CH_CHAINING = 1,
1251 CH_CACHE_URI,
1252 CH_MAX_DEPTH,
1253 CH_RETURN_ERR,
1254
1255 CH_LAST
1256 };
1257
1258 static ConfigDriver chain_cf_gen;
1259 static ConfigCfAdd chain_cfadd;
1260 static ConfigLDAPadd chain_ldadd;
1261 #ifdef SLAP_CONFIG_DELETE
1262 static ConfigLDAPdel chain_lddel;
1263 #endif
1264
1265 static ConfigTable chaincfg[] = {
1266 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1267 { "chain-chaining", "args",
1268 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
1269 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
1270 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
1271 "EQUALITY caseIgnoreMatch "
1272 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
1273 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1274 { "chain-cache-uri", "TRUE/FALSE",
1275 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
1276 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
1277 "DESC 'Enables caching of URIs not present in configuration' "
1278 "EQUALITY booleanMatch "
1279 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1280 { "chain-max-depth", "args",
1281 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
1282 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
1283 "DESC 'max referral depth' "
1284 "SYNTAX OMsInteger "
1285 "EQUALITY integerMatch "
1286 "SINGLE-VALUE )", NULL, NULL },
1287 { "chain-return-error", "TRUE/FALSE",
1288 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1289 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1290 "DESC 'Errors are returned instead of the original referral' "
1291 "EQUALITY booleanMatch "
1292 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1293 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1294 };
1295
1296 static ConfigOCs chainocs[] = {
1297 { "( OLcfgOvOc:3.1 "
1298 "NAME 'olcChainConfig' "
1299 "DESC 'Chain configuration' "
1300 "SUP olcOverlayConfig "
1301 "MAY ( "
1302 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1303 "olcChainingBehavior $ "
1304 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1305 "olcChainCacheURI $ "
1306 "olcChainMaxReferralDepth $ "
1307 "olcChainReturnError "
1308 ") )",
1309 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1310 { "( OLcfgOvOc:3.2 "
1311 "NAME 'olcChainDatabase' "
1312 "DESC 'Chain remote server configuration' "
1313 "AUXILIARY )",
1314 Cft_Misc, NULL, chain_ldadd
1315 #ifdef SLAP_CONFIG_DELETE
1316 , NULL, chain_lddel
1317 #endif
1318 },
1319 { NULL, 0, NULL }
1320 };
1321
1322 static int
chain_ldadd(CfEntryInfo * p,Entry * e,ConfigArgs * ca)1323 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1324 {
1325 slap_overinst *on;
1326 ldap_chain_t *lc;
1327
1328 ldapinfo_t *li;
1329
1330 AttributeDescription *ad = NULL;
1331 Attribute *at;
1332 const char *text;
1333
1334 int rc;
1335
1336 if ( p->ce_type != Cft_Overlay
1337 || !p->ce_bi
1338 || p->ce_bi->bi_cf_ocs != chainocs )
1339 {
1340 return LDAP_CONSTRAINT_VIOLATION;
1341 }
1342
1343 on = (slap_overinst *)p->ce_bi;
1344 lc = (ldap_chain_t *)on->on_bi.bi_private;
1345
1346 assert( ca->be == NULL );
1347 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1348
1349 ca->be->bd_info = (BackendInfo *)on;
1350
1351 rc = slap_str2ad( "olcDbURI", &ad, &text );
1352 assert( rc == LDAP_SUCCESS );
1353
1354 at = attr_find( e->e_attrs, ad );
1355 #if 0
1356 if ( lc->lc_common_li == NULL && at != NULL ) {
1357 /* FIXME: we should generate an empty default entry
1358 * if none is supplied */
1359 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1360 "first underlying database \"%s\" "
1361 "cannot contain attribute \"%s\".\n",
1362 e->e_name.bv_val, ad->ad_cname.bv_val );
1363 rc = LDAP_CONSTRAINT_VIOLATION;
1364 goto done;
1365
1366 } else
1367 #endif
1368 if ( lc->lc_common_li != NULL && lc->lc_common_li != lc->lc_cfg_li && at == NULL ) {
1369 /* FIXME: we should generate an empty default entry
1370 * if none is supplied */
1371 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1372 "subsequent underlying database \"%s\" "
1373 "must contain attribute \"%s\".\n",
1374 e->e_name.bv_val, ad->ad_cname.bv_val );
1375 rc = LDAP_CONSTRAINT_VIOLATION;
1376 goto done;
1377 }
1378
1379 if ( lc->lc_common_li == NULL ) {
1380 rc = ldap_chain_db_init_common( ca->be );
1381 if ( rc != 0 )
1382 goto fail;
1383 li = ca->be->be_private;
1384 lc->lc_common_li = lc->lc_cfg_li = li;
1385
1386 }
1387 rc = ldap_chain_db_init_one( ca->be );
1388 lc->lc_cfg_li = NULL;
1389
1390 if ( rc != 0 ) {
1391 fail:
1392 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1393 "unable to init %sunderlying database \"%s\".\n",
1394 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val );
1395 return LDAP_CONSTRAINT_VIOLATION;
1396 }
1397
1398 li = ca->be->be_private;
1399
1400 if ( at ) {
1401 char **urls;
1402
1403 urls = ldap_str2charray( at->a_vals[ 0 ].bv_val, ", \t" );
1404 if ( !urls || !urls[0] || urls[1] ) {
1405 ldap_charray_free( urls );
1406 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1407 "olcDbURI must contain exactly one url, got %s\n",
1408 at->a_vals[ 0 ].bv_val );
1409 rc = LDAP_CONSTRAINT_VIOLATION;
1410 goto done;
1411 }
1412 ldap_charray_free( urls );
1413
1414 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
1415 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
1416 if ( ldap_tavl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1417 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1418 {
1419 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1420 "database \"%s\" insert failed.\n",
1421 e->e_name.bv_val );
1422 rc = LDAP_CONSTRAINT_VIOLATION;
1423 goto done;
1424 }
1425 }
1426
1427 ca->ca_private = on;
1428
1429 done:;
1430 if ( rc != LDAP_SUCCESS ) {
1431 (void)ldap_chain_db_destroy_one( ca->be, NULL );
1432 ch_free( ca->be );
1433 ca->be = NULL;
1434 }
1435
1436 return rc;
1437 }
1438
1439 static void
ldap_chain_cfadd_apply(ldapinfo_t * li,Operation * op,SlapReply * rs,Entry * p,ConfigArgs * ca,int count)1440 ldap_chain_cfadd_apply(
1441 ldapinfo_t *li,
1442 Operation *op,
1443 SlapReply *rs,
1444 Entry *p,
1445 ConfigArgs *ca,
1446 int count )
1447 {
1448 struct berval bv;
1449
1450 /* FIXME: should not hardcode "olcDatabase" here */
1451 bv.bv_len = snprintf( ca->cr_msg, sizeof( ca->cr_msg ),
1452 "olcDatabase={%d}%s", count, lback->bi_type );
1453 bv.bv_val = ca->cr_msg;
1454
1455 ca->be->be_private = (void *)li;
1456 config_build_entry( op, rs, p->e_private, ca,
1457 &bv, lback->bi_cf_ocs, &chainocs[1] );
1458
1459 return;
1460 }
1461
1462 static int
chain_cfadd(Operation * op,SlapReply * rs,Entry * p,ConfigArgs * ca)1463 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1464 {
1465 CfEntryInfo *pe = p->e_private;
1466 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1467 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1468 void *priv = (void *)ca->be->be_private;
1469 TAvlnode *edge;
1470 int count = 0;
1471
1472 if ( lback->bi_cf_ocs ) {
1473
1474 ldap_chain_cfadd_apply( lc->lc_common_li, op, rs, p, ca, count++ );
1475
1476 edge = ldap_tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
1477 while ( edge ) {
1478 TAvlnode *next = ldap_tavl_next( edge, TAVL_DIR_RIGHT );
1479 ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
1480 ldap_chain_cfadd_apply( li, op, rs, p, ca, count++ );
1481 edge = next;
1482 }
1483
1484 ca->be->be_private = priv;
1485 }
1486
1487 lc->lc_cfg_li = NULL;
1488
1489 return 0;
1490 }
1491
1492 #ifdef SLAP_CONFIG_DELETE
1493 static int
chain_lddel(CfEntryInfo * ce,Operation * op)1494 chain_lddel( CfEntryInfo *ce, Operation *op )
1495 {
1496 CfEntryInfo *pe = ce->ce_parent;
1497 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1498 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1499 ldapinfo_t *li = (ldapinfo_t *) ce->ce_be->be_private;
1500
1501 if ( li != lc->lc_common_li ) {
1502 if (! ldap_tavl_delete( &lc->lc_lai.lai_tree, li, ldap_chain_uri_cmp ) ) {
1503 Debug( LDAP_DEBUG_ANY, "slapd-chain: ldap_avl_delete failed. "
1504 "\"%s\" not found.\n", li->li_uri );
1505 return -1;
1506 }
1507 } else if ( lc->lc_lai.lai_tree ) {
1508 Debug( LDAP_DEBUG_ANY, "slapd-chain: cannot delete first underlying "
1509 "LDAP database when other databases are still present.\n" );
1510 return -1;
1511 } else {
1512 lc->lc_common_li = NULL;
1513 }
1514
1515 ce->ce_be->bd_info = lback;
1516
1517 if ( ce->ce_be->bd_info->bi_db_close ) {
1518 ce->ce_be->bd_info->bi_db_close( ce->ce_be, NULL );
1519 }
1520 if ( ce->ce_be->bd_info->bi_db_destroy ) {
1521 ce->ce_be->bd_info->bi_db_destroy( ce->ce_be, NULL );
1522 }
1523
1524 ch_free(ce->ce_be);
1525 ce->ce_be = NULL;
1526
1527 return LDAP_SUCCESS;
1528 }
1529 #endif /* SLAP_CONFIG_DELETE */
1530
1531 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1532 static slap_verbmasks chaining_mode[] = {
1533 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1534 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1535 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1536 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1537 { BER_BVNULL, 0 }
1538 };
1539 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1540
1541 static int
chain_cf_gen(ConfigArgs * c)1542 chain_cf_gen( ConfigArgs *c )
1543 {
1544 slap_overinst *on = (slap_overinst *)c->bi;
1545 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1546
1547 int rc = 0;
1548
1549 if ( c->op == SLAP_CONFIG_EMIT ) {
1550 switch( c->type ) {
1551 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1552 case CH_CHAINING: {
1553 struct berval resolve = BER_BVNULL,
1554 continuation = BER_BVNULL;
1555
1556 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1557 return 1;
1558 }
1559
1560 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1561 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1562
1563 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1564 + STRLENOF( " " )
1565 + STRLENOF( "continuation=" ) + continuation.bv_len;
1566 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1567 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1568 "resolve=%s continuation=%s",
1569 resolve.bv_val, continuation.bv_val );
1570
1571 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1572 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1573 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1574 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1575 " critical", STRLENOF( " critical" ) + 1 );
1576 c->value_bv.bv_len += STRLENOF( " critical" );
1577 }
1578
1579 break;
1580 }
1581 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1582
1583 case CH_CACHE_URI:
1584 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1585 break;
1586
1587 case CH_MAX_DEPTH:
1588 c->value_int = lc->lc_max_depth;
1589 break;
1590
1591 case CH_RETURN_ERR:
1592 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1593 break;
1594
1595 default:
1596 assert( 0 );
1597 rc = 1;
1598 }
1599 return rc;
1600
1601 } else if ( c->op == LDAP_MOD_DELETE ) {
1602 switch( c->type ) {
1603 case CH_CHAINING:
1604 return 1;
1605
1606 case CH_CACHE_URI:
1607 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1608 break;
1609
1610 case CH_MAX_DEPTH:
1611 c->value_int = 0;
1612 break;
1613
1614 case CH_RETURN_ERR:
1615 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1616 break;
1617
1618 default:
1619 return 1;
1620 }
1621 return rc;
1622 }
1623
1624 switch( c->type ) {
1625 case CH_CHAINING: {
1626 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1627 char **argv = c->argv;
1628 int argc = c->argc;
1629 BerElementBuffer berbuf;
1630 BerElement *ber = (BerElement *)&berbuf;
1631 int resolve = -1,
1632 continuation = -1,
1633 iscritical = 0;
1634 Operation op = { 0 };
1635 SlapReply rs = { 0 };
1636
1637 lc->lc_chaining_ctrlflag = 0;
1638
1639 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1640 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1641 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1642 if ( resolve == -1 ) {
1643 Debug( LDAP_DEBUG_ANY, "%s: "
1644 "illegal <resolve> value %s "
1645 "in \"chain-chaining>\".\n",
1646 c->log, argv[ 0 ] );
1647 return 1;
1648 }
1649
1650 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1651 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1652 if ( continuation == -1 ) {
1653 Debug( LDAP_DEBUG_ANY, "%s: "
1654 "illegal <continuation> value %s "
1655 "in \"chain-chaining\".\n",
1656 c->log, argv[ 0 ] );
1657 return 1;
1658 }
1659
1660 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1661 iscritical = 1;
1662
1663 } else {
1664 Debug( LDAP_DEBUG_ANY, "%s: "
1665 "unknown option in \"chain-chaining\".\n",
1666 c->log );
1667 return 1;
1668 }
1669 }
1670
1671 if ( resolve != -1 || continuation != -1 ) {
1672 int err;
1673
1674 if ( resolve == -1 ) {
1675 /* default */
1676 resolve = SLAP_CHAINING_DEFAULT;
1677 }
1678
1679 ber_init2( ber, NULL, LBER_USE_DER );
1680
1681 err = ber_printf( ber, "{e" /* } */, resolve );
1682 if ( err == -1 ) {
1683 ber_free( ber, 1 );
1684 Debug( LDAP_DEBUG_ANY, "%s: "
1685 "chaining behavior control encoding error!\n",
1686 c->log );
1687 return 1;
1688 }
1689
1690 if ( continuation > -1 ) {
1691 err = ber_printf( ber, "e", continuation );
1692 if ( err == -1 ) {
1693 ber_free( ber, 1 );
1694 Debug( LDAP_DEBUG_ANY, "%s: "
1695 "chaining behavior control encoding error!\n",
1696 c->log );
1697 return 1;
1698 }
1699 }
1700
1701 err = ber_printf( ber, /* { */ "N}" );
1702 if ( err == -1 ) {
1703 ber_free( ber, 1 );
1704 Debug( LDAP_DEBUG_ANY, "%s: "
1705 "chaining behavior control encoding error!\n",
1706 c->log );
1707 return 1;
1708 }
1709
1710 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1711 exit( EXIT_FAILURE );
1712 }
1713
1714 } else {
1715 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1716 }
1717
1718 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1719 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1720
1721 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1722 {
1723 Debug( LDAP_DEBUG_ANY, "%s: "
1724 "unable to parse chaining control%s%s.\n",
1725 c->log, rs.sr_text ? ": " : "",
1726 rs.sr_text ? rs.sr_text : "" );
1727 return 1;
1728 }
1729
1730 lc->lc_chaining_ctrlflag = op.o_chaining;
1731
1732 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1733
1734 rc = 0;
1735 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1736 Debug( LDAP_DEBUG_ANY, "%s: "
1737 "\"chaining\" control unsupported (ignored).\n",
1738 c->log );
1739 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1740 } break;
1741
1742 case CH_CACHE_URI:
1743 if ( c->value_int ) {
1744 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1745 } else {
1746 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1747 }
1748 break;
1749
1750 case CH_MAX_DEPTH:
1751 if ( c->value_int < 0 ) {
1752 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1753 "<%s> invalid max referral depth %d",
1754 c->argv[0], c->value_int );
1755 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1756 c->log, c->cr_msg );
1757 rc = 1;
1758 break;
1759 }
1760 lc->lc_max_depth = c->value_int;
1761
1762 case CH_RETURN_ERR:
1763 if ( c->value_int ) {
1764 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1765 } else {
1766 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1767 }
1768 break;
1769
1770 default:
1771 assert( 0 );
1772 return 1;
1773 }
1774 return rc;
1775 }
1776
1777 static int
ldap_chain_db_init(BackendDB * be,ConfigReply * cr)1778 ldap_chain_db_init(
1779 BackendDB *be,
1780 ConfigReply *cr )
1781 {
1782 slap_overinst *on = (slap_overinst *)be->bd_info;
1783 ldap_chain_t *lc = NULL;
1784
1785 if ( lback == NULL ) {
1786 lback = backend_info( "ldap" );
1787
1788 if ( lback == NULL ) {
1789 return 1;
1790 }
1791 }
1792
1793 lc = ch_malloc( sizeof( ldap_chain_t ) );
1794 if ( lc == NULL ) {
1795 return 1;
1796 }
1797 memset( lc, 0, sizeof( ldap_chain_t ) );
1798 lc->lc_max_depth = 1;
1799 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1800
1801 on->on_bi.bi_private = (void *)lc;
1802
1803 return 0;
1804 }
1805
1806 static int
ldap_chain_db_config(BackendDB * be,const char * fname,int lineno,int argc,char ** argv)1807 ldap_chain_db_config(
1808 BackendDB *be,
1809 const char *fname,
1810 int lineno,
1811 int argc,
1812 char **argv )
1813 {
1814 slap_overinst *on = (slap_overinst *)be->bd_info;
1815 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1816
1817 int rc = SLAP_CONF_UNKNOWN;
1818
1819 if ( lc->lc_common_li == NULL ) {
1820 BackendDB db = *be;
1821 ldap_chain_db_init_common( &db );
1822 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)db.be_private;
1823 }
1824
1825 /* Something for the chain database? */
1826 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1827 char *save_argv0 = argv[ 0 ];
1828 BackendDB db = *be;
1829 static char *allowed_argv[] = {
1830 /* special: put URI here, so in the meanwhile
1831 * it detects whether a new URI is being provided */
1832 "uri",
1833 "nretries",
1834 "timeout",
1835 /* flags */
1836 "tls",
1837 /* FIXME: maybe rebind-as-user should be allowed
1838 * only within known URIs... */
1839 "rebind-as-user",
1840 "chase-referrals",
1841 "t-f-support",
1842 "proxy-whoami",
1843 NULL
1844 };
1845 int which_argv = -1;
1846
1847 argv[ 0 ] += STRLENOF( "chain-" );
1848
1849 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1850 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1851 break;
1852 }
1853 }
1854
1855 if ( allowed_argv[ which_argv ] == NULL ) {
1856 which_argv = -1;
1857
1858 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1859 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1860 "\"%s\" only allowed within a URI directive.\n.",
1861 fname, lineno, argv[ 0 ] );
1862 return 1;
1863 }
1864 }
1865
1866 if ( which_argv == 0 ) {
1867 rc = ldap_chain_db_init_one( &db );
1868 if ( rc != 0 ) {
1869 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1870 "underlying slapd-ldap initialization failed.\n.",
1871 fname, lineno );
1872 return 1;
1873 }
1874 lc->lc_cfg_li = db.be_private;
1875 }
1876
1877 /* TODO: add checks on what other slapd-ldap(5) args
1878 * should be put in the template; this is not quite
1879 * harmful, because attributes that shouldn't don't
1880 * get actually used, but the user should at least
1881 * be warned.
1882 */
1883
1884 db.bd_info = lback;
1885 db.be_private = (void *)lc->lc_cfg_li;
1886 db.be_cf_ocs = lback->bi_cf_ocs;
1887
1888 rc = config_generic_wrapper( &db, fname, lineno, argc, argv );
1889
1890 argv[ 0 ] = save_argv0;
1891
1892 if ( which_argv == 0 ) {
1893 private_destroy:;
1894 if ( rc != 0 ) {
1895 db.bd_info = lback;
1896 db.be_private = (void *)lc->lc_cfg_li;
1897 ldap_chain_db_destroy_one( &db, NULL );
1898 lc->lc_cfg_li = NULL;
1899 } else {
1900 if ( lc->lc_cfg_li->li_bvuri == NULL
1901 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1902 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1903 {
1904 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1905 "no URI list allowed in slapo-chain.\n",
1906 fname, lineno );
1907 rc = 1;
1908 goto private_destroy;
1909 }
1910
1911 if ( ldap_tavl_insert( &lc->lc_lai.lai_tree,
1912 (caddr_t)lc->lc_cfg_li,
1913 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1914 {
1915 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1916 "duplicate URI in slapo-chain.\n",
1917 fname, lineno );
1918 rc = 1;
1919 goto private_destroy;
1920 }
1921 }
1922 }
1923 }
1924
1925 return rc;
1926 }
1927
1928 enum db_which {
1929 db_open = 0,
1930 db_close,
1931 db_destroy,
1932
1933 db_last
1934 };
1935
1936 static int
ldap_chain_db_func(BackendDB * be,enum db_which which)1937 ldap_chain_db_func(
1938 BackendDB *be,
1939 enum db_which which
1940 )
1941 {
1942 slap_overinst *on = (slap_overinst *)be->bd_info;
1943 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1944
1945 int rc = 0;
1946
1947 if ( lc ) {
1948 BI_db_func *func = (&lback->bi_db_open)[ which ];
1949
1950 if ( func != NULL && lc->lc_common_li != NULL ) {
1951 BackendDB db = *be;
1952
1953 db.bd_info = lback;
1954 db.be_private = lc->lc_common_li;
1955
1956 rc = func( &db, NULL );
1957
1958 if ( rc != 0 ) {
1959 return rc;
1960 }
1961
1962 if ( lc->lc_lai.lai_tree != NULL ) {
1963 TAvlnode *edge = ldap_tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
1964 while ( edge ) {
1965 TAvlnode *next = ldap_tavl_next( edge, TAVL_DIR_RIGHT );
1966 ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
1967 db.be_private = (void *)li;
1968 rc = func( &db, NULL );
1969 if ( rc == 1 ) {
1970 break;
1971 }
1972 edge = next;
1973 }
1974 }
1975 }
1976 }
1977
1978 return rc;
1979 }
1980
1981 static int
ldap_chain_db_open(BackendDB * be,ConfigReply * cr)1982 ldap_chain_db_open(
1983 BackendDB *be,
1984 ConfigReply *cr )
1985 {
1986 slap_overinst *on = (slap_overinst *) be->bd_info;
1987 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1988 slap_mask_t monitoring;
1989 int rc = 0;
1990
1991 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1992 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1993 if ( rc != 0 ) {
1994 return rc;
1995 }
1996 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1997
1998 if ( lc->lc_common_li == NULL ) {
1999 void *be_private = be->be_private;
2000 ldap_chain_db_init_common( be );
2001 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
2002 be->be_private = be_private;
2003 }
2004
2005 /* filter out and restore monitoring */
2006 monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING );
2007 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING;
2008 rc = ldap_chain_db_func( be, db_open );
2009 SLAP_DBFLAGS( be ) |= monitoring;
2010
2011 return rc;
2012 }
2013
2014 static int
ldap_chain_db_close(BackendDB * be,ConfigReply * cr)2015 ldap_chain_db_close(
2016 BackendDB *be,
2017 ConfigReply *cr )
2018 {
2019 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2020 #ifdef SLAP_CONFIG_DELETE
2021 overlay_unregister_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
2022 #endif /* SLAP_CONFIG_DELETE */
2023 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2024 return ldap_chain_db_func( be, db_close );
2025 }
2026
2027 static int
ldap_chain_db_destroy(BackendDB * be,ConfigReply * cr)2028 ldap_chain_db_destroy(
2029 BackendDB *be,
2030 ConfigReply *cr )
2031 {
2032 slap_overinst *on = (slap_overinst *) be->bd_info;
2033 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
2034
2035 int rc;
2036
2037 rc = ldap_chain_db_func( be, db_destroy );
2038
2039 if ( lc ) {
2040 ldap_tavl_free( lc->lc_lai.lai_tree, NULL );
2041 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
2042 ch_free( lc );
2043 }
2044
2045 return rc;
2046 }
2047
2048 /*
2049 * inits one instance of the slapd-ldap backend, and stores
2050 * the private info in be_private of the arg
2051 */
2052 static int
ldap_chain_db_init_common(BackendDB * be)2053 ldap_chain_db_init_common(
2054 BackendDB *be )
2055 {
2056 BackendInfo *bi = be->bd_info;
2057 ldapinfo_t *li;
2058 int rc;
2059
2060 be->bd_info = lback;
2061 be->be_private = NULL;
2062 rc = lback->bi_db_init( be, NULL );
2063 if ( rc != 0 ) {
2064 return rc;
2065 }
2066 li = (ldapinfo_t *)be->be_private;
2067 li->li_urllist_f = NULL;
2068 li->li_urllist_p = NULL;
2069
2070 be->bd_info = bi;
2071
2072 return 0;
2073 }
2074
2075 /*
2076 * inits one instance of the slapd-ldap backend, stores
2077 * the private info in be_private of the arg and fills
2078 * selected fields with data from the template.
2079 *
2080 * NOTE: add checks about the other fields of the template,
2081 * which are ignored and SHOULD NOT be configured by the user.
2082 */
2083 static int
ldap_chain_db_init_one(BackendDB * be)2084 ldap_chain_db_init_one(
2085 BackendDB *be )
2086 {
2087 slap_overinst *on = (slap_overinst *)be->bd_info;
2088 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
2089
2090 BackendInfo *bi = be->bd_info;
2091 ldapinfo_t *li;
2092
2093 slap_op_t t;
2094
2095 be->bd_info = lback;
2096 be->be_private = NULL;
2097 t = lback->bi_db_init( be, NULL );
2098 if ( t != 0 ) {
2099 return t;
2100 }
2101 li = (ldapinfo_t *)be->be_private;
2102 li->li_urllist_f = NULL;
2103 li->li_urllist_p = NULL;
2104
2105 /* copy common data */
2106 li->li_nretries = lc->lc_common_li->li_nretries;
2107 li->li_flags = lc->lc_common_li->li_flags;
2108 li->li_version = lc->lc_common_li->li_version;
2109 for ( t = 0; t < SLAP_OP_LAST; t++ ) {
2110 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
2111 }
2112 be->bd_info = bi;
2113
2114 return 0;
2115 }
2116
2117 static int
ldap_chain_db_open_one(BackendDB * be)2118 ldap_chain_db_open_one(
2119 BackendDB *be )
2120 {
2121 if ( SLAP_DBMONITORING( be ) ) {
2122 ldapinfo_t *li = (ldapinfo_t *)be->be_private;
2123
2124 if ( li->li_uri == NULL ) {
2125 ber_str2bv( "cn=Common Connections", 0, 1,
2126 &li->li_monitor_info.lmi_conn_rdn );
2127 ber_str2bv( "cn=Operations on Common Connections", 0, 1,
2128 &li->li_monitor_info.lmi_conn_rdn );
2129
2130 } else {
2131 char *ptr;
2132
2133 li->li_monitor_info.lmi_conn_rdn.bv_len
2134 = STRLENOF( "cn=" ) + strlen( li->li_uri );
2135 ptr = li->li_monitor_info.lmi_conn_rdn.bv_val
2136 = ch_malloc( li->li_monitor_info.lmi_conn_rdn.bv_len + 1 );
2137 ptr = lutil_strcopy( ptr, "cn=" );
2138 ptr = lutil_strcopy( ptr, li->li_uri );
2139 ptr[ 0 ] = '\0';
2140
2141 li->li_monitor_info.lmi_ops_rdn.bv_len
2142 = STRLENOF( "cn=Operations on " ) + strlen( li->li_uri );
2143 ptr = li->li_monitor_info.lmi_ops_rdn.bv_val
2144 = ch_malloc( li->li_monitor_info.lmi_ops_rdn.bv_len + 1 );
2145 ptr = lutil_strcopy( ptr, "cn=Operations on " );
2146 ptr = lutil_strcopy( ptr, li->li_uri );
2147 ptr[ 0 ] = '\0';
2148 }
2149 }
2150
2151 return lback->bi_db_open( be, NULL );
2152 }
2153
2154 static int
ldap_chain_connection_destroy(BackendDB * be,Connection * conn)2155 ldap_chain_connection_destroy(
2156 BackendDB *be,
2157 Connection *conn
2158 )
2159 {
2160 slap_overinst *on = (slap_overinst *) be->bd_info;
2161 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
2162 void *private = be->be_private;
2163 TAvlnode *edge;
2164 int rc;
2165
2166 be->be_private = NULL;
2167 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
2168 edge = ldap_tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
2169 while ( edge ) {
2170 TAvlnode *next = ldap_tavl_next( edge, TAVL_DIR_RIGHT );
2171 ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
2172 be->be_private = (void *)li;
2173 rc = lback->bi_connection_destroy( be, conn );
2174 if ( rc == 1 ) {
2175 break;
2176 }
2177 edge = next;
2178 }
2179
2180
2181 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
2182 be->be_private = private;
2183
2184 return rc;
2185 }
2186
2187 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2188 static int
ldap_chain_parse_ctrl(Operation * op,SlapReply * rs,LDAPControl * ctrl)2189 ldap_chain_parse_ctrl(
2190 Operation *op,
2191 SlapReply *rs,
2192 LDAPControl *ctrl )
2193 {
2194 ber_tag_t tag;
2195 BerElement *ber;
2196 ber_int_t mode,
2197 behavior;
2198
2199 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
2200 rs->sr_text = "Chaining behavior control specified multiple times";
2201 return LDAP_PROTOCOL_ERROR;
2202 }
2203
2204 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
2205 rs->sr_text = "Chaining behavior control specified with pagedResults control";
2206 return LDAP_PROTOCOL_ERROR;
2207 }
2208
2209 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
2210 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
2211
2212 } else {
2213 ber_len_t len;
2214
2215 /* Parse the control value
2216 * ChainingBehavior ::= SEQUENCE {
2217 * resolveBehavior Behavior OPTIONAL,
2218 * continuationBehavior Behavior OPTIONAL }
2219 *
2220 * Behavior :: = ENUMERATED {
2221 * chainingPreferred (0),
2222 * chainingRequired (1),
2223 * referralsPreferred (2),
2224 * referralsRequired (3) }
2225 */
2226
2227 ber = ber_init( &ctrl->ldctl_value );
2228 if( ber == NULL ) {
2229 rs->sr_text = "internal error";
2230 return LDAP_OTHER;
2231 }
2232
2233 tag = ber_scanf( ber, "{e" /* } */, &behavior );
2234 /* FIXME: since the whole SEQUENCE is optional,
2235 * should we accept no enumerations at all? */
2236 if ( tag != LBER_ENUMERATED ) {
2237 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
2238 return LDAP_PROTOCOL_ERROR;
2239 }
2240
2241 switch ( behavior ) {
2242 case LDAP_CHAINING_PREFERRED:
2243 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
2244 break;
2245
2246 case LDAP_CHAINING_REQUIRED:
2247 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
2248 break;
2249
2250 case LDAP_REFERRALS_PREFERRED:
2251 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
2252 break;
2253
2254 case LDAP_REFERRALS_REQUIRED:
2255 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
2256 break;
2257
2258 default:
2259 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
2260 return LDAP_PROTOCOL_ERROR;
2261 }
2262
2263 tag = ber_peek_tag( ber, &len );
2264 if ( tag == LBER_ENUMERATED ) {
2265 tag = ber_scanf( ber, "e", &behavior );
2266 if ( tag == LBER_ERROR ) {
2267 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
2268 return LDAP_PROTOCOL_ERROR;
2269 }
2270 }
2271
2272 if ( tag == LBER_DEFAULT ) {
2273 mode |= SLAP_CH_CONTINUATION_DEFAULT;
2274
2275 } else {
2276 switch ( behavior ) {
2277 case LDAP_CHAINING_PREFERRED:
2278 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
2279 break;
2280
2281 case LDAP_CHAINING_REQUIRED:
2282 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
2283 break;
2284
2285 case LDAP_REFERRALS_PREFERRED:
2286 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
2287 break;
2288
2289 case LDAP_REFERRALS_REQUIRED:
2290 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
2291 break;
2292
2293 default:
2294 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
2295 return LDAP_PROTOCOL_ERROR;
2296 }
2297 }
2298
2299 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
2300 rs->sr_text = "Chaining behavior control: decoding error";
2301 return LDAP_PROTOCOL_ERROR;
2302 }
2303
2304 (void) ber_free( ber, 1 );
2305 }
2306
2307 op->o_chaining = mode | ( ctrl->ldctl_iscritical
2308 ? SLAP_CONTROL_CRITICAL
2309 : SLAP_CONTROL_NONCRITICAL );
2310
2311 return LDAP_SUCCESS;
2312 }
2313 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2314
2315 int
chain_initialize(void)2316 chain_initialize( void )
2317 {
2318 int rc;
2319
2320 /* Make sure we don't exceed the bits reserved for userland */
2321 config_check_userland( CH_LAST );
2322
2323 /* olcDatabaseDummy is defined in slapd, and Windows
2324 will not let us initialize a struct element with a data pointer
2325 from another library, so we have to initialize this element
2326 "by hand". */
2327 chainocs[1].co_table = olcDatabaseDummy;
2328
2329 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2330 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
2331 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
2332 ldap_chain_parse_ctrl, &sc_chainingBehavior );
2333 if ( rc != LDAP_SUCCESS ) {
2334 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
2335 "unable to register chaining behavior control: %d.\n",
2336 rc );
2337 return rc;
2338 }
2339 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2340
2341 ldapchain.on_bi.bi_type = "chain";
2342 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
2343 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
2344 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
2345 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
2346 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
2347
2348 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2349
2350 ldapchain.on_response = ldap_chain_response;
2351
2352 ldapchain.on_bi.bi_cf_ocs = chainocs;
2353
2354 rc = config_register_schema( chaincfg, chainocs );
2355 if ( rc ) {
2356 return rc;
2357 }
2358
2359 return overlay_register( &ldapchain );
2360 }
2361
2362