1 /* $NetBSD: bind.c,v 1.3 2021/08/14 16:15:00 christos Exp $ */
2
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1999-2021 The OpenLDAP Foundation.
7 * Portions Copyright 2001-2003 Pierangelo Masarati.
8 * Portions Copyright 1999-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 and subsequently enhanced by Pierangelo
22 * Masarati.
23 */
24
25 #include <sys/cdefs.h>
26 __RCSID("$NetBSD: bind.c,v 1.3 2021/08/14 16:15:00 christos Exp $");
27
28 #include "portable.h"
29
30 #include <stdio.h>
31
32 #include <ac/errno.h>
33 #include <ac/socket.h>
34 #include <ac/string.h>
35
36
37 #define AVL_INTERNAL
38 #include "slap.h"
39 #include "../back-ldap/back-ldap.h"
40 #include "back-meta.h"
41
42 #include "lutil_ldap.h"
43
44 static int
45 meta_back_proxy_authz_bind(
46 metaconn_t *mc,
47 int candidate,
48 Operation *op,
49 SlapReply *rs,
50 ldap_back_send_t sendok,
51 int dolock );
52
53 static int
54 meta_back_single_bind(
55 Operation *op,
56 SlapReply *rs,
57 metaconn_t *mc,
58 int candidate );
59
60 int
meta_back_bind(Operation * op,SlapReply * rs)61 meta_back_bind( Operation *op, SlapReply *rs )
62 {
63 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
64 metaconn_t *mc = NULL;
65
66 int rc = LDAP_OTHER,
67 i,
68 gotit = 0,
69 isroot = 0;
70
71 SlapReply *candidates;
72
73 rs->sr_err = LDAP_SUCCESS;
74
75 Debug( LDAP_DEBUG_ARGS, "%s meta_back_bind: dn=\"%s\".\n",
76 op->o_log_prefix, op->o_req_dn.bv_val );
77
78 /* the test on the bind method should be superfluous */
79 switch ( be_rootdn_bind( op, rs ) ) {
80 case LDAP_SUCCESS:
81 if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) {
82 /* frontend will return success */
83 return rs->sr_err;
84 }
85
86 isroot = 1;
87 /* fallthru */
88
89 case SLAP_CB_CONTINUE:
90 break;
91
92 default:
93 /* be_rootdn_bind() sent result */
94 return rs->sr_err;
95 }
96
97 /* we need meta_back_getconn() not send result even on error,
98 * because we want to intercept the error and make it
99 * invalidCredentials */
100 mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND );
101 if ( !mc ) {
102 Debug(LDAP_DEBUG_ANY,
103 "%s meta_back_bind: no target " "for dn \"%s\" (%d%s%s).\n",
104 op->o_log_prefix, op->o_req_dn.bv_val,
105 rs->sr_err, rs->sr_text ? ". " : "",
106 rs->sr_text ? rs->sr_text : "" );
107
108 /* FIXME: there might be cases where we don't want
109 * to map the error onto invalidCredentials */
110 switch ( rs->sr_err ) {
111 case LDAP_NO_SUCH_OBJECT:
112 case LDAP_UNWILLING_TO_PERFORM:
113 rs->sr_err = LDAP_INVALID_CREDENTIALS;
114 rs->sr_text = NULL;
115 break;
116 }
117 send_ldap_result( op, rs );
118 return rs->sr_err;
119 }
120
121 candidates = meta_back_candidates_get( op );
122
123 /*
124 * Each target is scanned ...
125 */
126 mc->mc_authz_target = META_BOUND_NONE;
127 for ( i = 0; i < mi->mi_ntargets; i++ ) {
128 metatarget_t *mt = mi->mi_targets[ i ];
129 int lerr;
130
131 /*
132 * Skip non-candidates
133 */
134 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
135 continue;
136 }
137
138 if ( gotit == 0 ) {
139 /* set rc to LDAP_SUCCESS only if at least
140 * one candidate has been tried */
141 rc = LDAP_SUCCESS;
142 gotit = 1;
143
144 } else if ( !isroot ) {
145 /*
146 * A bind operation is expected to have
147 * ONE CANDIDATE ONLY!
148 */
149 Debug( LDAP_DEBUG_ANY,
150 "### %s meta_back_bind: more than one"
151 " candidate selected...\n",
152 op->o_log_prefix );
153 }
154
155 if ( isroot ) {
156 if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE
157 || BER_BVISNULL( &mt->mt_idassert_authcDN ) )
158 {
159 metasingleconn_t *msc = &mc->mc_conns[ i ];
160
161 /* skip the target if no pseudorootdn is provided */
162 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
163 ch_free( msc->msc_bound_ndn.bv_val );
164 BER_BVZERO( &msc->msc_bound_ndn );
165 }
166
167 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
168 /* destroy sensitive data */
169 memset( msc->msc_cred.bv_val, 0,
170 msc->msc_cred.bv_len );
171 ch_free( msc->msc_cred.bv_val );
172 BER_BVZERO( &msc->msc_cred );
173 }
174
175 continue;
176 }
177
178
179 (void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND, 1 );
180 lerr = rs->sr_err;
181
182 } else {
183 lerr = meta_back_single_bind( op, rs, mc, i );
184 }
185
186 if ( lerr != LDAP_SUCCESS ) {
187 rc = rs->sr_err = lerr;
188
189 /* FIXME: in some cases (e.g. unavailable)
190 * do not assume it's not candidate; rather
191 * mark this as an error to be eventually
192 * reported to client */
193 META_CANDIDATE_CLEAR( &candidates[ i ] );
194 break;
195 }
196 }
197
198 /* must re-insert if local DN changed as result of bind */
199 if ( rc == LDAP_SUCCESS ) {
200 if ( isroot ) {
201 mc->mc_authz_target = META_BOUND_ALL;
202 }
203
204 if ( !LDAP_BACK_PCONN_ISPRIV( mc )
205 && !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) )
206 {
207 int lerr;
208
209 /* wait for all other ops to release the connection */
210 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
211 assert( mc->mc_refcnt == 1 );
212 #if META_BACK_PRINT_CONNTREE > 0
213 meta_back_print_conntree( mi, ">>> meta_back_bind" );
214 #endif /* META_BACK_PRINT_CONNTREE */
215
216 /* delete all cached connections with the current connection */
217 if ( LDAP_BACK_SINGLECONN( mi ) ) {
218 metaconn_t *tmpmc;
219
220 while ( ( tmpmc = ldap_tavl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )
221 {
222 assert( !LDAP_BACK_PCONN_ISPRIV( mc ) );
223 Debug( LDAP_DEBUG_TRACE,
224 "=>meta_back_bind: destroying conn %lu (refcnt=%u)\n",
225 mc->mc_conn->c_connid, mc->mc_refcnt );
226
227 if ( tmpmc->mc_refcnt != 0 ) {
228 /* taint it */
229 LDAP_BACK_CONN_TAINTED_SET( tmpmc );
230
231 } else {
232 /*
233 * Needs a test because the handler may be corrupted,
234 * and calling ldap_unbind on a corrupted header results
235 * in a segmentation fault
236 */
237 meta_back_conn_free( tmpmc );
238 }
239 }
240 }
241
242 ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
243 lerr = ldap_tavl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
244 meta_back_conndn_cmp, meta_back_conndn_dup );
245 #if META_BACK_PRINT_CONNTREE > 0
246 meta_back_print_conntree( mi, "<<< meta_back_bind" );
247 #endif /* META_BACK_PRINT_CONNTREE */
248 if ( lerr == 0 ) {
249 #if 0
250 /* NOTE: a connection cannot be privileged
251 * and be in the avl tree at the same time
252 */
253 if ( isroot ) {
254 LDAP_BACK_CONN_ISPRIV_SET( mc );
255 LDAP_BACK_PCONN_SET( mc, op );
256 }
257 #endif
258 LDAP_BACK_CONN_CACHED_SET( mc );
259
260 } else {
261 LDAP_BACK_CONN_CACHED_CLEAR( mc );
262 }
263 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
264 }
265 }
266
267 if ( mc != NULL ) {
268 meta_back_release_conn( mi, mc );
269 }
270
271 /*
272 * rc is LDAP_SUCCESS if at least one bind succeeded,
273 * err is the last error that occurred during a bind;
274 * if at least (and at most?) one bind succeeds, fine.
275 */
276 if ( rc != LDAP_SUCCESS ) {
277
278 /*
279 * deal with bind failure ...
280 */
281
282 /*
283 * no target was found within the naming context,
284 * so bind must fail with invalid credentials
285 */
286 if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {
287 rs->sr_err = LDAP_INVALID_CREDENTIALS;
288 } else {
289 rs->sr_err = slap_map_api2result( rs );
290 }
291 send_ldap_result( op, rs );
292 return rs->sr_err;
293
294 }
295
296 return LDAP_SUCCESS;
297 }
298
299 static int
meta_back_bind_op_result(Operation * op,SlapReply * rs,metaconn_t * mc,int candidate,int msgid,ldap_back_send_t sendok,int dolock)300 meta_back_bind_op_result(
301 Operation *op,
302 SlapReply *rs,
303 metaconn_t *mc,
304 int candidate,
305 int msgid,
306 ldap_back_send_t sendok,
307 int dolock )
308 {
309 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
310 metatarget_t *mt = mi->mi_targets[ candidate ];
311 metasingleconn_t *msc = &mc->mc_conns[ candidate ];
312 LDAPMessage *res;
313 struct timeval tv;
314 int rc;
315 int nretries = mt->mt_nretries;
316
317 Debug( LDAP_DEBUG_TRACE,
318 ">>> %s meta_back_bind_op_result[%d]\n",
319 op->o_log_prefix, candidate );
320
321 /* make sure this is clean */
322 assert( rs->sr_ctrls == NULL );
323
324 if ( rs->sr_err == LDAP_SUCCESS ) {
325 time_t stoptime = (time_t)(-1),
326 timeout;
327 int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
328 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
329 const char *timeout_text = "Operation timed out";
330 slap_op_t opidx = slap_req2op( op->o_tag );
331
332 /* since timeout is not specified, compute and use
333 * the one specific to the ongoing operation */
334 if ( opidx == LDAP_REQ_SEARCH ) {
335 if ( op->ors_tlimit <= 0 ) {
336 timeout = 0;
337
338 } else {
339 timeout = op->ors_tlimit;
340 timeout_err = LDAP_TIMELIMIT_EXCEEDED;
341 timeout_text = NULL;
342 }
343
344 } else {
345 timeout = mt->mt_timeout[ opidx ];
346 }
347
348 /* better than nothing :) */
349 if ( timeout == 0 ) {
350 if ( mi->mi_idle_timeout ) {
351 timeout = mi->mi_idle_timeout;
352
353 } else if ( mi->mi_conn_ttl ) {
354 timeout = mi->mi_conn_ttl;
355 }
356 }
357
358 if ( timeout ) {
359 stoptime = op->o_time + timeout;
360 }
361
362 LDAP_BACK_TV_SET( &tv );
363
364 /*
365 * handle response!!!
366 */
367 retry:;
368 rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
369 switch ( rc ) {
370 case 0:
371 if ( nretries != META_RETRY_NEVER
372 || ( timeout && slap_get_time() <= stoptime ) )
373 {
374 ldap_pvt_thread_yield();
375 if ( nretries > 0 ) {
376 nretries--;
377 }
378 tv = mt->mt_bind_timeout;
379 goto retry;
380 }
381
382 /* don't let anyone else use this handler,
383 * because there's a pending bind that will not
384 * be acknowledged */
385 if ( dolock) {
386 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
387 }
388 assert( LDAP_BACK_CONN_BINDING( msc ) );
389
390 #ifdef DEBUG_205
391 Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n",
392 op->o_log_prefix, candidate, (void *)msc->msc_ld );
393 #endif /* DEBUG_205 */
394
395 meta_clear_one_candidate( op, mc, candidate );
396 if ( dolock ) {
397 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
398 }
399
400 rs->sr_err = timeout_err;
401 rs->sr_text = timeout_text;
402 break;
403
404 case -1:
405 ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
406 &rs->sr_err );
407
408 Debug(LDAP_DEBUG_ANY,
409 "### %s meta_back_bind_op_result[%d]: err=%d (%s) nretries=%d.\n",
410 op->o_log_prefix, candidate, rs->sr_err,
411 ldap_err2string(rs->sr_err), nretries );
412 break;
413
414 default:
415 /* only touch when activity actually took place... */
416 if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
417 msc->msc_time = op->o_time;
418 }
419
420 /* FIXME: matched? referrals? response controls? */
421 rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
422 NULL, NULL, NULL, NULL, 1 );
423 if ( rc != LDAP_SUCCESS ) {
424 rs->sr_err = rc;
425 }
426 rs->sr_err = slap_map_api2result( rs );
427 break;
428 }
429 }
430
431 rs->sr_err = slap_map_api2result( rs );
432
433 Debug( LDAP_DEBUG_TRACE,
434 "<<< %s meta_back_bind_op_result[%d] err=%d\n",
435 op->o_log_prefix, candidate, rs->sr_err );
436
437 return rs->sr_err;
438 }
439
440 /*
441 * meta_back_single_bind
442 *
443 * attempts to perform a bind with creds
444 */
445 static int
meta_back_single_bind(Operation * op,SlapReply * rs,metaconn_t * mc,int candidate)446 meta_back_single_bind(
447 Operation *op,
448 SlapReply *rs,
449 metaconn_t *mc,
450 int candidate )
451 {
452 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
453 metatarget_t *mt = mi->mi_targets[ candidate ];
454 struct berval mdn = BER_BVNULL;
455 metasingleconn_t *msc = &mc->mc_conns[ candidate ];
456 int msgid;
457 dncookie dc;
458 struct berval save_o_dn;
459 int save_o_do_not_cache;
460 LDAPControl **ctrls = NULL;
461
462 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
463 ch_free( msc->msc_bound_ndn.bv_val );
464 BER_BVZERO( &msc->msc_bound_ndn );
465 }
466
467 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
468 /* destroy sensitive data */
469 memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
470 ch_free( msc->msc_cred.bv_val );
471 BER_BVZERO( &msc->msc_cred );
472 }
473
474 /*
475 * Rewrite the bind dn if needed
476 */
477 dc.target = mt;
478 dc.conn = op->o_conn;
479 dc.rs = rs;
480 dc.ctx = "bindDN";
481
482 if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
483 rs->sr_text = "DN rewrite error";
484 rs->sr_err = LDAP_OTHER;
485 return rs->sr_err;
486 }
487
488 /* don't add proxyAuthz; set the bindDN */
489 save_o_dn = op->o_dn;
490 save_o_do_not_cache = op->o_do_not_cache;
491 op->o_do_not_cache = 1;
492 op->o_dn = op->o_req_dn;
493
494 ctrls = op->o_ctrls;
495 rs->sr_err = meta_back_controls_add( op, rs, mc, candidate, &ctrls );
496 op->o_dn = save_o_dn;
497 op->o_do_not_cache = save_o_do_not_cache;
498 if ( rs->sr_err != LDAP_SUCCESS ) {
499 goto return_results;
500 }
501
502 /* FIXME: this fixes the bind problem right now; we need
503 * to use the asynchronous version to get the "matched"
504 * and more in case of failure ... */
505 /* FIXME: should we check if at least some of the op->o_ctrls
506 * can/should be passed? */
507 for (;;) {
508 rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val,
509 LDAP_SASL_SIMPLE, &op->orb_cred,
510 ctrls, NULL, &msgid );
511 if ( rs->sr_err != LDAP_X_CONNECTING ) {
512 break;
513 }
514 ldap_pvt_thread_yield();
515 }
516
517 mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
518
519 meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND, 1 );
520 if ( rs->sr_err != LDAP_SUCCESS ) {
521 goto return_results;
522 }
523
524 /* If defined, proxyAuthz will be used also when
525 * back-ldap is the authorizing backend; for this
526 * purpose, a successful bind is followed by a
527 * bind with the configured identity assertion */
528 /* NOTE: use with care */
529 if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
530 meta_back_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR, 1 );
531 if ( !LDAP_BACK_CONN_ISBOUND( msc ) ) {
532 goto return_results;
533 }
534 goto cache_refresh;
535 }
536
537 ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_ndn );
538 LDAP_BACK_CONN_ISBOUND_SET( msc );
539 mc->mc_authz_target = candidate;
540
541 if ( META_BACK_TGT_SAVECRED( mt ) ) {
542 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
543 memset( msc->msc_cred.bv_val, 0,
544 msc->msc_cred.bv_len );
545 }
546 ber_bvreplace( &msc->msc_cred, &op->orb_cred );
547 ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
548 }
549
550 cache_refresh:;
551 if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED
552 && !BER_BVISEMPTY( &op->o_req_ndn ) )
553 {
554 ( void )meta_dncache_update_entry( &mi->mi_cache,
555 &op->o_req_ndn, candidate );
556 }
557
558 return_results:;
559 if ( mdn.bv_val != op->o_req_dn.bv_val ) {
560 free( mdn.bv_val );
561 }
562
563 if ( META_BACK_TGT_QUARANTINE( mt ) ) {
564 meta_back_quarantine( op, rs, candidate );
565 }
566
567 return rs->sr_err;
568 }
569
570 /*
571 * meta_back_single_dobind
572 */
573 int
meta_back_single_dobind(Operation * op,SlapReply * rs,metaconn_t ** mcp,int candidate,ldap_back_send_t sendok,int nretries,int dolock)574 meta_back_single_dobind(
575 Operation *op,
576 SlapReply *rs,
577 metaconn_t **mcp,
578 int candidate,
579 ldap_back_send_t sendok,
580 int nretries,
581 int dolock )
582 {
583 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
584 metatarget_t *mt = mi->mi_targets[ candidate ];
585 metaconn_t *mc = *mcp;
586 metasingleconn_t *msc = &mc->mc_conns[ candidate ];
587 int msgid;
588
589 assert( !LDAP_BACK_CONN_ISBOUND( msc ) );
590
591 /* NOTE: this obsoletes pseudorootdn */
592 if ( op->o_conn != NULL &&
593 !op->o_do_not_cache &&
594 ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
595 BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
596 ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) ||
597 ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
598 {
599 (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok, dolock );
600
601 } else {
602 char *binddn = "";
603 struct berval cred = BER_BVC( "" );
604
605 /* use credentials if available */
606 if ( !BER_BVISNULL( &msc->msc_bound_ndn )
607 && !BER_BVISNULL( &msc->msc_cred ) )
608 {
609 binddn = msc->msc_bound_ndn.bv_val;
610 cred = msc->msc_cred;
611 }
612
613 /* FIXME: should we check if at least some of the op->o_ctrls
614 * can/should be passed? */
615 if(!dolock) {
616 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
617 }
618
619 for (;;) {
620 rs->sr_err = ldap_sasl_bind( msc->msc_ld,
621 binddn, LDAP_SASL_SIMPLE, &cred,
622 NULL, NULL, &msgid );
623 if ( rs->sr_err != LDAP_X_CONNECTING ) {
624 break;
625 }
626 ldap_pvt_thread_yield();
627 }
628
629 if(!dolock) {
630 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
631 }
632
633 rs->sr_err = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
634
635 /* if bind succeeded, but anonymous, clear msc_bound_ndn */
636 if ( rs->sr_err != LDAP_SUCCESS || binddn[0] == '\0' ) {
637 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
638 ber_memfree( msc->msc_bound_ndn.bv_val );
639 BER_BVZERO( &msc->msc_bound_ndn );
640 }
641
642 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
643 memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
644 ber_memfree( msc->msc_cred.bv_val );
645 BER_BVZERO( &msc->msc_cred );
646 }
647 }
648 }
649
650 if ( rs->sr_err != LDAP_SUCCESS ) {
651 if ( dolock ) {
652 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
653 }
654 LDAP_BACK_CONN_BINDING_CLEAR( msc );
655 if ( META_BACK_ONERR_STOP( mi ) ) {
656 LDAP_BACK_CONN_TAINTED_SET( mc );
657 meta_back_release_conn_lock( mi, mc, 0 );
658 *mcp = NULL;
659 }
660 if ( dolock ) {
661 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
662 }
663 }
664
665 if ( META_BACK_TGT_QUARANTINE( mt ) ) {
666 meta_back_quarantine( op, rs, candidate );
667 }
668
669 return rs->sr_err;
670 }
671
672 /*
673 * meta_back_dobind
674 */
675 int
meta_back_dobind(Operation * op,SlapReply * rs,metaconn_t * mc,ldap_back_send_t sendok)676 meta_back_dobind(
677 Operation *op,
678 SlapReply *rs,
679 metaconn_t *mc,
680 ldap_back_send_t sendok )
681 {
682 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
683
684 int bound = 0,
685 i,
686 isroot = 0;
687
688 SlapReply *candidates;
689
690 if ( be_isroot( op ) ) {
691 isroot = 1;
692 }
693
694 if ( LogTest( LDAP_DEBUG_TRACE ) ) {
695 char buf[STRLENOF("4294967295U") + 1] = { 0 };
696 mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
697
698 Debug( LDAP_DEBUG_TRACE,
699 "%s meta_back_dobind: conn=%s%s\n",
700 op->o_log_prefix, buf,
701 isroot ? " (isroot)" : "" );
702 }
703
704 /*
705 * all the targets are bound as pseudoroot
706 */
707 if ( mc->mc_authz_target == META_BOUND_ALL ) {
708 bound = 1;
709 goto done;
710 }
711
712 candidates = meta_back_candidates_get( op );
713
714 for ( i = 0; i < mi->mi_ntargets; i++ ) {
715 metatarget_t *mt = mi->mi_targets[ i ];
716 metasingleconn_t *msc = &mc->mc_conns[ i ];
717 int rc;
718
719 /*
720 * Not a candidate
721 */
722 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
723 continue;
724 }
725
726 assert( msc->msc_ld != NULL );
727
728 /*
729 * If the target is already bound it is skipped
730 */
731
732 retry_binding:;
733 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
734 if ( LDAP_BACK_CONN_ISBOUND( msc )
735 || ( LDAP_BACK_CONN_ISANON( msc )
736 && mt->mt_idassert_authmethod == LDAP_AUTH_NONE ) )
737 {
738 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
739 ++bound;
740 continue;
741
742 } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) )
743 {
744 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
745 ldap_pvt_thread_yield();
746 goto retry_binding;
747
748 }
749
750 LDAP_BACK_CONN_BINDING_SET( msc );
751 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
752
753 rc = meta_back_single_dobind( op, rs, &mc, i,
754 LDAP_BACK_DONTSEND, mt->mt_nretries, 1 );
755 /*
756 * NOTE: meta_back_single_dobind() already retries;
757 * in case of failure, it resets mc...
758 */
759 if ( rc != LDAP_SUCCESS ) {
760 if ( mc == NULL ) {
761 /* meta_back_single_dobind() already sent
762 * response and released connection */
763 goto send_err;
764 }
765
766 if ( rc == LDAP_UNAVAILABLE ) {
767 /* FIXME: meta_back_retry() already re-calls
768 * meta_back_single_dobind() */
769 if ( meta_back_retry( op, rs, &mc, i, sendok ) ) {
770 goto retry_ok;
771 }
772
773 if ( mc != NULL ) {
774 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
775 LDAP_BACK_CONN_BINDING_CLEAR( msc );
776 meta_back_release_conn_lock( mi, mc, 0 );
777 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
778 }
779
780 return 0;
781 }
782
783 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
784 LDAP_BACK_CONN_BINDING_CLEAR( msc );
785 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
786
787 Debug(LDAP_DEBUG_ANY,
788 "%s meta_back_dobind[%d]: (%s) err=%d (%s).\n",
789 op->o_log_prefix, i,
790 isroot ? op->o_bd->be_rootdn.bv_val : "anonymous",
791 rc, ldap_err2string(rc) );
792
793 /*
794 * null cred bind should always succeed
795 * as anonymous, so a failure means
796 * the target is no longer candidate possibly
797 * due to technical reasons (remote host down?)
798 * so better clear the handle
799 */
800 /* leave the target candidate, but record the error for later use */
801 candidates[ i ].sr_err = rc;
802 if ( META_BACK_ONERR_STOP( mi ) ) {
803 bound = 0;
804 goto done;
805 }
806
807 continue;
808 } /* else */
809
810 retry_ok:;
811 Debug( LDAP_DEBUG_TRACE,
812 "%s meta_back_dobind[%d]: "
813 "(%s)\n",
814 op->o_log_prefix, i,
815 isroot ? op->o_bd->be_rootdn.bv_val : "anonymous" );
816
817 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
818 LDAP_BACK_CONN_BINDING_CLEAR( msc );
819 if ( isroot ) {
820 LDAP_BACK_CONN_ISBOUND_SET( msc );
821 } else {
822 LDAP_BACK_CONN_ISANON_SET( msc );
823 }
824 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
825 ++bound;
826 }
827
828 done:;
829 if ( LogTest( LDAP_DEBUG_TRACE ) ) {
830 char buf[STRLENOF("4294967295U") + 1] = { 0 };
831 mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
832
833 Debug( LDAP_DEBUG_TRACE,
834 "%s meta_back_dobind: conn=%s bound=%d\n",
835 op->o_log_prefix, buf, bound );
836 }
837
838 if ( bound == 0 ) {
839 meta_back_release_conn( mi, mc );
840
841 send_err:;
842 if ( sendok & LDAP_BACK_SENDERR ) {
843 if ( rs->sr_err == LDAP_SUCCESS ) {
844 rs->sr_err = LDAP_BUSY;
845 }
846 send_ldap_result( op, rs );
847 }
848
849 return 0;
850 }
851
852 return ( bound > 0 );
853 }
854
855 /*
856 * meta_back_default_rebind
857 *
858 * This is a callback used for chasing referrals using the same
859 * credentials as the original user on this session.
860 */
861 int
meta_back_default_rebind(LDAP * ld,LDAP_CONST char * url,ber_tag_t request,ber_int_t msgid,void * params)862 meta_back_default_rebind(
863 LDAP *ld,
864 LDAP_CONST char *url,
865 ber_tag_t request,
866 ber_int_t msgid,
867 void *params )
868 {
869 metasingleconn_t *msc = ( metasingleconn_t * )params;
870
871 return ldap_sasl_bind_s( ld, msc->msc_bound_ndn.bv_val,
872 LDAP_SASL_SIMPLE, &msc->msc_cred,
873 NULL, NULL, NULL );
874 }
875
876 /*
877 * meta_back_default_urllist
878 *
879 * This is a callback used for mucking with the urllist
880 */
881 int
meta_back_default_urllist(LDAP * ld,LDAPURLDesc ** urllist,LDAPURLDesc ** url,void * params)882 meta_back_default_urllist(
883 LDAP *ld,
884 LDAPURLDesc **urllist,
885 LDAPURLDesc **url,
886 void *params )
887 {
888 metatarget_t *mt = (metatarget_t *)params;
889 LDAPURLDesc **urltail;
890
891 if ( urllist == url ) {
892 return LDAP_SUCCESS;
893 }
894
895 for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
896 /* count */ ;
897
898 *urltail = *urllist;
899 *urllist = *url;
900 *url = NULL;
901
902 ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
903 if ( mt->mt_uri ) {
904 ch_free( mt->mt_uri );
905 }
906
907 ldap_get_option( ld, LDAP_OPT_URI, (void *)&mt->mt_uri );
908 ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
909
910 return LDAP_SUCCESS;
911 }
912
913 int
meta_back_cancel(metaconn_t * mc,Operation * op,SlapReply * rs,ber_int_t msgid,int candidate,ldap_back_send_t sendok)914 meta_back_cancel(
915 metaconn_t *mc,
916 Operation *op,
917 SlapReply *rs,
918 ber_int_t msgid,
919 int candidate,
920 ldap_back_send_t sendok )
921 {
922 metainfo_t *mi = (metainfo_t *)op->o_bd->be_private;
923
924 metatarget_t *mt = mi->mi_targets[ candidate ];
925 metasingleconn_t *msc = &mc->mc_conns[ candidate ];
926
927 int rc = LDAP_OTHER;
928
929 Debug( LDAP_DEBUG_TRACE, ">>> %s meta_back_cancel[%d] msgid=%d\n",
930 op->o_log_prefix, candidate, msgid );
931
932 /* default behavior */
933 if ( META_BACK_TGT_ABANDON( mt ) ) {
934 rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
935
936 } else if ( META_BACK_TGT_IGNORE( mt ) ) {
937 rc = ldap_pvt_discard( msc->msc_ld, msgid );
938
939 } else if ( META_BACK_TGT_CANCEL( mt ) ) {
940 rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL );
941
942 } else {
943 assert( 0 );
944 }
945
946 Debug( LDAP_DEBUG_TRACE, "<<< %s meta_back_cancel[%d] err=%d\n",
947 op->o_log_prefix, candidate, rc );
948
949 return rc;
950 }
951
952
953
954 /*
955 * FIXME: error return must be handled in a cleaner way ...
956 */
957 int
meta_back_op_result(metaconn_t * mc,Operation * op,SlapReply * rs,int candidate,ber_int_t msgid,time_t timeout,ldap_back_send_t sendok)958 meta_back_op_result(
959 metaconn_t *mc,
960 Operation *op,
961 SlapReply *rs,
962 int candidate,
963 ber_int_t msgid,
964 time_t timeout,
965 ldap_back_send_t sendok )
966 {
967 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
968
969 const char *save_text = rs->sr_text,
970 *save_matched = rs->sr_matched;
971 BerVarray save_ref = rs->sr_ref;
972 LDAPControl **save_ctrls = rs->sr_ctrls;
973 void *matched_ctx = NULL;
974
975 char *matched = NULL;
976 char *text = NULL;
977 char **refs = NULL;
978 LDAPControl **ctrls = NULL;
979
980 assert( mc != NULL );
981
982 rs->sr_text = NULL;
983 rs->sr_matched = NULL;
984 rs->sr_ref = NULL;
985 rs->sr_ctrls = NULL;
986
987 if ( candidate != META_TARGET_NONE ) {
988 metatarget_t *mt = mi->mi_targets[ candidate ];
989 metasingleconn_t *msc = &mc->mc_conns[ candidate ];
990
991 if ( LDAP_ERR_OK( rs->sr_err ) ) {
992 int rc;
993 struct timeval tv;
994 LDAPMessage *res = NULL;
995 time_t stoptime = (time_t)(-1);
996 int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
997 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
998 const char *timeout_text = "Operation timed out";
999
1000 /* if timeout is not specified, compute and use
1001 * the one specific to the ongoing operation */
1002 if ( timeout == (time_t)(-1) ) {
1003 slap_op_t opidx = slap_req2op( op->o_tag );
1004
1005 if ( opidx == SLAP_OP_SEARCH ) {
1006 if ( op->ors_tlimit <= 0 ) {
1007 timeout = 0;
1008
1009 } else {
1010 timeout = op->ors_tlimit;
1011 timeout_err = LDAP_TIMELIMIT_EXCEEDED;
1012 timeout_text = NULL;
1013 }
1014
1015 } else {
1016 timeout = mt->mt_timeout[ opidx ];
1017 }
1018 }
1019
1020 /* better than nothing :) */
1021 if ( timeout == 0 ) {
1022 if ( mi->mi_idle_timeout ) {
1023 timeout = mi->mi_idle_timeout;
1024
1025 } else if ( mi->mi_conn_ttl ) {
1026 timeout = mi->mi_conn_ttl;
1027 }
1028 }
1029
1030 if ( timeout ) {
1031 stoptime = op->o_time + timeout;
1032 }
1033
1034 LDAP_BACK_TV_SET( &tv );
1035
1036 retry:;
1037 rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
1038 switch ( rc ) {
1039 case 0:
1040 if ( timeout && slap_get_time() > stoptime ) {
1041 (void)meta_back_cancel( mc, op, rs, msgid, candidate, sendok );
1042 rs->sr_err = timeout_err;
1043 rs->sr_text = timeout_text;
1044 break;
1045 }
1046
1047 LDAP_BACK_TV_SET( &tv );
1048 ldap_pvt_thread_yield();
1049 goto retry;
1050
1051 case -1:
1052 ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,
1053 &rs->sr_err );
1054 break;
1055
1056
1057 /* otherwise get the result; if it is not
1058 * LDAP_SUCCESS, record it in the reply
1059 * structure (this includes
1060 * LDAP_COMPARE_{TRUE|FALSE}) */
1061 default:
1062 /* only touch when activity actually took place... */
1063 if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
1064 msc->msc_time = op->o_time;
1065 }
1066
1067 rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
1068 &matched, &text, &refs, &ctrls, 1 );
1069 res = NULL;
1070 if ( rc == LDAP_SUCCESS ) {
1071 rs->sr_text = text;
1072 } else {
1073 rs->sr_err = rc;
1074 }
1075 rs->sr_err = slap_map_api2result( rs );
1076
1077 /* RFC 4511: referrals can only appear
1078 * if result code is LDAP_REFERRAL */
1079 if ( refs != NULL
1080 && refs[ 0 ] != NULL
1081 && refs[ 0 ][ 0 ] != '\0' )
1082 {
1083 if ( rs->sr_err != LDAP_REFERRAL ) {
1084 Debug( LDAP_DEBUG_ANY,
1085 "%s meta_back_op_result[%d]: "
1086 "got referrals with err=%d\n",
1087 op->o_log_prefix,
1088 candidate, rs->sr_err );
1089
1090 } else {
1091 int i;
1092
1093 for ( i = 0; refs[ i ] != NULL; i++ )
1094 /* count */ ;
1095 rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
1096 op->o_tmpmemctx );
1097 for ( i = 0; refs[ i ] != NULL; i++ ) {
1098 ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
1099 }
1100 BER_BVZERO( &rs->sr_ref[ i ] );
1101 }
1102
1103 } else if ( rs->sr_err == LDAP_REFERRAL ) {
1104 Debug( LDAP_DEBUG_ANY,
1105 "%s meta_back_op_result[%d]: "
1106 "got err=%d with null "
1107 "or empty referrals\n",
1108 op->o_log_prefix,
1109 candidate, rs->sr_err );
1110
1111 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1112 }
1113
1114 if ( ctrls != NULL ) {
1115 rs->sr_ctrls = ctrls;
1116 }
1117 }
1118
1119 assert( res == NULL );
1120 }
1121
1122 /* if the error in the reply structure is not
1123 * LDAP_SUCCESS, try to map it from client
1124 * to server error */
1125 if ( !LDAP_ERR_OK( rs->sr_err ) ) {
1126 rs->sr_err = slap_map_api2result( rs );
1127
1128 /* internal ops ( op->o_conn == NULL )
1129 * must not reply to client */
1130 if ( op->o_conn && !op->o_do_not_cache && matched ) {
1131
1132 /* record the (massaged) matched
1133 * DN into the reply structure */
1134 rs->sr_matched = matched;
1135 }
1136 }
1137
1138 if ( META_BACK_TGT_QUARANTINE( mt ) ) {
1139 meta_back_quarantine( op, rs, candidate );
1140 }
1141
1142 } else {
1143 int i,
1144 err = rs->sr_err;
1145
1146 for ( i = 0; i < mi->mi_ntargets; i++ ) {
1147 metasingleconn_t *msc = &mc->mc_conns[ i ];
1148 char *xtext = NULL;
1149 char *xmatched = NULL;
1150
1151 if ( msc->msc_ld == NULL ) {
1152 continue;
1153 }
1154
1155 rs->sr_err = LDAP_SUCCESS;
1156
1157 ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err );
1158 if ( rs->sr_err != LDAP_SUCCESS ) {
1159 /*
1160 * better check the type of error. In some cases
1161 * (search ?) it might be better to return a
1162 * success if at least one of the targets gave
1163 * positive result ...
1164 */
1165 ldap_get_option( msc->msc_ld,
1166 LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext );
1167 if ( xtext != NULL && xtext [ 0 ] == '\0' ) {
1168 ldap_memfree( xtext );
1169 xtext = NULL;
1170 }
1171
1172 ldap_get_option( msc->msc_ld,
1173 LDAP_OPT_MATCHED_DN, &xmatched );
1174 if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) {
1175 ldap_memfree( xmatched );
1176 xmatched = NULL;
1177 }
1178
1179 rs->sr_err = slap_map_api2result( rs );
1180
1181 Debug(LDAP_DEBUG_ANY,
1182 "%s meta_back_op_result[%d] " "err=%d text=\"%s\" matched=\"%s\".\n",
1183 op->o_log_prefix, i, rs->sr_err,
1184 (xtext ? xtext : ""),
1185 (xmatched ? xmatched : "") );
1186
1187 /*
1188 * FIXME: need to rewrite "match" (need rwinfo)
1189 */
1190 switch ( rs->sr_err ) {
1191 default:
1192 err = rs->sr_err;
1193 if ( xtext != NULL ) {
1194 if ( text ) {
1195 ldap_memfree( text );
1196 }
1197 text = xtext;
1198 xtext = NULL;
1199 }
1200 if ( xmatched != NULL ) {
1201 if ( matched ) {
1202 ldap_memfree( matched );
1203 }
1204 matched = xmatched;
1205 xmatched = NULL;
1206 }
1207 break;
1208 }
1209
1210 if ( xtext ) {
1211 ldap_memfree( xtext );
1212 }
1213
1214 if ( xmatched ) {
1215 ldap_memfree( xmatched );
1216 }
1217 }
1218
1219 if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
1220 meta_back_quarantine( op, rs, i );
1221 }
1222 }
1223
1224 if ( err != LDAP_SUCCESS ) {
1225 rs->sr_err = err;
1226 }
1227 }
1228
1229 if ( matched != NULL ) {
1230 struct berval dn, pdn;
1231
1232 ber_str2bv( matched, 0, 0, &dn );
1233 if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
1234 ldap_memfree( matched );
1235 matched_ctx = op->o_tmpmemctx;
1236 matched = pdn.bv_val;
1237 }
1238 rs->sr_matched = matched;
1239 }
1240
1241 if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1242 if ( !( sendok & LDAP_BACK_RETRYING ) ) {
1243 if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
1244 if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
1245 send_ldap_result( op, rs );
1246 }
1247 }
1248
1249 } else if ( op->o_conn &&
1250 ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
1251 || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
1252 {
1253 send_ldap_result( op, rs );
1254 }
1255 if ( matched ) {
1256 op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
1257 }
1258 if ( text ) {
1259 ldap_memfree( text );
1260 }
1261 if ( rs->sr_ref ) {
1262 op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
1263 rs->sr_ref = NULL;
1264 }
1265 if ( refs ) {
1266 ber_memvfree( (void **)refs );
1267 }
1268 if ( ctrls ) {
1269 assert( rs->sr_ctrls != NULL );
1270 ldap_controls_free( ctrls );
1271 }
1272
1273 rs->sr_text = save_text;
1274 rs->sr_matched = save_matched;
1275 rs->sr_ref = save_ref;
1276 rs->sr_ctrls = save_ctrls;
1277
1278 return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
1279 }
1280
1281 /*
1282 * meta_back_proxy_authz_cred()
1283 *
1284 * prepares credentials & method for meta_back_proxy_authz_bind();
1285 * or, if method is SASL, performs the SASL bind directly.
1286 */
1287 int
meta_back_proxy_authz_cred(metaconn_t * mc,int candidate,Operation * op,SlapReply * rs,ldap_back_send_t sendok,struct berval * binddn,struct berval * bindcred,int * method)1288 meta_back_proxy_authz_cred(
1289 metaconn_t *mc,
1290 int candidate,
1291 Operation *op,
1292 SlapReply *rs,
1293 ldap_back_send_t sendok,
1294 struct berval *binddn,
1295 struct berval *bindcred,
1296 int *method )
1297 {
1298 metainfo_t *mi = (metainfo_t *)op->o_bd->be_private;
1299 metatarget_t *mt = mi->mi_targets[ candidate ];
1300 metasingleconn_t *msc = &mc->mc_conns[ candidate ];
1301 struct berval ndn;
1302 int dobind = 0;
1303
1304 /* don't proxyAuthz if protocol is not LDAPv3 */
1305 switch ( mt->mt_version ) {
1306 case LDAP_VERSION3:
1307 break;
1308
1309 case 0:
1310 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
1311 break;
1312 }
1313 /* fall thru */
1314
1315 default:
1316 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1317 if ( sendok & LDAP_BACK_SENDERR ) {
1318 send_ldap_result( op, rs );
1319 }
1320 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1321 goto done;
1322 }
1323
1324 if ( op->o_tag == LDAP_REQ_BIND ) {
1325 ndn = op->o_req_ndn;
1326
1327 } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
1328 ndn = op->o_conn->c_ndn;
1329
1330 } else {
1331 ndn = op->o_ndn;
1332 }
1333 rs->sr_err = LDAP_SUCCESS;
1334
1335 /*
1336 * FIXME: we need to let clients use proxyAuthz
1337 * otherwise we cannot do symmetric pools of servers;
1338 * we have to live with the fact that a user can
1339 * authorize itself as any ID that is allowed
1340 * by the authzTo directive of the "proxyauthzdn".
1341 */
1342 /*
1343 * NOTE: current Proxy Authorization specification
1344 * and implementation do not allow proxy authorization
1345 * control to be provided with Bind requests
1346 */
1347 /*
1348 * if no bind took place yet, but the connection is bound
1349 * and the "proxyauthzdn" is set, then bind as
1350 * "proxyauthzdn" and explicitly add the proxyAuthz
1351 * control to every operation with the dn bound
1352 * to the connection as control value.
1353 */
1354
1355 /* bind as proxyauthzdn only if no idassert mode
1356 * is requested, or if the client's identity
1357 * is authorized */
1358 switch ( mt->mt_idassert_mode ) {
1359 case LDAP_BACK_IDASSERT_LEGACY:
1360 if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
1361 if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) && !BER_BVISEMPTY( &mt->mt_idassert_authcDN ) )
1362 {
1363 *binddn = mt->mt_idassert_authcDN;
1364 *bindcred = mt->mt_idassert_passwd;
1365 dobind = 1;
1366 }
1367 }
1368 break;
1369
1370 default:
1371 /* NOTE: rootdn can always idassert */
1372 if ( BER_BVISNULL( &ndn )
1373 && mt->mt_idassert_authz == NULL
1374 && !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
1375 {
1376 if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1377 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1378 if ( sendok & LDAP_BACK_SENDERR ) {
1379 send_ldap_result( op, rs );
1380 }
1381 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1382 goto done;
1383
1384 }
1385
1386 rs->sr_err = LDAP_SUCCESS;
1387 *binddn = slap_empty_bv;
1388 *bindcred = slap_empty_bv;
1389 break;
1390
1391 } else if ( mt->mt_idassert_authz && !be_isroot( op ) ) {
1392 struct berval authcDN;
1393
1394 if ( BER_BVISNULL( &ndn ) ) {
1395 authcDN = slap_empty_bv;
1396
1397 } else {
1398 authcDN = ndn;
1399 }
1400 rs->sr_err = slap_sasl_matches( op, mt->mt_idassert_authz,
1401 &authcDN, &authcDN );
1402 if ( rs->sr_err != LDAP_SUCCESS ) {
1403 if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1404 if ( sendok & LDAP_BACK_SENDERR ) {
1405 send_ldap_result( op, rs );
1406 }
1407 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1408 goto done;
1409 }
1410
1411 rs->sr_err = LDAP_SUCCESS;
1412 *binddn = slap_empty_bv;
1413 *bindcred = slap_empty_bv;
1414 break;
1415 }
1416 }
1417
1418 *binddn = mt->mt_idassert_authcDN;
1419 *bindcred = mt->mt_idassert_passwd;
1420 dobind = 1;
1421 break;
1422 }
1423
1424 if ( dobind && mt->mt_idassert_authmethod == LDAP_AUTH_SASL ) {
1425 #ifdef HAVE_CYRUS_SASL
1426 void *defaults = NULL;
1427 struct berval authzID = BER_BVNULL;
1428 int freeauthz = 0;
1429
1430 /* if SASL supports native authz, prepare for it */
1431 if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
1432 ( mt->mt_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
1433 {
1434 switch ( mt->mt_idassert_mode ) {
1435 case LDAP_BACK_IDASSERT_OTHERID:
1436 case LDAP_BACK_IDASSERT_OTHERDN:
1437 authzID = mt->mt_idassert_authzID;
1438 break;
1439
1440 case LDAP_BACK_IDASSERT_ANONYMOUS:
1441 BER_BVSTR( &authzID, "dn:" );
1442 break;
1443
1444 case LDAP_BACK_IDASSERT_SELF:
1445 if ( BER_BVISNULL( &ndn ) ) {
1446 /* connection is not authc'd, so don't idassert */
1447 BER_BVSTR( &authzID, "dn:" );
1448 break;
1449 }
1450 authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
1451 authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
1452 AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
1453 AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
1454 ndn.bv_val, ndn.bv_len + 1 );
1455 freeauthz = 1;
1456 break;
1457
1458 default:
1459 break;
1460 }
1461 }
1462
1463 if ( mt->mt_idassert_secprops != NULL ) {
1464 rs->sr_err = ldap_set_option( msc->msc_ld,
1465 LDAP_OPT_X_SASL_SECPROPS,
1466 (void *)mt->mt_idassert_secprops );
1467
1468 if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
1469 rs->sr_err = LDAP_OTHER;
1470 if ( sendok & LDAP_BACK_SENDERR ) {
1471 send_ldap_result( op, rs );
1472 }
1473 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1474 goto done;
1475 }
1476 }
1477
1478 defaults = lutil_sasl_defaults( msc->msc_ld,
1479 mt->mt_idassert_sasl_mech.bv_val,
1480 mt->mt_idassert_sasl_realm.bv_val,
1481 mt->mt_idassert_authcID.bv_val,
1482 mt->mt_idassert_passwd.bv_val,
1483 authzID.bv_val );
1484 if ( defaults == NULL ) {
1485 rs->sr_err = LDAP_OTHER;
1486 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1487 if ( sendok & LDAP_BACK_SENDERR ) {
1488 send_ldap_result( op, rs );
1489 }
1490 goto done;
1491 }
1492
1493 rs->sr_err = ldap_sasl_interactive_bind_s( msc->msc_ld, binddn->bv_val,
1494 mt->mt_idassert_sasl_mech.bv_val, NULL, NULL,
1495 LDAP_SASL_QUIET, lutil_sasl_interact,
1496 defaults );
1497
1498 rs->sr_err = slap_map_api2result( rs );
1499 if ( rs->sr_err != LDAP_SUCCESS ) {
1500 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1501 if ( sendok & LDAP_BACK_SENDERR ) {
1502 send_ldap_result( op, rs );
1503 }
1504
1505 } else {
1506 LDAP_BACK_CONN_ISBOUND_SET( msc );
1507 }
1508
1509 lutil_sasl_freedefs( defaults );
1510 if ( freeauthz ) {
1511 slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
1512 }
1513
1514 goto done;
1515 #endif /* HAVE_CYRUS_SASL */
1516 }
1517
1518 *method = mt->mt_idassert_authmethod;
1519 switch ( mt->mt_idassert_authmethod ) {
1520 case LDAP_AUTH_NONE:
1521 BER_BVSTR( binddn, "" );
1522 BER_BVSTR( bindcred, "" );
1523 /* fallthru */
1524
1525 case LDAP_AUTH_SIMPLE:
1526 break;
1527
1528 default:
1529 /* unsupported! */
1530 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1531 rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
1532 if ( sendok & LDAP_BACK_SENDERR ) {
1533 send_ldap_result( op, rs );
1534 }
1535 break;
1536 }
1537
1538 done:;
1539
1540 if ( !BER_BVISEMPTY( binddn ) ) {
1541 LDAP_BACK_CONN_ISIDASSERT_SET( msc );
1542 }
1543
1544 return rs->sr_err;
1545 }
1546
1547 static int
meta_back_proxy_authz_bind(metaconn_t * mc,int candidate,Operation * op,SlapReply * rs,ldap_back_send_t sendok,int dolock)1548 meta_back_proxy_authz_bind(
1549 metaconn_t *mc,
1550 int candidate,
1551 Operation *op,
1552 SlapReply *rs,
1553 ldap_back_send_t sendok,
1554 int dolock )
1555 {
1556 metainfo_t *mi = (metainfo_t *)op->o_bd->be_private;
1557 metatarget_t *mt = mi->mi_targets[ candidate ];
1558 metasingleconn_t *msc = &mc->mc_conns[ candidate ];
1559 struct berval binddn = BER_BVC( "" ),
1560 cred = BER_BVC( "" );
1561 int method = LDAP_AUTH_NONE,
1562 rc;
1563
1564 rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, sendok, &binddn, &cred, &method );
1565 if ( rc == LDAP_SUCCESS && !LDAP_BACK_CONN_ISBOUND( msc ) ) {
1566 int msgid;
1567
1568 switch ( method ) {
1569 case LDAP_AUTH_NONE:
1570 case LDAP_AUTH_SIMPLE:
1571
1572 if(!dolock) {
1573 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1574 }
1575
1576 for (;;) {
1577 rs->sr_err = ldap_sasl_bind( msc->msc_ld,
1578 binddn.bv_val, LDAP_SASL_SIMPLE,
1579 &cred, NULL, NULL, &msgid );
1580 if ( rs->sr_err != LDAP_X_CONNECTING ) {
1581 break;
1582 }
1583 ldap_pvt_thread_yield();
1584 }
1585
1586 if(!dolock) {
1587 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1588 }
1589
1590 rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
1591 if ( rc == LDAP_SUCCESS ) {
1592 /* set rebind stuff in case of successful proxyAuthz bind,
1593 * so that referral chasing is attempted using the right
1594 * identity */
1595 LDAP_BACK_CONN_ISBOUND_SET( msc );
1596 ber_bvreplace( &msc->msc_bound_ndn, &binddn );
1597
1598 if ( META_BACK_TGT_SAVECRED( mt ) ) {
1599 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
1600 memset( msc->msc_cred.bv_val, 0,
1601 msc->msc_cred.bv_len );
1602 }
1603 ber_bvreplace( &msc->msc_cred, &cred );
1604 ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
1605 }
1606 }
1607 break;
1608
1609 default:
1610 assert( 0 );
1611 break;
1612 }
1613 }
1614
1615 return LDAP_BACK_CONN_ISBOUND( msc );
1616 }
1617
1618 /*
1619 * Add controls;
1620 *
1621 * if any needs to be added, it is prepended to existing ones,
1622 * in a newly allocated array. The companion function
1623 * mi->mi_ldap_extra->controls_free() must be used to restore the original
1624 * status of op->o_ctrls.
1625 */
1626 int
meta_back_controls_add(Operation * op,SlapReply * rs,metaconn_t * mc,int candidate,LDAPControl *** pctrls)1627 meta_back_controls_add(
1628 Operation *op,
1629 SlapReply *rs,
1630 metaconn_t *mc,
1631 int candidate,
1632 LDAPControl ***pctrls )
1633 {
1634 metainfo_t *mi = (metainfo_t *)op->o_bd->be_private;
1635 metatarget_t *mt = mi->mi_targets[ candidate ];
1636 metasingleconn_t *msc = &mc->mc_conns[ candidate ];
1637
1638 LDAPControl **ctrls = NULL;
1639 /* set to the maximum number of controls this backend can add */
1640 LDAPControl c[ 2 ] = {{ 0 }};
1641 int n = 0, i, j1 = 0, j2 = 0, skipped = 0;
1642
1643 *pctrls = NULL;
1644
1645 rs->sr_err = LDAP_SUCCESS;
1646
1647 /* don't add controls if protocol is not LDAPv3 */
1648 switch ( mt->mt_version ) {
1649 case LDAP_VERSION3:
1650 break;
1651
1652 case 0:
1653 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
1654 break;
1655 }
1656 /* fall thru */
1657
1658 default:
1659 goto done;
1660 }
1661
1662 /* put controls that go __before__ existing ones here */
1663
1664 /* proxyAuthz for identity assertion */
1665 switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn,
1666 mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) )
1667 {
1668 case SLAP_CB_CONTINUE:
1669 break;
1670
1671 case LDAP_SUCCESS:
1672 j1++;
1673 break;
1674
1675 default:
1676 goto done;
1677 }
1678
1679 /* put controls that go __after__ existing ones here */
1680
1681 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1682 /* session tracking */
1683 if ( META_BACK_TGT_ST_REQUEST( mt ) ) {
1684 switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) {
1685 case SLAP_CB_CONTINUE:
1686 break;
1687
1688 case LDAP_SUCCESS:
1689 j2++;
1690 break;
1691
1692 default:
1693 goto done;
1694 }
1695 }
1696 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1697
1698 if ( rs->sr_err == SLAP_CB_CONTINUE ) {
1699 rs->sr_err = LDAP_SUCCESS;
1700 }
1701
1702 /* if nothing to do, just bail out */
1703 if ( j1 == 0 && j2 == 0 ) {
1704 goto done;
1705 }
1706
1707 assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) );
1708
1709 if ( op->o_ctrls ) {
1710 for ( n = 0; op->o_ctrls[ n ]; n++ )
1711 /* just count ctrls */ ;
1712 }
1713
1714 ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ),
1715 op->o_tmpmemctx );
1716 if ( j1 ) {
1717 ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
1718 *ctrls[ 0 ] = c[ 0 ];
1719 for ( i = 1; i < j1; i++ ) {
1720 ctrls[ i ] = &ctrls[ 0 ][ i ];
1721 *ctrls[ i ] = c[ i ];
1722 }
1723 }
1724
1725 i = 0;
1726 if ( op->o_ctrls ) {
1727 LDAPControl *proxyauthz = ldap_control_find(
1728 LDAP_CONTROL_PROXY_AUTHZ, op->o_ctrls, NULL );
1729
1730 for ( i = 0; op->o_ctrls[ i ]; i++ ) {
1731 /* Only replace it if we generated one */
1732 if ( j1 && proxyauthz && proxyauthz == op->o_ctrls[ i ] ) {
1733 /* Frontend has already checked only one is present */
1734 assert( skipped == 0 );
1735 skipped++;
1736 continue;
1737 }
1738 ctrls[ i + j1 - skipped ] = op->o_ctrls[ i ];
1739 }
1740 }
1741
1742 n += j1 - skipped;
1743 if ( j2 ) {
1744 ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1;
1745 *ctrls[ n ] = c[ j1 ];
1746 for ( i = 1; i < j2; i++ ) {
1747 ctrls[ n + i ] = &ctrls[ n ][ i ];
1748 *ctrls[ n + i ] = c[ i ];
1749 }
1750 }
1751
1752 ctrls[ n + j2 ] = NULL;
1753
1754 done:;
1755 if ( ctrls == NULL ) {
1756 ctrls = op->o_ctrls;
1757 }
1758
1759 *pctrls = ctrls;
1760
1761 return rs->sr_err;
1762 }
1763
1764