1 /* bind.c - ldap backend bind function */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/bind.c,v 1.162.2.17 2008/04/14 20:02:21 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1999-2008 The OpenLDAP Foundation.
6 * Portions Copyright 2000-2003 Pierangelo Masarati.
7 * Portions Copyright 1999-2003 Howard Chu.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
19 * This work was initially developed by Howard Chu for inclusion
20 * in OpenLDAP Software and subsequently enhanced by Pierangelo
29 #include <ac/socket.h>
30 #include <ac/string.h>
34 #include "back-ldap.h"
35 #undef ldap_debug /* silence a warning in ldap-int.h */
36 #include "../../../libraries/libldap/ldap-int.h"
38 #include "lutil_ldap.h"
40 #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ "2.16.840.1.113730.3.4.12"
42 #if LDAP_BACK_PRINT_CONNTREE > 0
44 ldap_back_ravl_print( Avlnode
*root
, int depth
)
53 ldap_back_ravl_print( root
->avl_right
, depth
+1 );
55 for ( i
= 0; i
< depth
; i
++ ) {
56 fprintf( stderr
, "-" );
60 fprintf( stderr
, "lc=%p local=\"%s\" conn=%p %s refcnt=%d flags=0x%08x\n",
62 lc
->lc_local_ndn
.bv_val
? lc
->lc_local_ndn
.bv_val
: "",
64 avl_bf2str( root
->avl_bf
), lc
->lc_refcnt
, lc
->lc_lcflags
);
66 ldap_back_ravl_print( root
->avl_left
, depth
+1 );
69 static char* priv2str
[] = {
80 ldap_back_print_conntree( ldapinfo_t
*li
, char *msg
)
84 fprintf( stderr
, "========> %s\n", msg
);
86 for ( c
= LDAP_BACK_PCONN_FIRST
; c
< LDAP_BACK_PCONN_LAST
; c
++ ) {
90 fprintf( stderr
, " %s[%d]\n", priv2str
[ c
], li
->li_conn_priv
[ c
].lic_num
);
92 LDAP_TAILQ_FOREACH( lc
, &li
->li_conn_priv
[ c
].lic_priv
, lc_q
)
94 fprintf( stderr
, " [%d] lc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",
97 lc
->lc_local_ndn
.bv_val
? lc
->lc_local_ndn
.bv_val
: "",
98 (void *)lc
->lc_conn
, lc
->lc_refcnt
, lc
->lc_lcflags
);
103 if ( li
->li_conninfo
.lai_tree
== 0 ) {
104 fprintf( stderr
, "\t(empty)\n" );
107 ldap_back_ravl_print( li
->li_conninfo
.lai_tree
, 0 );
110 fprintf( stderr
, "<======== %s\n", msg
);
112 #endif /* LDAP_BACK_PRINT_CONNTREE */
115 ldap_back_freeconn( ldapinfo_t
*li
, ldapconn_t
*lc
, int dolock
);
118 ldap_back_getconn( Operation
*op
, SlapReply
*rs
, ldap_back_send_t sendok
,
119 struct berval
*binddn
, struct berval
*bindcred
);
122 ldap_back_is_proxy_authz( Operation
*op
, SlapReply
*rs
, ldap_back_send_t sendok
,
123 struct berval
*binddn
, struct berval
*bindcred
);
126 ldap_back_proxy_authz_bind( ldapconn_t
*lc
, Operation
*op
, SlapReply
*rs
,
127 ldap_back_send_t sendok
, struct berval
*binddn
, struct berval
*bindcred
);
130 ldap_back_prepare_conn( ldapconn_t
*lc
, Operation
*op
, SlapReply
*rs
,
131 ldap_back_send_t sendok
);
134 ldap_back_conndnlc_cmp( const void *c1
, const void *c2
);
137 ldap_back_conn_delete( ldapinfo_t
*li
, ldapconn_t
*lc
)
139 if ( LDAP_BACK_PCONN_ISPRIV( lc
) ) {
140 if ( LDAP_BACK_CONN_CACHED( lc
) ) {
141 assert( lc
->lc_q
.tqe_prev
!= NULL
);
142 assert( li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( lc
) ].lic_num
> 0 );
143 li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( lc
) ].lic_num
--;
144 LDAP_TAILQ_REMOVE( &li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( lc
) ].lic_priv
, lc
, lc_q
);
145 LDAP_TAILQ_ENTRY_INIT( lc
, lc_q
);
146 LDAP_BACK_CONN_CACHED_CLEAR( lc
);
149 assert( LDAP_BACK_CONN_TAINTED( lc
) );
150 assert( lc
->lc_q
.tqe_prev
== NULL
);
154 ldapconn_t
*tmplc
= NULL
;
156 if ( LDAP_BACK_CONN_CACHED( lc
) ) {
157 assert( !LDAP_BACK_CONN_TAINTED( lc
) );
158 tmplc
= avl_delete( &li
->li_conninfo
.lai_tree
, (caddr_t
)lc
,
159 ldap_back_conndnlc_cmp
);
160 assert( tmplc
== lc
);
161 LDAP_BACK_CONN_CACHED_CLEAR( lc
);
164 assert( LDAP_BACK_CONN_TAINTED( lc
) || tmplc
== lc
);
171 ldap_back_bind( Operation
*op
, SlapReply
*rs
)
173 ldapinfo_t
*li
= (ldapinfo_t
*) op
->o_bd
->be_private
;
176 LDAPControl
**ctrls
= NULL
;
177 struct berval save_o_dn
;
178 int save_o_do_not_cache
,
181 ldap_back_send_t retrying
= LDAP_BACK_RETRYING
;
183 /* allow rootdn as a means to auth without the need to actually
184 * contact the proxied DSA */
185 switch ( be_rootdn_bind( op
, rs
) ) {
186 case SLAP_CB_CONTINUE
:
193 lc
= ldap_back_getconn( op
, rs
, LDAP_BACK_BIND_SERR
, NULL
, NULL
);
198 /* we can do (almost) whatever we want with this conn,
199 * because either it's temporary, or it's marked as binding */
200 if ( !BER_BVISNULL( &lc
->lc_bound_ndn
) ) {
201 ch_free( lc
->lc_bound_ndn
.bv_val
);
202 BER_BVZERO( &lc
->lc_bound_ndn
);
204 if ( !BER_BVISNULL( &lc
->lc_cred
) ) {
205 memset( lc
->lc_cred
.bv_val
, 0, lc
->lc_cred
.bv_len
);
206 ch_free( lc
->lc_cred
.bv_val
);
207 BER_BVZERO( &lc
->lc_cred
);
209 LDAP_BACK_CONN_ISBOUND_CLEAR( lc
);
211 /* don't add proxyAuthz; set the bindDN */
212 save_o_dn
= op
->o_dn
;
213 save_o_do_not_cache
= op
->o_do_not_cache
;
214 op
->o_dn
= op
->o_req_dn
;
215 op
->o_do_not_cache
= 1;
218 rc
= ldap_back_controls_add( op
, rs
, lc
, &ctrls
);
219 op
->o_dn
= save_o_dn
;
220 op
->o_do_not_cache
= save_o_do_not_cache
;
221 if ( rc
!= LDAP_SUCCESS
) {
222 send_ldap_result( op
, rs
);
223 ldap_back_release_conn( li
, lc
);
228 /* method is always LDAP_AUTH_SIMPLE if we got here */
229 rs
->sr_err
= ldap_sasl_bind( lc
->lc_ld
, op
->o_req_dn
.bv_val
,
231 &op
->orb_cred
, ctrls
, NULL
, &msgid
);
232 /* FIXME: should we always retry, or only when piping the bind
233 * in the "override" connection pool? */
234 rc
= ldap_back_op_result( lc
, op
, rs
, msgid
,
235 li
->li_timeout
[ SLAP_OP_BIND
],
236 LDAP_BACK_BIND_SERR
| retrying
);
237 if ( rc
== LDAP_UNAVAILABLE
&& retrying
) {
238 retrying
&= ~LDAP_BACK_RETRYING
;
239 if ( ldap_back_retry( &lc
, op
, rs
, LDAP_BACK_BIND_SERR
) ) {
244 ldap_back_controls_free( op
, rs
, &ctrls
);
246 if ( rc
== LDAP_SUCCESS
) {
247 /* If defined, proxyAuthz will be used also when
248 * back-ldap is the authorizing backend; for this
249 * purpose, after a successful bind the connection
250 * is left for further binds, and further operations
251 * on this client connection will use a default
252 * connection with identity assertion */
253 /* NOTE: use with care */
254 if ( li
->li_idassert_flags
& LDAP_BACK_AUTH_OVERRIDE
) {
255 ldap_back_release_conn( li
, lc
);
259 /* rebind is now done inside ldap_back_proxy_authz_bind()
260 * in case of success */
261 LDAP_BACK_CONN_ISBOUND_SET( lc
);
262 ber_dupbv( &lc
->lc_bound_ndn
, &op
->o_req_ndn
);
264 if ( !BER_BVISNULL( &lc
->lc_cred
) ) {
265 memset( lc
->lc_cred
.bv_val
, 0,
266 lc
->lc_cred
.bv_len
);
269 if ( LDAP_BACK_SAVECRED( li
) ) {
270 ber_bvreplace( &lc
->lc_cred
, &op
->orb_cred
);
271 ldap_set_rebind_proc( lc
->lc_ld
, li
->li_rebind_f
, lc
);
274 lc
->lc_cred
.bv_len
= 0;
278 /* must re-insert if local DN changed as result of bind */
279 if ( !LDAP_BACK_CONN_ISBOUND( lc
)
280 || ( !dn_match( &op
->o_req_ndn
, &lc
->lc_local_ndn
)
281 && !LDAP_BACK_PCONN_ISPRIV( lc
) ) )
286 /* wait for all other ops to release the connection */
288 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
289 if ( lc
->lc_refcnt
> 1 ) {
290 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
291 ldap_pvt_thread_yield();
295 #if LDAP_BACK_PRINT_CONNTREE > 0
296 ldap_back_print_conntree( li
, ">>> ldap_back_bind" );
297 #endif /* LDAP_BACK_PRINT_CONNTREE */
299 assert( lc
->lc_refcnt
== 1 );
300 ldap_back_conn_delete( li
, lc
);
302 /* delete all cached connections with the current connection */
303 if ( LDAP_BACK_SINGLECONN( li
) ) {
304 while ( ( tmplc
= avl_delete( &li
->li_conninfo
.lai_tree
, (caddr_t
)lc
, ldap_back_conn_cmp
) ) != NULL
)
306 Debug( LDAP_DEBUG_TRACE
,
307 "=>ldap_back_bind: destroying conn %ld (refcnt=%u)\n",
308 LDAP_BACK_PCONN_ID( lc
), lc
->lc_refcnt
, 0 );
310 if ( tmplc
->lc_refcnt
!= 0 ) {
312 LDAP_BACK_CONN_TAINTED_SET( tmplc
);
313 LDAP_BACK_CONN_CACHED_CLEAR( tmplc
);
317 * Needs a test because the handler may be corrupted,
318 * and calling ldap_unbind on a corrupted header results
319 * in a segmentation fault
321 ldap_back_conn_free( tmplc
);
326 if ( LDAP_BACK_CONN_ISBOUND( lc
) ) {
327 ber_bvreplace( &lc
->lc_local_ndn
, &op
->o_req_ndn
);
328 if ( be_isroot_dn( op
->o_bd
, &op
->o_req_ndn
) ) {
329 LDAP_BACK_PCONN_ROOTDN_SET( lc
, op
);
331 lerr
= avl_insert( &li
->li_conninfo
.lai_tree
, (caddr_t
)lc
,
332 ldap_back_conndn_cmp
, ldap_back_conndn_dup
);
335 #if LDAP_BACK_PRINT_CONNTREE > 0
336 ldap_back_print_conntree( li
, "<<< ldap_back_bind" );
337 #endif /* LDAP_BACK_PRINT_CONNTREE */
339 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
342 LDAP_BACK_CONN_CACHED_SET( lc
);
346 /* duplicate; someone else successfully bound
347 * on the same connection with the same identity;
348 * we can do this because lc_refcnt == 1 */
349 ldap_back_conn_free( lc
);
355 ldap_back_release_conn( li
, lc
);
362 * ldap_back_conndn_cmp
364 * compares two ldapconn_t based on the value of the conn pointer
365 * and of the local DN; used by avl stuff for insert, lookup
369 ldap_back_conndn_cmp( const void *c1
, const void *c2
)
371 const ldapconn_t
*lc1
= (const ldapconn_t
*)c1
;
372 const ldapconn_t
*lc2
= (const ldapconn_t
*)c2
;
375 /* If local DNs don't match, it is definitely not a match */
376 /* For shared sessions, conn is NULL. Only explicitly
377 * bound sessions will have non-NULL conn.
379 rc
= SLAP_PTRCMP( lc1
->lc_conn
, lc2
->lc_conn
);
381 rc
= ber_bvcmp( &lc1
->lc_local_ndn
, &lc2
->lc_local_ndn
);
388 * ldap_back_conndnlc_cmp
390 * compares two ldapconn_t based on the value of the conn pointer,
391 * the local DN and the lc pointer; used by avl stuff for insert, lookup
395 ldap_back_conndnlc_cmp( const void *c1
, const void *c2
)
397 const ldapconn_t
*lc1
= (const ldapconn_t
*)c1
;
398 const ldapconn_t
*lc2
= (const ldapconn_t
*)c2
;
401 /* If local DNs don't match, it is definitely not a match */
402 /* For shared sessions, conn is NULL. Only explicitly
403 * bound sessions will have non-NULL conn.
405 rc
= SLAP_PTRCMP( lc1
->lc_conn
, lc2
->lc_conn
);
407 rc
= ber_bvcmp( &lc1
->lc_local_ndn
, &lc2
->lc_local_ndn
);
409 rc
= SLAP_PTRCMP( lc1
, lc2
);
419 * compares two ldapconn_t based on the value of the conn pointer;
420 * used by avl stuff for delete of all conns with the same connid
423 ldap_back_conn_cmp( const void *c1
, const void *c2
)
425 const ldapconn_t
*lc1
= (const ldapconn_t
*)c1
;
426 const ldapconn_t
*lc2
= (const ldapconn_t
*)c2
;
428 /* For shared sessions, conn is NULL. Only explicitly
429 * bound sessions will have non-NULL conn.
431 return SLAP_PTRCMP( lc1
->lc_conn
, lc2
->lc_conn
);
435 * ldap_back_conndn_dup
437 * returns -1 in case a duplicate ldapconn_t has been inserted;
441 ldap_back_conndn_dup( void *c1
, void *c2
)
443 ldapconn_t
*lc1
= (ldapconn_t
*)c1
;
444 ldapconn_t
*lc2
= (ldapconn_t
*)c2
;
446 /* Cannot have more than one shared session with same DN */
447 if ( lc1
->lc_conn
== lc2
->lc_conn
&&
448 dn_match( &lc1
->lc_local_ndn
, &lc2
->lc_local_ndn
) )
457 ldap_back_freeconn( ldapinfo_t
*li
, ldapconn_t
*lc
, int dolock
)
460 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
463 #if LDAP_BACK_PRINT_CONNTREE > 0
464 ldap_back_print_conntree( li
, ">>> ldap_back_freeconn" );
465 #endif /* LDAP_BACK_PRINT_CONNTREE */
467 (void)ldap_back_conn_delete( li
, lc
);
469 if ( lc
->lc_refcnt
== 0 ) {
470 ldap_back_conn_free( (void *)lc
);
473 #if LDAP_BACK_PRINT_CONNTREE > 0
474 ldap_back_print_conntree( li
, "<<< ldap_back_freeconn" );
475 #endif /* LDAP_BACK_PRINT_CONNTREE */
478 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
495 int rc
= LDAP_SUCCESS
;
497 /* start TLS ("tls-[try-]{start,propagate}" statements) */
498 if ( ( LDAP_BACK_USE_TLS_F( flags
) || ( *is_tls
&& LDAP_BACK_PROPAGATE_TLS_F( flags
) ) )
499 && !ldap_is_ldaps_url( url
) )
501 #ifdef SLAP_STARTTLS_ASYNCHRONOUS
503 * use asynchronous StartTLS
504 * in case, chase referral (not implemented yet)
508 if ( protocol
== 0 ) {
509 ldap_get_option( ld
, LDAP_OPT_PROTOCOL_VERSION
,
513 if ( protocol
< LDAP_VERSION3
) {
514 /* we should rather bail out... */
515 rc
= LDAP_UNWILLING_TO_PERFORM
;
516 *text
= "invalid protocol version";
519 if ( rc
== LDAP_SUCCESS
) {
520 rc
= ldap_start_tls( ld
, NULL
, NULL
, &msgid
);
523 if ( rc
== LDAP_SUCCESS
) {
524 LDAPMessage
*res
= NULL
;
527 LDAP_BACK_TV_SET( &tv
);
530 rc
= ldap_result( ld
, msgid
, LDAP_MSG_ALL
, &tv
, &res
);
532 rc
= LDAP_UNAVAILABLE
;
534 } else if ( rc
== 0 ) {
535 if ( retries
!= LDAP_BACK_RETRY_NEVER
) {
536 ldap_pvt_thread_yield();
540 LDAP_BACK_TV_SET( &tv
);
543 rc
= LDAP_UNAVAILABLE
;
545 } else if ( rc
== LDAP_RES_EXTENDED
) {
546 struct berval
*data
= NULL
;
548 rc
= ldap_parse_extended_result( ld
, res
,
550 if ( rc
== LDAP_SUCCESS
) {
552 rc
= ldap_parse_result( ld
, res
, &err
,
553 NULL
, NULL
, NULL
, NULL
, 1 );
554 if ( rc
== LDAP_SUCCESS
) {
559 /* FIXME: in case a referral
560 * is returned, should we try
561 * using it instead of the
563 if ( rc
== LDAP_SUCCESS
) {
564 rc
= ldap_install_tls( ld
);
566 } else if ( rc
== LDAP_REFERRAL
) {
567 rc
= LDAP_UNWILLING_TO_PERFORM
;
568 *text
= "unwilling to chase referral returned by Start TLS exop";
572 if ( data
->bv_val
) {
573 ber_memfree( data
->bv_val
);
587 #else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
589 * use synchronous StartTLS
591 rc
= ldap_start_tls_s( ld
, NULL
, NULL
);
592 #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
594 /* if StartTLS is requested, only attempt it if the URL
595 * is not "ldaps://"; this may occur not only in case
596 * of misconfiguration, but also when used in the chain
597 * overlay, where the "uri" can be parsed out of a referral */
603 case LDAP_SERVER_DOWN
:
607 if ( LDAP_BACK_TLS_CRITICAL_F( flags
) ) {
608 *text
= "could not start TLS";
612 /* in case Start TLS is not critical */
624 #endif /* HAVE_TLS */
627 ldap_back_prepare_conn( ldapconn_t
*lc
, Operation
*op
, SlapReply
*rs
, ldap_back_send_t sendok
)
629 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
633 int is_tls
= op
->o_conn
->c_is_tls
;
634 time_t lc_time
= (time_t)(-1);
636 #endif /* HAVE_TLS */
638 ldap_pvt_thread_mutex_lock( &li
->li_uri_mutex
);
639 rs
->sr_err
= ldap_initialize( &ld
, li
->li_uri
);
640 ldap_pvt_thread_mutex_unlock( &li
->li_uri_mutex
);
641 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
645 if ( li
->li_urllist_f
) {
646 ldap_set_urllist_proc( ld
, li
->li_urllist_f
, li
->li_urllist_p
);
649 /* Set LDAP version. This will always succeed: If the client
650 * bound with a particular version, then so can we.
652 if ( li
->li_version
!= 0 ) {
653 version
= li
->li_version
;
655 } else if ( op
->o_protocol
!= 0 ) {
656 version
= op
->o_protocol
;
659 /* assume it's an internal op; set to LDAPv3 */
660 version
= LDAP_VERSION3
;
662 ldap_set_option( ld
, LDAP_OPT_PROTOCOL_VERSION
, (const void *)&version
);
664 /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
665 ldap_set_option( ld
, LDAP_OPT_REFERRALS
,
666 LDAP_BACK_CHASE_REFERRALS( li
) ? LDAP_OPT_ON
: LDAP_OPT_OFF
);
668 if ( li
->li_network_timeout
> 0 ) {
671 tv
.tv_sec
= li
->li_network_timeout
;
673 ldap_set_option( ld
, LDAP_OPT_NETWORK_TIMEOUT
, (const void *)&tv
);
677 if ( LDAP_BACK_CONN_ISPRIV( lc
) ) {
680 } else if ( LDAP_BACK_CONN_ISIDASSERT( lc
) ) {
681 sb
= &li
->li_idassert
.si_bc
;
687 if ( sb
->sb_tls_do_init
) {
688 bindconf_tls_set( sb
, ld
);
689 } else if ( sb
->sb_tls_ctx
) {
690 ldap_set_option( ld
, LDAP_OPT_X_TLS_CTX
, sb
->sb_tls_ctx
);
693 ldap_pvt_thread_mutex_lock( &li
->li_uri_mutex
);
694 rs
->sr_err
= ldap_back_start_tls( ld
, op
->o_protocol
, &is_tls
,
695 li
->li_uri
, li
->li_flags
, li
->li_nretries
, &rs
->sr_text
);
696 ldap_pvt_thread_mutex_unlock( &li
->li_uri_mutex
);
697 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
698 ldap_unbind_ext( ld
, NULL
, NULL
);
699 rs
->sr_text
= "Start TLS failed";
702 } else if ( li
->li_idle_timeout
) {
703 /* only touch when activity actually took place... */
704 lc_time
= op
->o_time
;
706 #endif /* HAVE_TLS */
712 LDAP_BACK_CONN_ISTLS_SET( lc
);
714 LDAP_BACK_CONN_ISTLS_CLEAR( lc
);
716 if ( lc_time
!= (time_t)(-1) ) {
717 lc
->lc_time
= lc_time
;
719 #endif /* HAVE_TLS */
722 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
723 rs
->sr_err
= slap_map_api2result( rs
);
724 if ( sendok
& LDAP_BACK_SENDERR
) {
725 if ( rs
->sr_text
== NULL
) {
726 rs
->sr_text
= "Proxy connection initialization failed";
728 send_ldap_result( op
, rs
);
732 if ( li
->li_conn_ttl
> 0 ) {
733 lc
->lc_create_time
= op
->o_time
;
744 ldap_back_send_t sendok
,
745 struct berval
*binddn
,
746 struct berval
*bindcred
)
748 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
749 ldapconn_t
*lc
= NULL
,
752 lookupconn
= !( sendok
& LDAP_BACK_BINDING
);
754 /* if the server is quarantined, and
755 * - the current interval did not expire yet, or
756 * - no more retries should occur,
757 * don't return the connection */
758 if ( li
->li_isquarantined
) {
759 slap_retry_info_t
*ri
= &li
->li_quarantine
;
762 if ( li
->li_quarantine
.ri_interval
) {
763 ldap_pvt_thread_mutex_lock( &li
->li_quarantine_mutex
);
764 if ( li
->li_isquarantined
== LDAP_BACK_FQ_YES
) {
765 dont_retry
= ( ri
->ri_num
[ ri
->ri_idx
] == SLAP_RETRYNUM_TAIL
766 || slap_get_time() < ri
->ri_last
+ ri
->ri_interval
[ ri
->ri_idx
] );
768 Debug( LDAP_DEBUG_ANY
,
769 "%s: ldap_back_getconn quarantine "
770 "retry block #%d try #%d.\n",
771 op
->o_log_prefix
, ri
->ri_idx
, ri
->ri_count
);
772 li
->li_isquarantined
= LDAP_BACK_FQ_RETRYING
;
775 ldap_pvt_thread_mutex_unlock( &li
->li_quarantine_mutex
);
779 rs
->sr_err
= LDAP_UNAVAILABLE
;
780 if ( op
->o_conn
&& ( sendok
& LDAP_BACK_SENDERR
) ) {
781 rs
->sr_text
= "Target is quarantined";
782 send_ldap_result( op
, rs
);
788 /* Internal searches are privileged and shared. So is root. */
789 if ( op
->o_do_not_cache
|| be_isroot( op
) ) {
790 LDAP_BACK_CONN_ISPRIV_SET( &lc_curr
);
791 lc_curr
.lc_local_ndn
= op
->o_bd
->be_rootndn
;
792 LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr
, op
);
795 struct berval tmpbinddn
,
802 if ( binddn
== NULL
) {
805 if ( bindcred
== NULL
) {
806 bindcred
= &tmpbindcred
;
808 if ( op
->o_tag
== LDAP_REQ_BIND
) {
809 save_o_dn
= op
->o_dn
;
810 save_o_ndn
= op
->o_ndn
;
811 op
->o_dn
= op
->o_req_dn
;
812 op
->o_ndn
= op
->o_req_ndn
;
814 isproxyauthz
= ldap_back_is_proxy_authz( op
, rs
, sendok
, binddn
, bindcred
);
815 if ( op
->o_tag
== LDAP_REQ_BIND
) {
816 op
->o_dn
= save_o_dn
;
817 op
->o_ndn
= save_o_ndn
;
819 if ( isproxyauthz
== -1 ) {
823 lc_curr
.lc_local_ndn
= op
->o_ndn
;
824 /* Explicit binds must not be shared;
825 * however, explicit binds are piped in a special connection
826 * when idassert is to occur with "override" set */
827 if ( op
->o_tag
== LDAP_REQ_BIND
&& !isproxyauthz
) {
828 lc_curr
.lc_conn
= op
->o_conn
;
831 if ( isproxyauthz
&& !( sendok
& LDAP_BACK_BINDING
) ) {
832 lc_curr
.lc_local_ndn
= *binddn
;
833 LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr
, op
);
834 LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr
);
836 } else if ( isproxyauthz
&& ( li
->li_idassert_flags
& LDAP_BACK_AUTH_OVERRIDE
) ) {
837 lc_curr
.lc_local_ndn
= slap_empty_bv
;
838 LDAP_BACK_PCONN_BIND_SET( &lc_curr
, op
);
839 LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr
);
842 } else if ( SLAP_IS_AUTHZ_BACKEND( op
) ) {
843 lc_curr
.lc_conn
= op
->o_conn
;
846 LDAP_BACK_PCONN_ANON_SET( &lc_curr
, op
);
851 /* Explicit Bind requests always get their own conn */
854 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
855 if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr
) ) {
856 /* lookup a conn that's not binding */
857 LDAP_TAILQ_FOREACH( lc
,
858 &li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( &lc_curr
) ].lic_priv
,
861 if ( !LDAP_BACK_CONN_BINDING( lc
) && lc
->lc_refcnt
== 0 ) {
867 if ( lc
!= LDAP_TAILQ_LAST( &li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( lc
) ].lic_priv
,
870 LDAP_TAILQ_REMOVE( &li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( lc
) ].lic_priv
,
872 LDAP_TAILQ_ENTRY_INIT( lc
, lc_q
);
873 LDAP_TAILQ_INSERT_TAIL( &li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( lc
) ].lic_priv
,
877 } else if ( !LDAP_BACK_USE_TEMPORARIES( li
)
878 && li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( &lc_curr
) ].lic_num
== li
->li_conn_priv_max
)
880 lc
= LDAP_TAILQ_FIRST( &li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( &lc_curr
) ].lic_priv
);
885 /* Searches for a ldapconn in the avl tree */
886 lc
= (ldapconn_t
*)avl_find( li
->li_conninfo
.lai_tree
,
887 (caddr_t
)&lc_curr
, ldap_back_conndn_cmp
);
891 /* Don't reuse connections while they're still binding */
892 if ( LDAP_BACK_CONN_BINDING( lc
) ) {
893 if ( !LDAP_BACK_USE_TEMPORARIES( li
) ) {
894 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
896 ldap_pvt_thread_yield();
903 if ( op
->o_tag
== LDAP_REQ_BIND
) {
904 /* right now, this is the only possible case */
905 assert( ( li
->li_idassert_flags
& LDAP_BACK_AUTH_OVERRIDE
) );
906 LDAP_BACK_CONN_BINDING_SET( lc
);
909 refcnt
= ++lc
->lc_refcnt
;
912 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
915 /* Looks like we didn't get a bind. Open a new session... */
917 lc
= (ldapconn_t
*)ch_calloc( 1, sizeof( ldapconn_t
) );
918 lc
->lc_flags
= li
->li_flags
;
919 lc
->lc_lcflags
= lc_curr
.lc_lcflags
;
920 if ( ldap_back_prepare_conn( lc
, op
, rs
, sendok
) != LDAP_SUCCESS
) {
925 if ( sendok
& LDAP_BACK_BINDING
) {
926 LDAP_BACK_CONN_BINDING_SET( lc
);
929 lc
->lc_conn
= lc_curr
.lc_conn
;
930 ber_dupbv( &lc
->lc_local_ndn
, &lc_curr
.lc_local_ndn
);
933 * the rationale is: connections as the rootdn are privileged,
934 * so acl_authcDN is to be used; however, in some cases
935 * one already configured identity assertion with a highly
936 * privileged idassert_authcDN, so if acl_authcDN is NULL
937 * and idassert_authcDN is not, use the second instead.
939 * might change in the future, because it's preferable
940 * to make clear what identity is being used, since
941 * the only drawback is that one risks to configure
942 * the same identity twice...
944 if ( LDAP_BACK_CONN_ISPRIV( &lc_curr
) ) {
945 if ( BER_BVISNULL( &li
->li_acl_authcDN
) && !BER_BVISNULL( &li
->li_idassert_authcDN
) ) {
946 ber_dupbv( &lc
->lc_bound_ndn
, &li
->li_idassert_authcDN
);
947 ber_dupbv( &lc
->lc_cred
, &li
->li_idassert_passwd
);
950 ber_dupbv( &lc
->lc_bound_ndn
, &li
->li_acl_authcDN
);
951 ber_dupbv( &lc
->lc_cred
, &li
->li_acl_passwd
);
953 LDAP_BACK_CONN_ISPRIV_SET( lc
);
955 } else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr
) ) {
956 if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr
) ) {
957 ber_dupbv( &lc
->lc_bound_ndn
, &li
->li_idassert_authcDN
);
958 ber_dupbv( &lc
->lc_cred
, &li
->li_idassert_passwd
);
960 LDAP_BACK_CONN_ISIDASSERT_SET( lc
);
963 BER_BVZERO( &lc
->lc_cred
);
964 BER_BVZERO( &lc
->lc_bound_ndn
);
965 if ( !BER_BVISEMPTY( &op
->o_ndn
)
966 && SLAP_IS_AUTHZ_BACKEND( op
) )
968 ber_dupbv( &lc
->lc_bound_ndn
, &op
->o_ndn
);
973 /* if start TLS failed but it was not mandatory,
974 * check if the non-TLS connection was already
975 * in cache; in case, destroy the newly created
976 * connection and use the existing one */
977 if ( LDAP_BACK_PCONN_ISTLS( lc
)
978 && !ldap_tls_inplace( lc
->lc_ld
) )
980 ldapconn_t
*tmplc
= NULL
;
981 int idx
= LDAP_BACK_CONN2PRIV( &lc_curr
) - 1;
983 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
984 LDAP_TAILQ_FOREACH( tmplc
,
985 &li
->li_conn_priv
[ idx
].lic_priv
,
988 if ( !LDAP_BACK_CONN_BINDING( tmplc
) ) {
993 if ( tmplc
!= NULL
) {
994 refcnt
= ++tmplc
->lc_refcnt
;
995 ldap_back_conn_free( lc
);
998 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
1000 if ( tmplc
!= NULL
) {
1004 #endif /* HAVE_TLS */
1006 /* Inserts the newly created ldapconn in the avl tree */
1007 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
1009 LDAP_BACK_CONN_ISBOUND_CLEAR( lc
);
1011 assert( lc
->lc_refcnt
== 1 );
1013 #if LDAP_BACK_PRINT_CONNTREE > 0
1014 ldap_back_print_conntree( li
, ">>> ldap_back_getconn(insert)" );
1015 #endif /* LDAP_BACK_PRINT_CONNTREE */
1017 if ( LDAP_BACK_PCONN_ISPRIV( lc
) ) {
1018 if ( li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( lc
) ].lic_num
< li
->li_conn_priv_max
) {
1019 LDAP_TAILQ_INSERT_TAIL( &li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( lc
) ].lic_priv
, lc
, lc_q
);
1020 li
->li_conn_priv
[ LDAP_BACK_CONN2PRIV( lc
) ].lic_num
++;
1021 LDAP_BACK_CONN_CACHED_SET( lc
);
1024 LDAP_BACK_CONN_TAINTED_SET( lc
);
1029 rs
->sr_err
= avl_insert( &li
->li_conninfo
.lai_tree
, (caddr_t
)lc
,
1030 ldap_back_conndn_cmp
, ldap_back_conndn_dup
);
1031 LDAP_BACK_CONN_CACHED_SET( lc
);
1034 #if LDAP_BACK_PRINT_CONNTREE > 0
1035 ldap_back_print_conntree( li
, "<<< ldap_back_getconn(insert)" );
1036 #endif /* LDAP_BACK_PRINT_CONNTREE */
1038 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
1040 if ( LogTest( LDAP_DEBUG_TRACE
) ) {
1041 char buf
[ SLAP_TEXT_BUFLEN
];
1043 snprintf( buf
, sizeof( buf
),
1044 "lc=%p inserted refcnt=%u rc=%d",
1045 (void *)lc
, refcnt
, rs
->sr_err
);
1047 Debug( LDAP_DEBUG_TRACE
,
1048 "=>ldap_back_getconn: %s: %s\n",
1049 op
->o_log_prefix
, buf
, 0 );
1052 if ( !LDAP_BACK_PCONN_ISPRIV( lc
) ) {
1053 /* Err could be -1 in case a duplicate ldapconn is inserted */
1054 switch ( rs
->sr_err
) {
1059 LDAP_BACK_CONN_CACHED_CLEAR( lc
);
1060 if ( !( sendok
& LDAP_BACK_BINDING
) && !LDAP_BACK_USE_TEMPORARIES( li
) ) {
1061 /* duplicate: free and try to get the newly created one */
1062 ldap_back_conn_free( lc
);
1067 /* taint connection, so that it'll be freed when released */
1068 LDAP_BACK_CONN_TAINTED_SET( lc
);
1072 LDAP_BACK_CONN_CACHED_CLEAR( lc
);
1073 ldap_back_conn_free( lc
);
1074 rs
->sr_err
= LDAP_OTHER
;
1075 rs
->sr_text
= "Proxy bind collision";
1076 if ( op
->o_conn
&& ( sendok
& LDAP_BACK_SENDERR
) ) {
1077 send_ldap_result( op
, rs
);
1086 if ( ( li
->li_idle_timeout
!= 0 && op
->o_time
> lc
->lc_time
+ li
->li_idle_timeout
)
1087 || ( li
->li_conn_ttl
!= 0 && op
->o_time
> lc
->lc_create_time
+ li
->li_conn_ttl
) )
1091 /* let it be used, but taint/delete it so that
1092 * no-one else can look it up any further */
1093 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
1095 #if LDAP_BACK_PRINT_CONNTREE > 0
1096 ldap_back_print_conntree( li
, ">>> ldap_back_getconn(timeout)" );
1097 #endif /* LDAP_BACK_PRINT_CONNTREE */
1099 (void)ldap_back_conn_delete( li
, lc
);
1100 LDAP_BACK_CONN_TAINTED_SET( lc
);
1102 #if LDAP_BACK_PRINT_CONNTREE > 0
1103 ldap_back_print_conntree( li
, "<<< ldap_back_getconn(timeout)" );
1104 #endif /* LDAP_BACK_PRINT_CONNTREE */
1106 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
1109 if ( LogTest( LDAP_DEBUG_TRACE
) ) {
1110 char buf
[ SLAP_TEXT_BUFLEN
];
1112 snprintf( buf
, sizeof( buf
),
1113 "conn %p fetched refcnt=%u%s",
1115 expiring
? " expiring" : "" );
1116 Debug( LDAP_DEBUG_TRACE
,
1117 "=>ldap_back_getconn: %s.\n", buf
, 0, 0 );
1123 #endif /* HAVE_TLS */
1129 ldap_back_release_conn_lock(
1135 ldapconn_t
*lc
= *lcp
;
1138 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
1140 assert( lc
->lc_refcnt
> 0 );
1141 LDAP_BACK_CONN_BINDING_CLEAR( lc
);
1143 if ( LDAP_BACK_CONN_TAINTED( lc
) ) {
1144 ldap_back_freeconn( li
, lc
, 0 );
1148 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
1153 ldap_back_quarantine(
1157 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
1159 slap_retry_info_t
*ri
= &li
->li_quarantine
;
1161 ldap_pvt_thread_mutex_lock( &li
->li_quarantine_mutex
);
1163 if ( rs
->sr_err
== LDAP_UNAVAILABLE
) {
1164 time_t new_last
= slap_get_time();
1166 switch ( li
->li_isquarantined
) {
1167 case LDAP_BACK_FQ_NO
:
1168 if ( ri
->ri_last
== new_last
) {
1172 Debug( LDAP_DEBUG_ANY
,
1173 "%s: ldap_back_quarantine enter.\n",
1174 op
->o_log_prefix
, 0, 0 );
1180 case LDAP_BACK_FQ_RETRYING
:
1181 Debug( LDAP_DEBUG_ANY
,
1182 "%s: ldap_back_quarantine block #%d try #%d failed.\n",
1183 op
->o_log_prefix
, ri
->ri_idx
, ri
->ri_count
);
1186 if ( ri
->ri_num
[ ri
->ri_idx
] != SLAP_RETRYNUM_FOREVER
1187 && ri
->ri_count
== ri
->ri_num
[ ri
->ri_idx
] )
1198 li
->li_isquarantined
= LDAP_BACK_FQ_YES
;
1199 ri
->ri_last
= new_last
;
1201 } else if ( li
->li_isquarantined
!= LDAP_BACK_FQ_NO
) {
1202 if ( ri
->ri_last
== slap_get_time() ) {
1206 Debug( LDAP_DEBUG_ANY
,
1207 "%s: ldap_back_quarantine exit (%d) err=%d.\n",
1208 op
->o_log_prefix
, li
->li_isquarantined
, rs
->sr_err
);
1210 if ( li
->li_quarantine_f
) {
1211 (void)li
->li_quarantine_f( li
, li
->li_quarantine_p
);
1216 li
->li_isquarantined
= LDAP_BACK_FQ_NO
;
1220 ldap_pvt_thread_mutex_unlock( &li
->li_quarantine_mutex
);
1224 ldap_back_dobind_cb(
1229 ber_tag_t
*tptr
= op
->o_callback
->sc_private
;
1231 rs
->sr_tag
= slap_req2res( op
->o_tag
);
1233 return SLAP_CB_CONTINUE
;
1237 * ldap_back_dobind_int
1239 * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
1242 ldap_back_dobind_int(
1246 ldap_back_send_t sendok
,
1250 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
1253 struct berval binddn
= slap_empty_bv
,
1254 bindcred
= slap_empty_bv
;
1260 ber_tag_t o_tag
= op
->o_tag
;
1261 slap_callback cb
= {0};
1263 assert( lcp
!= NULL
);
1264 assert( retries
>= 0 );
1266 if ( sendok
& LDAP_BACK_GETCONN
) {
1267 assert( *lcp
== NULL
);
1269 lc
= ldap_back_getconn( op
, rs
, sendok
, &binddn
, &bindcred
);
1279 assert( lc
!= NULL
);
1283 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
1286 if ( binding
== 0 ) {
1287 /* check if already bound */
1288 rc
= isbound
= LDAP_BACK_CONN_ISBOUND( lc
);
1291 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
1296 if ( LDAP_BACK_CONN_BINDING( lc
) ) {
1297 /* if someone else is about to bind it, give up and retry */
1299 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
1301 ldap_pvt_thread_yield();
1305 /* otherwise this thread will bind it */
1306 LDAP_BACK_CONN_BINDING_SET( lc
);
1312 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
1316 * FIXME: we need to let clients use proxyAuthz
1317 * otherwise we cannot do symmetric pools of servers;
1318 * we have to live with the fact that a user can
1319 * authorize itself as any ID that is allowed
1320 * by the authzTo directive of the "proxyauthzdn".
1323 * NOTE: current Proxy Authorization specification
1324 * and implementation do not allow proxy authorization
1325 * control to be provided with Bind requests
1328 * if no bind took place yet, but the connection is bound
1329 * and the "idassert-authcDN" (or other ID) is set,
1330 * then bind as the asserting identity and explicitly
1331 * add the proxyAuthz control to every operation with the
1332 * dn bound to the connection as control value.
1333 * This is done also if this is the authorizing backend,
1334 * but the "override" flag is given to idassert.
1335 * It allows to use SASL bind and yet proxyAuthz users
1337 op
->o_tag
= LDAP_REQ_BIND
;
1338 cb
.sc_next
= op
->o_callback
;
1339 cb
.sc_private
= &o_tag
;
1340 cb
.sc_response
= ldap_back_dobind_cb
;
1341 op
->o_callback
= &cb
;
1343 if ( LDAP_BACK_CONN_ISIDASSERT( lc
) ) {
1344 if ( BER_BVISEMPTY( &binddn
) && BER_BVISEMPTY( &bindcred
) ) {
1345 /* if we got here, it shouldn't return result */
1346 rc
= ldap_back_is_proxy_authz( op
, rs
,
1347 LDAP_BACK_DONTSEND
, &binddn
, &bindcred
);
1350 rc
= ldap_back_proxy_authz_bind( lc
, op
, rs
, sendok
, &binddn
, &bindcred
);
1354 #ifdef HAVE_CYRUS_SASL
1355 if ( LDAP_BACK_CONN_ISPRIV( lc
)
1356 && li
->li_acl_authmethod
== LDAP_AUTH_SASL
)
1358 void *defaults
= NULL
;
1360 if ( li
->li_acl_secprops
!= NULL
) {
1361 rc
= ldap_set_option( lc
->lc_ld
,
1362 LDAP_OPT_X_SASL_SECPROPS
, li
->li_acl_secprops
);
1364 if ( rc
!= LDAP_OPT_SUCCESS
) {
1365 Debug( LDAP_DEBUG_ANY
, "Error: ldap_set_option "
1366 "(SECPROPS,\"%s\") failed!\n",
1367 li
->li_acl_secprops
, 0, 0 );
1372 defaults
= lutil_sasl_defaults( lc
->lc_ld
,
1373 li
->li_acl_sasl_mech
.bv_val
,
1374 li
->li_acl_sasl_realm
.bv_val
,
1375 li
->li_acl_authcID
.bv_val
,
1376 li
->li_acl_passwd
.bv_val
,
1378 if ( defaults
== NULL
) {
1379 rs
->sr_err
= LDAP_OTHER
;
1380 LDAP_BACK_CONN_ISBOUND_CLEAR( lc
);
1381 if ( sendok
& LDAP_BACK_SENDERR
) {
1382 send_ldap_result( op
, rs
);
1387 rs
->sr_err
= ldap_sasl_interactive_bind_s( lc
->lc_ld
,
1388 li
->li_acl_authcDN
.bv_val
,
1389 li
->li_acl_sasl_mech
.bv_val
, NULL
, NULL
,
1390 LDAP_SASL_QUIET
, lutil_sasl_interact
,
1393 lutil_sasl_freedefs( defaults
);
1395 switch ( rs
->sr_err
) {
1397 LDAP_BACK_CONN_ISBOUND_SET( lc
);
1400 case LDAP_LOCAL_ERROR
:
1401 /* list client API error codes that require
1402 * to taint the connection */
1403 /* FIXME: should actually retry? */
1404 LDAP_BACK_CONN_TAINTED_SET( lc
);
1409 LDAP_BACK_CONN_ISBOUND_CLEAR( lc
);
1410 rs
->sr_err
= slap_map_api2result( rs
);
1411 if ( sendok
& LDAP_BACK_SENDERR
) {
1412 send_ldap_result( op
, rs
);
1417 if ( LDAP_BACK_QUARANTINE( li
) ) {
1418 ldap_back_quarantine( op
, rs
);
1423 #endif /* HAVE_CYRUS_SASL */
1426 rs
->sr_err
= ldap_sasl_bind( lc
->lc_ld
,
1427 BER_BVISNULL( &lc
->lc_cred
) ? "" : lc
->lc_bound_ndn
.bv_val
,
1428 LDAP_SASL_SIMPLE
, &lc
->lc_cred
,
1429 NULL
, NULL
, &msgid
);
1431 if ( rs
->sr_err
== LDAP_SERVER_DOWN
) {
1432 if ( retries
!= LDAP_BACK_RETRY_NEVER
) {
1434 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
1437 assert( lc
->lc_refcnt
> 0 );
1438 if ( lc
->lc_refcnt
== 1 ) {
1439 ldap_unbind_ext( lc
->lc_ld
, NULL
, NULL
);
1442 /* lc here must be the regular lc, reset and ready for init */
1443 rs
->sr_err
= ldap_back_prepare_conn( lc
, op
, rs
, sendok
);
1444 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
1445 sendok
&= ~LDAP_BACK_SENDERR
;
1451 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
1454 if ( rs
->sr_err
== LDAP_SUCCESS
) {
1455 if ( retries
> 0 ) {
1462 assert( lc
->lc_refcnt
== 1 );
1464 ldap_back_freeconn( li
, lc
, dolock
);
1466 rs
->sr_err
= slap_map_api2result( rs
);
1468 if ( LDAP_BACK_QUARANTINE( li
) ) {
1469 ldap_back_quarantine( op
, rs
);
1472 if ( rs
->sr_err
!= LDAP_SUCCESS
&&
1473 ( sendok
& LDAP_BACK_SENDERR
) )
1475 if ( op
->o_callback
== &cb
)
1476 op
->o_callback
= cb
.sc_next
;
1478 rs
->sr_text
= "Proxy can't contact remote server";
1479 send_ldap_result( op
, rs
);
1486 rc
= ldap_back_op_result( lc
, op
, rs
, msgid
,
1487 -1, ( sendok
| LDAP_BACK_BINDING
) );
1488 if ( rc
== LDAP_SUCCESS
) {
1489 LDAP_BACK_CONN_ISBOUND_SET( lc
);
1493 LDAP_BACK_CONN_BINDING_CLEAR( lc
);
1494 rc
= LDAP_BACK_CONN_ISBOUND( lc
);
1496 ldap_back_release_conn_lock( li
, lcp
, dolock
);
1498 } else if ( LDAP_BACK_SAVECRED( li
) ) {
1499 ldap_set_rebind_proc( lc
->lc_ld
, li
->li_rebind_f
, lc
);
1503 if ( op
->o_callback
== &cb
)
1504 op
->o_callback
= cb
.sc_next
;
1513 * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
1516 ldap_back_dobind( ldapconn_t
**lcp
, Operation
*op
, SlapReply
*rs
, ldap_back_send_t sendok
)
1518 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
1520 return ldap_back_dobind_int( lcp
, op
, rs
,
1521 ( sendok
| LDAP_BACK_GETCONN
), li
->li_nretries
, 1 );
1525 * ldap_back_default_rebind
1527 * This is a callback used for chasing referrals using the same
1528 * credentials as the original user on this session.
1531 ldap_back_default_rebind( LDAP
*ld
, LDAP_CONST
char *url
, ber_tag_t request
,
1532 ber_int_t msgid
, void *params
)
1534 ldapconn_t
*lc
= (ldapconn_t
*)params
;
1537 /* ... otherwise we couldn't get here */
1538 assert( lc
!= NULL
);
1540 if ( !ldap_tls_inplace( ld
) ) {
1541 int is_tls
= LDAP_BACK_CONN_ISTLS( lc
),
1543 const char *text
= NULL
;
1545 rc
= ldap_back_start_tls( ld
, 0, &is_tls
, url
, lc
->lc_flags
,
1546 LDAP_BACK_RETRY_DEFAULT
, &text
);
1547 if ( rc
!= LDAP_SUCCESS
) {
1551 #endif /* HAVE_TLS */
1553 /* FIXME: add checks on the URL/identity? */
1555 return ldap_sasl_bind_s( ld
,
1556 BER_BVISNULL( &lc
->lc_cred
) ? "" : lc
->lc_bound_ndn
.bv_val
,
1557 LDAP_SASL_SIMPLE
, &lc
->lc_cred
, NULL
, NULL
, NULL
);
1561 * ldap_back_default_urllist
1564 ldap_back_default_urllist(
1566 LDAPURLDesc
**urllist
,
1570 ldapinfo_t
*li
= (ldapinfo_t
*)params
;
1571 LDAPURLDesc
**urltail
;
1573 if ( urllist
== url
) {
1574 return LDAP_SUCCESS
;
1577 for ( urltail
= &(*url
)->lud_next
; *urltail
; urltail
= &(*urltail
)->lud_next
)
1580 *urltail
= *urllist
;
1584 ldap_pvt_thread_mutex_lock( &li
->li_uri_mutex
);
1586 ch_free( li
->li_uri
);
1589 ldap_get_option( ld
, LDAP_OPT_URI
, (void *)&li
->li_uri
);
1590 ldap_pvt_thread_mutex_unlock( &li
->li_uri_mutex
);
1592 return LDAP_SUCCESS
;
1601 ldap_back_send_t sendok
)
1603 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
1605 /* default behavior */
1606 if ( LDAP_BACK_ABANDON( li
) ) {
1607 return ldap_abandon_ext( lc
->lc_ld
, msgid
, NULL
, NULL
);
1610 if ( LDAP_BACK_IGNORE( li
) ) {
1611 return ldap_pvt_discard( lc
->lc_ld
, msgid
);
1614 if ( LDAP_BACK_CANCEL( li
) ) {
1615 /* FIXME: asynchronous? */
1616 return ldap_cancel_s( lc
->lc_ld
, msgid
, NULL
, NULL
);
1625 ldap_back_op_result(
1631 ldap_back_send_t sendok
)
1633 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
1638 LDAPControl
**ctrls
= NULL
;
1640 #define ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE)
1643 rs
->sr_matched
= NULL
;
1645 rs
->sr_ctrls
= NULL
;
1647 /* if the error recorded in the reply corresponds
1648 * to a successful state, get the error from the
1649 * remote server response */
1650 if ( ERR_OK( rs
->sr_err
) ) {
1653 LDAPMessage
*res
= NULL
;
1654 time_t stoptime
= (time_t)(-1);
1655 int timeout_err
= op
->o_protocol
>= LDAP_VERSION3
?
1656 LDAP_ADMINLIMIT_EXCEEDED
: LDAP_OTHER
;
1657 const char *timeout_text
= "Operation timed out";
1659 /* if timeout is not specified, compute and use
1660 * the one specific to the ongoing operation */
1661 if ( timeout
== (time_t)(-1) ) {
1662 slap_op_t opidx
= slap_req2op( op
->o_tag
);
1664 if ( opidx
== SLAP_OP_SEARCH
) {
1665 if ( op
->ors_tlimit
<= 0 ) {
1669 timeout
= op
->ors_tlimit
;
1670 timeout_err
= LDAP_TIMELIMIT_EXCEEDED
;
1671 timeout_text
= NULL
;
1675 timeout
= li
->li_timeout
[ opidx
];
1679 /* better than nothing :) */
1680 if ( timeout
== 0 ) {
1681 if ( li
->li_idle_timeout
) {
1682 timeout
= li
->li_idle_timeout
;
1684 } else if ( li
->li_conn_ttl
) {
1685 timeout
= li
->li_conn_ttl
;
1690 stoptime
= op
->o_time
+ timeout
;
1693 LDAP_BACK_TV_SET( &tv
);
1696 /* if result parsing fails, note the failure reason */
1697 rc
= ldap_result( lc
->lc_ld
, msgid
, LDAP_MSG_ALL
, &tv
, &res
);
1700 if ( timeout
&& slap_get_time() > stoptime
) {
1701 if ( sendok
& LDAP_BACK_BINDING
) {
1702 ldap_unbind_ext( lc
->lc_ld
, NULL
, NULL
);
1705 /* let it be used, but taint/delete it so that
1706 * no-one else can look it up any further */
1707 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
1709 #if LDAP_BACK_PRINT_CONNTREE > 0
1710 ldap_back_print_conntree( li
, ">>> ldap_back_getconn(timeout)" );
1711 #endif /* LDAP_BACK_PRINT_CONNTREE */
1713 (void)ldap_back_conn_delete( li
, lc
);
1714 LDAP_BACK_CONN_TAINTED_SET( lc
);
1716 #if LDAP_BACK_PRINT_CONNTREE > 0
1717 ldap_back_print_conntree( li
, "<<< ldap_back_getconn(timeout)" );
1718 #endif /* LDAP_BACK_PRINT_CONNTREE */
1719 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
1722 (void)ldap_back_cancel( lc
, op
, rs
, msgid
, sendok
);
1724 rs
->sr_err
= timeout_err
;
1725 rs
->sr_text
= timeout_text
;
1730 LDAP_BACK_TV_SET( &tv
);
1731 ldap_pvt_thread_yield();
1735 ldap_get_option( lc
->lc_ld
, LDAP_OPT_ERROR_NUMBER
,
1740 /* otherwise get the result; if it is not
1741 * LDAP_SUCCESS, record it in the reply
1742 * structure (this includes
1743 * LDAP_COMPARE_{TRUE|FALSE}) */
1745 /* only touch when activity actually took place... */
1746 if ( li
->li_idle_timeout
&& lc
) {
1747 lc
->lc_time
= op
->o_time
;
1750 rc
= ldap_parse_result( lc
->lc_ld
, res
, &rs
->sr_err
,
1751 &match
, &text
, &refs
, &ctrls
, 1 );
1753 if ( rc
!= LDAP_SUCCESS
) {
1757 /* RFC 4511: referrals can only appear
1758 * if result code is LDAP_REFERRAL */
1760 && refs
[ 0 ] != NULL
1761 && refs
[ 0 ][ 0 ] != '\0' )
1763 if ( rs
->sr_err
!= LDAP_REFERRAL
) {
1764 Debug( LDAP_DEBUG_ANY
,
1765 "%s ldap_back_op_result: "
1766 "got referrals with err=%d\n",
1773 for ( i
= 0; refs
[ i
] != NULL
; i
++ )
1775 rs
->sr_ref
= op
->o_tmpalloc( sizeof( struct berval
) * ( i
+ 1 ),
1777 for ( i
= 0; refs
[ i
] != NULL
; i
++ ) {
1778 ber_str2bv( refs
[ i
], 0, 0, &rs
->sr_ref
[ i
] );
1780 BER_BVZERO( &rs
->sr_ref
[ i
] );
1783 } else if ( rs
->sr_err
== LDAP_REFERRAL
) {
1784 Debug( LDAP_DEBUG_ANY
,
1785 "%s ldap_back_op_result: "
1786 "got err=%d with null "
1787 "or empty referrals\n",
1791 rs
->sr_err
= LDAP_NO_SUCH_OBJECT
;
1794 if ( ctrls
!= NULL
) {
1795 rs
->sr_ctrls
= ctrls
;
1800 /* if the error in the reply structure is not
1801 * LDAP_SUCCESS, try to map it from client
1802 * to server error */
1803 if ( !ERR_OK( rs
->sr_err
) ) {
1804 rs
->sr_err
= slap_map_api2result( rs
);
1806 /* internal ops ( op->o_conn == NULL )
1807 * must not reply to client */
1808 if ( op
->o_conn
&& !op
->o_do_not_cache
&& match
) {
1810 /* record the (massaged) matched
1811 * DN into the reply structure */
1812 rs
->sr_matched
= match
;
1816 if ( rs
->sr_err
== LDAP_UNAVAILABLE
) {
1817 if ( !( sendok
& LDAP_BACK_RETRYING
) ) {
1818 if ( LDAP_BACK_QUARANTINE( li
) ) {
1819 ldap_back_quarantine( op
, rs
);
1821 if ( op
->o_conn
&& ( sendok
& LDAP_BACK_SENDERR
) ) {
1822 if ( rs
->sr_text
== NULL
) rs
->sr_text
= "Proxy operation retry failed";
1823 send_ldap_result( op
, rs
);
1827 } else if ( op
->o_conn
&&
1828 ( ( ( sendok
& LDAP_BACK_SENDOK
) && ERR_OK( rs
->sr_err
) )
1829 || ( ( sendok
& LDAP_BACK_SENDERR
) && rs
->sr_err
!= LDAP_SUCCESS
) ) )
1831 send_ldap_result( op
, rs
);
1835 if ( rs
->sr_matched
!= match
) {
1836 free( (char *)rs
->sr_matched
);
1838 rs
->sr_matched
= NULL
;
1839 ldap_memfree( match
);
1843 ldap_memfree( text
);
1848 op
->o_tmpfree( rs
->sr_ref
, op
->o_tmpmemctx
);
1853 ber_memvfree( (void **)refs
);
1857 assert( rs
->sr_ctrls
!= NULL
);
1858 ldap_controls_free( ctrls
);
1859 rs
->sr_ctrls
= NULL
;
1862 return( ERR_OK( rs
->sr_err
) ? LDAP_SUCCESS
: rs
->sr_err
);
1865 /* return true if bound, false if failed */
1867 ldap_back_retry( ldapconn_t
**lcp
, Operation
*op
, SlapReply
*rs
, ldap_back_send_t sendok
)
1869 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
1872 assert( lcp
!= NULL
);
1873 assert( *lcp
!= NULL
);
1875 ldap_pvt_thread_mutex_lock( &li
->li_conninfo
.lai_mutex
);
1877 if ( (*lcp
)->lc_refcnt
== 1 ) {
1878 int binding
= LDAP_BACK_CONN_BINDING( *lcp
);
1880 ldap_pvt_thread_mutex_lock( &li
->li_uri_mutex
);
1881 Debug( LDAP_DEBUG_ANY
,
1882 "%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
1883 op
->o_log_prefix
, li
->li_uri
,
1884 BER_BVISNULL( &(*lcp
)->lc_bound_ndn
) ?
1885 "" : (*lcp
)->lc_bound_ndn
.bv_val
);
1886 ldap_pvt_thread_mutex_unlock( &li
->li_uri_mutex
);
1888 ldap_unbind_ext( (*lcp
)->lc_ld
, NULL
, NULL
);
1889 (*lcp
)->lc_ld
= NULL
;
1890 LDAP_BACK_CONN_ISBOUND_CLEAR( (*lcp
) );
1892 /* lc here must be the regular lc, reset and ready for init */
1893 rc
= ldap_back_prepare_conn( *lcp
, op
, rs
, sendok
);
1894 if ( rc
!= LDAP_SUCCESS
) {
1895 /* freeit, because lc_refcnt == 1 */
1896 (*lcp
)->lc_refcnt
= 0;
1897 (void)ldap_back_freeconn( li
, *lcp
, 0 );
1901 } else if ( ( sendok
& LDAP_BACK_BINDING
) ) {
1903 LDAP_BACK_CONN_BINDING_SET( *lcp
);
1908 rc
= ldap_back_dobind_int( lcp
, op
, rs
, sendok
, 0, 0 );
1909 if ( rc
== 0 && *lcp
!= NULL
) {
1910 /* freeit, because lc_refcnt == 1 */
1911 (*lcp
)->lc_refcnt
= 0;
1912 LDAP_BACK_CONN_TAINTED_SET( *lcp
);
1913 (void)ldap_back_freeconn( li
, *lcp
, 0 );
1919 Debug( LDAP_DEBUG_TRACE
,
1920 "ldap_back_retry: conn %p refcnt=%u unable to retry.\n",
1921 (void *)(*lcp
), (*lcp
)->lc_refcnt
, 0 );
1923 LDAP_BACK_CONN_TAINTED_SET( *lcp
);
1924 ldap_back_release_conn_lock( li
, lcp
, 0 );
1925 assert( *lcp
== NULL
);
1927 if ( sendok
& LDAP_BACK_SENDERR
) {
1928 rs
->sr_err
= LDAP_UNAVAILABLE
;
1929 rs
->sr_text
= "Unable to retry";
1930 send_ldap_result( op
, rs
);
1934 ldap_pvt_thread_mutex_unlock( &li
->li_conninfo
.lai_mutex
);
1940 ldap_back_is_proxy_authz( Operation
*op
, SlapReply
*rs
, ldap_back_send_t sendok
,
1941 struct berval
*binddn
, struct berval
*bindcred
)
1943 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
1947 if ( op
->o_conn
== NULL
|| op
->o_do_not_cache
) {
1951 /* don't proxyAuthz if protocol is not LDAPv3 */
1952 switch ( li
->li_version
) {
1957 if ( op
->o_protocol
== 0 || op
->o_protocol
== LDAP_VERSION3
) {
1963 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
1964 if ( sendok
& LDAP_BACK_SENDERR
) {
1965 send_ldap_result( op
, rs
);
1972 *binddn
= slap_empty_bv
;
1973 *bindcred
= slap_empty_bv
;
1975 if ( !BER_BVISNULL( &op
->o_conn
->c_ndn
) ) {
1976 ndn
= op
->o_conn
->c_ndn
;
1982 switch ( li
->li_idassert_mode
) {
1983 case LDAP_BACK_IDASSERT_LEGACY
:
1984 if ( !BER_BVISNULL( &ndn
) && !BER_BVISEMPTY( &ndn
) ) {
1985 if ( !BER_BVISNULL( &li
->li_idassert_authcDN
) && !BER_BVISEMPTY( &li
->li_idassert_authcDN
) )
1987 *binddn
= li
->li_idassert_authcDN
;
1988 *bindcred
= li
->li_idassert_passwd
;
1995 /* NOTE: rootdn can always idassert */
1996 if ( BER_BVISNULL( &ndn
)
1997 && li
->li_idassert_authz
== NULL
1998 && !( li
->li_idassert_flags
& LDAP_BACK_AUTH_AUTHZ_ALL
) )
2000 if ( li
->li_idassert_flags
& LDAP_BACK_AUTH_PRESCRIPTIVE
) {
2001 rs
->sr_err
= LDAP_INAPPROPRIATE_AUTH
;
2002 if ( sendok
& LDAP_BACK_SENDERR
) {
2003 send_ldap_result( op
, rs
);
2008 rs
->sr_err
= LDAP_SUCCESS
;
2009 *binddn
= slap_empty_bv
;
2010 *bindcred
= slap_empty_bv
;
2016 } else if ( li
->li_idassert_authz
&& !be_isroot( op
) ) {
2017 struct berval authcDN
;
2019 if ( BER_BVISNULL( &ndn
) ) {
2020 authcDN
= slap_empty_bv
;
2025 rs
->sr_err
= slap_sasl_matches( op
, li
->li_idassert_authz
,
2026 &authcDN
, &authcDN
);
2027 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
2028 if ( li
->li_idassert_flags
& LDAP_BACK_AUTH_PRESCRIPTIVE
) {
2029 if ( sendok
& LDAP_BACK_SENDERR
) {
2030 send_ldap_result( op
, rs
);
2035 rs
->sr_err
= LDAP_SUCCESS
;
2036 *binddn
= slap_empty_bv
;
2037 *bindcred
= slap_empty_bv
;
2045 *binddn
= li
->li_idassert_authcDN
;
2046 *bindcred
= li
->li_idassert_passwd
;
2056 ldap_back_proxy_authz_bind(
2060 ldap_back_send_t sendok
,
2061 struct berval
*binddn
,
2062 struct berval
*bindcred
)
2064 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
2069 if ( !BER_BVISNULL( &op
->o_conn
->c_ndn
) ) {
2070 ndn
= op
->o_conn
->c_ndn
;
2076 if ( li
->li_idassert_authmethod
== LDAP_AUTH_SASL
) {
2077 #ifdef HAVE_CYRUS_SASL
2078 void *defaults
= NULL
;
2079 struct berval authzID
= BER_BVNULL
;
2082 /* if SASL supports native authz, prepare for it */
2083 if ( ( !op
->o_do_not_cache
|| !op
->o_is_auth_check
) &&
2084 ( li
->li_idassert_flags
& LDAP_BACK_AUTH_NATIVE_AUTHZ
) )
2086 switch ( li
->li_idassert_mode
) {
2087 case LDAP_BACK_IDASSERT_OTHERID
:
2088 case LDAP_BACK_IDASSERT_OTHERDN
:
2089 authzID
= li
->li_idassert_authzID
;
2092 case LDAP_BACK_IDASSERT_ANONYMOUS
:
2093 BER_BVSTR( &authzID
, "dn:" );
2096 case LDAP_BACK_IDASSERT_SELF
:
2097 if ( BER_BVISNULL( &ndn
) ) {
2098 /* connection is not authc'd, so don't idassert */
2099 BER_BVSTR( &authzID
, "dn:" );
2102 authzID
.bv_len
= STRLENOF( "dn:" ) + ndn
.bv_len
;
2103 authzID
.bv_val
= slap_sl_malloc( authzID
.bv_len
+ 1, op
->o_tmpmemctx
);
2104 AC_MEMCPY( authzID
.bv_val
, "dn:", STRLENOF( "dn:" ) );
2105 AC_MEMCPY( authzID
.bv_val
+ STRLENOF( "dn:" ),
2106 ndn
.bv_val
, ndn
.bv_len
+ 1 );
2115 if ( li
->li_idassert_secprops
!= NULL
) {
2116 rs
->sr_err
= ldap_set_option( lc
->lc_ld
,
2117 LDAP_OPT_X_SASL_SECPROPS
,
2118 (void *)li
->li_idassert_secprops
);
2120 if ( rs
->sr_err
!= LDAP_OPT_SUCCESS
) {
2121 rs
->sr_err
= LDAP_OTHER
;
2122 if ( sendok
& LDAP_BACK_SENDERR
) {
2123 send_ldap_result( op
, rs
);
2125 LDAP_BACK_CONN_ISBOUND_CLEAR( lc
);
2130 defaults
= lutil_sasl_defaults( lc
->lc_ld
,
2131 li
->li_idassert_sasl_mech
.bv_val
,
2132 li
->li_idassert_sasl_realm
.bv_val
,
2133 li
->li_idassert_authcID
.bv_val
,
2134 li
->li_idassert_passwd
.bv_val
,
2136 if ( defaults
== NULL
) {
2137 rs
->sr_err
= LDAP_OTHER
;
2138 LDAP_BACK_CONN_ISBOUND_CLEAR( lc
);
2139 if ( sendok
& LDAP_BACK_SENDERR
) {
2140 send_ldap_result( op
, rs
);
2145 rs
->sr_err
= ldap_sasl_interactive_bind_s( lc
->lc_ld
, binddn
->bv_val
,
2146 li
->li_idassert_sasl_mech
.bv_val
, NULL
, NULL
,
2147 LDAP_SASL_QUIET
, lutil_sasl_interact
,
2150 switch ( rs
->sr_err
) {
2152 LDAP_BACK_CONN_ISBOUND_SET( lc
);
2155 case LDAP_LOCAL_ERROR
:
2156 /* list client API error codes that require
2157 * to taint the connection */
2158 /* FIXME: should actually retry? */
2159 LDAP_BACK_CONN_TAINTED_SET( lc
);
2164 LDAP_BACK_CONN_ISBOUND_CLEAR( lc
);
2165 rs
->sr_err
= slap_map_api2result( rs
);
2166 if ( sendok
& LDAP_BACK_SENDERR
) {
2167 send_ldap_result( op
, rs
);
2172 lutil_sasl_freedefs( defaults
);
2174 slap_sl_free( authzID
.bv_val
, op
->o_tmpmemctx
);
2178 #endif /* HAVE_CYRUS_SASL */
2181 switch ( li
->li_idassert_authmethod
) {
2182 case LDAP_AUTH_NONE
:
2183 /* FIXME: do we really need this? */
2184 BER_BVSTR( binddn
, "" );
2185 BER_BVSTR( bindcred
, "" );
2188 case LDAP_AUTH_SIMPLE
:
2189 rs
->sr_err
= ldap_sasl_bind( lc
->lc_ld
,
2190 binddn
->bv_val
, LDAP_SASL_SIMPLE
,
2191 bindcred
, NULL
, NULL
, &msgid
);
2192 rc
= ldap_back_op_result( lc
, op
, rs
, msgid
,
2193 -1, ( sendok
| LDAP_BACK_BINDING
) );
2198 LDAP_BACK_CONN_ISBOUND_CLEAR( lc
);
2199 rs
->sr_err
= LDAP_AUTH_METHOD_NOT_SUPPORTED
;
2200 if ( sendok
& LDAP_BACK_SENDERR
) {
2201 send_ldap_result( op
, rs
);
2206 if ( rc
== LDAP_SUCCESS
) {
2207 /* set rebind stuff in case of successful proxyAuthz bind,
2208 * so that referral chasing is attempted using the right
2210 LDAP_BACK_CONN_ISBOUND_SET( lc
);
2211 ber_bvreplace( &lc
->lc_bound_ndn
, binddn
);
2213 if ( !BER_BVISNULL( &lc
->lc_cred
) ) {
2214 memset( lc
->lc_cred
.bv_val
, 0,
2215 lc
->lc_cred
.bv_len
);
2218 if ( LDAP_BACK_SAVECRED( li
) ) {
2219 ber_bvreplace( &lc
->lc_cred
, bindcred
);
2220 ldap_set_rebind_proc( lc
->lc_ld
, li
->li_rebind_f
, lc
);
2223 lc
->lc_cred
.bv_len
= 0;
2227 return LDAP_BACK_CONN_ISBOUND( lc
);
2231 * ldap_back_proxy_authz_ctrl() prepends a proxyAuthz control
2232 * to existing server-side controls if required; if not,
2233 * the existing server-side controls are placed in *pctrls.
2234 * The caller, after using the controls in client API
2235 * operations, if ( *pctrls != op->o_ctrls ), should
2236 * free( (*pctrls)[ 0 ] ) and free( *pctrls ).
2237 * The function returns success if the control could
2238 * be added if required, or if it did nothing; in the future,
2239 * it might return some error if it failed.
2241 * if no bind took place yet, but the connection is bound
2242 * and the "proxyauthzdn" is set, then bind as "proxyauthzdn"
2243 * and explicitly add proxyAuthz the control to every operation
2244 * with the dn bound to the connection as control value.
2246 * If no server-side controls are defined for the operation,
2247 * simply add the proxyAuthz control; otherwise, if the
2248 * proxyAuthz control is not already set, add it as
2251 * FIXME: is controls order significant for security?
2252 * ANSWER: controls ordering and interoperability
2253 * must be indicated by the specs of each control; if none
2254 * is specified, the order is irrelevant.
2257 ldap_back_proxy_authz_ctrl(
2260 struct berval
*bound_ndn
,
2262 slap_idassert_t
*si
,
2265 slap_idassert_mode_t mode
;
2266 struct berval assertedID
,
2270 rs
->sr_err
= SLAP_CB_CONTINUE
;
2272 /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID,
2273 * but if it is not set this test fails. We need a different
2274 * means to detect if idassert is enabled */
2275 if ( ( BER_BVISNULL( &si
->si_bc
.sb_authcId
) || BER_BVISEMPTY( &si
->si_bc
.sb_authcId
) )
2276 && ( BER_BVISNULL( &si
->si_bc
.sb_binddn
) || BER_BVISEMPTY( &si
->si_bc
.sb_binddn
) )
2277 && BER_BVISNULL( &si
->si_bc
.sb_saslmech
) )
2282 if ( !op
->o_conn
|| op
->o_do_not_cache
|| ( isroot
= be_isroot( op
) ) ) {
2286 if ( op
->o_tag
== LDAP_REQ_BIND
) {
2287 ndn
= op
->o_req_ndn
;
2289 } else if ( !BER_BVISNULL( &op
->o_conn
->c_ndn
) ) {
2290 ndn
= op
->o_conn
->c_ndn
;
2296 if ( si
->si_mode
== LDAP_BACK_IDASSERT_LEGACY
) {
2297 if ( op
->o_proxy_authz
) {
2299 * FIXME: we do not want to perform proxyAuthz
2300 * on behalf of the client, because this would
2301 * be performed with "proxyauthzdn" privileges.
2303 * This might actually be too strict, since
2304 * the "proxyauthzdn" authzTo, and each entry's
2305 * authzFrom attributes may be crafted
2306 * to avoid unwanted proxyAuthz to take place.
2309 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
2310 rs
->sr_text
= "proxyAuthz not allowed within namingContext";
2315 if ( !BER_BVISNULL( bound_ndn
) ) {
2319 if ( BER_BVISNULL( &ndn
) ) {
2323 if ( BER_BVISNULL( &si
->si_bc
.sb_binddn
) ) {
2327 } else if ( si
->si_bc
.sb_method
== LDAP_AUTH_SASL
) {
2328 if ( ( si
->si_flags
& LDAP_BACK_AUTH_NATIVE_AUTHZ
) )
2330 /* already asserted in SASL via native authz */
2334 } else if ( si
->si_authz
&& !isroot
) {
2336 struct berval authcDN
;
2338 if ( BER_BVISNULL( &ndn
) ) {
2339 authcDN
= slap_empty_bv
;
2343 rc
= slap_sasl_matches( op
, si
->si_authz
,
2344 &authcDN
, &authcDN
);
2345 if ( rc
!= LDAP_SUCCESS
) {
2346 if ( si
->si_flags
& LDAP_BACK_AUTH_PRESCRIPTIVE
) {
2347 /* ndn is not authorized
2348 * to use idassert */
2355 if ( op
->o_proxy_authz
) {
2358 * 1) ignore the already set proxyAuthz control
2359 * 2) leave it in place, and don't set ours
2361 * 4) reject the operation
2363 * option (4) is very drastic
2364 * option (3) will make the remote server reject
2365 * the operation, thus being equivalent to (4)
2366 * option (2) will likely break the idassert
2367 * assumptions, so we cannot accept it;
2368 * option (1) means that we are contradicting
2369 * the client's reques.
2371 * I think (4) is the only correct choice.
2373 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
2374 rs
->sr_text
= "proxyAuthz not allowed within namingContext";
2377 if ( op
->o_is_auth_check
) {
2378 mode
= LDAP_BACK_IDASSERT_NOASSERT
;
2385 case LDAP_BACK_IDASSERT_LEGACY
:
2386 /* original behavior:
2387 * assert the client's identity */
2388 case LDAP_BACK_IDASSERT_SELF
:
2392 case LDAP_BACK_IDASSERT_ANONYMOUS
:
2393 /* assert "anonymous" */
2394 assertedID
= slap_empty_bv
;
2397 case LDAP_BACK_IDASSERT_NOASSERT
:
2398 /* don't assert; bind as proxyauthzdn */
2401 case LDAP_BACK_IDASSERT_OTHERID
:
2402 case LDAP_BACK_IDASSERT_OTHERDN
:
2403 /* assert idassert DN */
2404 assertedID
= si
->si_bc
.sb_authzId
;
2411 /* if we got here, "" is allowed to proxyAuthz */
2412 if ( BER_BVISNULL( &assertedID
) ) {
2413 assertedID
= slap_empty_bv
;
2416 /* don't idassert the bound DN (ITS#4497) */
2417 if ( dn_match( &assertedID
, bound_ndn
) ) {
2421 ctrl
->ldctl_oid
= LDAP_CONTROL_PROXY_AUTHZ
;
2423 switch ( si
->si_mode
) {
2424 /* already in u:ID or dn:DN form */
2425 case LDAP_BACK_IDASSERT_OTHERID
:
2426 case LDAP_BACK_IDASSERT_OTHERDN
:
2427 ber_dupbv_x( &ctrl
->ldctl_value
, &assertedID
, op
->o_tmpmemctx
);
2428 rs
->sr_err
= LDAP_SUCCESS
;
2431 /* needs the dn: prefix */
2433 ctrl
->ldctl_value
.bv_len
= assertedID
.bv_len
+ STRLENOF( "dn:" );
2434 ctrl
->ldctl_value
.bv_val
= op
->o_tmpalloc( ctrl
->ldctl_value
.bv_len
+ 1,
2436 AC_MEMCPY( ctrl
->ldctl_value
.bv_val
, "dn:", STRLENOF( "dn:" ) );
2437 AC_MEMCPY( &ctrl
->ldctl_value
.bv_val
[ STRLENOF( "dn:" ) ],
2438 assertedID
.bv_val
, assertedID
.bv_len
+ 1 );
2439 rs
->sr_err
= LDAP_SUCCESS
;
2443 /* Older versions of <draft-weltman-ldapv3-proxy> required
2444 * to encode the value of the authzID (and called it proxyDN);
2445 * this hack provides compatibility with those DSAs that
2446 * implement it this way */
2447 if ( si
->si_flags
& LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND
) {
2448 struct berval authzID
= ctrl
->ldctl_value
;
2449 BerElementBuffer berbuf
;
2450 BerElement
*ber
= (BerElement
*)&berbuf
;
2453 ber_init2( ber
, 0, LBER_USE_DER
);
2454 ber_set_option( ber
, LBER_OPT_BER_MEMCTX
, &op
->o_tmpmemctx
);
2456 tag
= ber_printf( ber
, "O", &authzID
);
2457 if ( tag
== LBER_ERROR
) {
2458 rs
->sr_err
= LDAP_OTHER
;
2462 if ( ber_flatten2( ber
, &ctrl
->ldctl_value
, 1 ) == -1 ) {
2463 rs
->sr_err
= LDAP_OTHER
;
2467 rs
->sr_err
= LDAP_SUCCESS
;
2470 op
->o_tmpfree( authzID
.bv_val
, op
->o_tmpmemctx
);
2471 ber_free_buf( ber
);
2473 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
2477 } else if ( si
->si_flags
& LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ
) {
2478 struct berval authzID
= ctrl
->ldctl_value
,
2480 BerElementBuffer berbuf
;
2481 BerElement
*ber
= (BerElement
*)&berbuf
;
2484 if ( strncasecmp( authzID
.bv_val
, "dn:", STRLENOF( "dn:" ) ) != 0 ) {
2485 rs
->sr_err
= LDAP_PROTOCOL_ERROR
;
2490 tmp
.bv_val
+= STRLENOF( "dn:" );
2491 tmp
.bv_len
-= STRLENOF( "dn:" );
2493 ber_init2( ber
, 0, LBER_USE_DER
);
2494 ber_set_option( ber
, LBER_OPT_BER_MEMCTX
, &op
->o_tmpmemctx
);
2496 /* apparently, Mozilla API encodes this
2497 * as "SEQUENCE { LDAPDN }" */
2498 tag
= ber_printf( ber
, "{O}", &tmp
);
2499 if ( tag
== LBER_ERROR
) {
2500 rs
->sr_err
= LDAP_OTHER
;
2504 if ( ber_flatten2( ber
, &ctrl
->ldctl_value
, 1 ) == -1 ) {
2505 rs
->sr_err
= LDAP_OTHER
;
2509 ctrl
->ldctl_oid
= LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ
;
2510 rs
->sr_err
= LDAP_SUCCESS
;
2513 op
->o_tmpfree( authzID
.bv_val
, op
->o_tmpmemctx
);
2514 ber_free_buf( ber
);
2516 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
2529 * if any needs to be added, it is prepended to existing ones,
2530 * in a newly allocated array. The companion function
2531 * ldap_back_controls_free() must be used to restore the original
2532 * status of op->o_ctrls.
2535 ldap_back_controls_add(
2539 LDAPControl
***pctrls
)
2541 ldapinfo_t
*li
= (ldapinfo_t
*)op
->o_bd
->be_private
;
2543 LDAPControl
**ctrls
= NULL
;
2544 /* set to the maximum number of controls this backend can add */
2545 LDAPControl c
[ 2 ] = { { 0 } };
2546 int n
= 0, i
, j1
= 0, j2
= 0;
2550 rs
->sr_err
= LDAP_SUCCESS
;
2552 /* don't add controls if protocol is not LDAPv3 */
2553 switch ( li
->li_version
) {
2558 if ( op
->o_protocol
== 0 || op
->o_protocol
== LDAP_VERSION3
) {
2567 /* put controls that go __before__ existing ones here */
2569 /* proxyAuthz for identity assertion */
2570 switch ( ldap_back_proxy_authz_ctrl( op
, rs
, &lc
->lc_bound_ndn
,
2571 li
->li_version
, &li
->li_idassert
, &c
[ j1
] ) )
2573 case SLAP_CB_CONTINUE
:
2584 /* put controls that go __after__ existing ones here */
2586 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
2587 /* FIXME: according to <draft-wahl-ldap-session>,
2588 * the server should check if the control can be added
2589 * based on the identity of the client and so */
2591 /* session tracking */
2592 if ( LDAP_BACK_ST_REQUEST( li
) ) {
2593 switch ( slap_ctrl_session_tracking_request_add( op
, rs
, &c
[ j1
+ j2
] ) ) {
2594 case SLAP_CB_CONTINUE
:
2605 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
2607 if ( rs
->sr_err
== SLAP_CB_CONTINUE
) {
2608 rs
->sr_err
= LDAP_SUCCESS
;
2611 /* if nothing to do, just bail out */
2612 if ( j1
== 0 && j2
== 0 ) {
2616 assert( j1
+ j1
<= sizeof( c
)/sizeof(LDAPControl
) );
2618 if ( op
->o_ctrls
) {
2619 for ( n
= 0; op
->o_ctrls
[ n
]; n
++ )
2620 /* just count ctrls */ ;
2623 ctrls
= op
->o_tmpalloc( (n
+ j1
+ j2
+ 1) * sizeof( LDAPControl
* ) + ( j1
+ j2
) * sizeof( LDAPControl
),
2626 ctrls
[ 0 ] = (LDAPControl
*)&ctrls
[ n
+ j1
+ j2
+ 1 ];
2627 *ctrls
[ 0 ] = c
[ 0 ];
2628 for ( i
= 1; i
< j1
; i
++ ) {
2629 ctrls
[ i
] = &ctrls
[ 0 ][ i
];
2630 *ctrls
[ i
] = c
[ i
];
2635 if ( op
->o_ctrls
) {
2636 for ( i
= 0; op
->o_ctrls
[ i
]; i
++ ) {
2637 ctrls
[ i
+ j1
] = op
->o_ctrls
[ i
];
2643 ctrls
[ n
] = (LDAPControl
*)&ctrls
[ n
+ j2
+ 1 ] + j1
;
2644 *ctrls
[ n
] = c
[ j1
];
2645 for ( i
= 1; i
< j2
; i
++ ) {
2646 ctrls
[ n
+ i
] = &ctrls
[ n
][ i
];
2647 *ctrls
[ n
+ i
] = c
[ i
];
2651 ctrls
[ n
+ j2
] = NULL
;
2654 if ( ctrls
== NULL
) {
2655 ctrls
= op
->o_ctrls
;
2664 ldap_back_controls_free( Operation
*op
, SlapReply
*rs
, LDAPControl
***pctrls
)
2666 LDAPControl
**ctrls
= *pctrls
;
2668 /* we assume that the controls added by the proxy come first,
2669 * so as soon as we find op->o_ctrls[ 0 ] we can stop */
2670 if ( ctrls
&& ctrls
!= op
->o_ctrls
) {
2671 int i
= 0, n
= 0, n_added
;
2672 LDAPControl
*lower
, *upper
;
2674 assert( ctrls
[ 0 ] != NULL
);
2676 for ( n
= 0; ctrls
[ n
] != NULL
; n
++ )
2679 if ( op
->o_ctrls
) {
2680 for ( i
= 0; op
->o_ctrls
[ i
] != NULL
; i
++ )
2685 lower
= (LDAPControl
*)&ctrls
[ n
];
2686 upper
= &lower
[ n_added
];
2688 for ( i
= 0; ctrls
[ i
] != NULL
; i
++ ) {
2689 if ( ctrls
[ i
] < lower
|| ctrls
[ i
] >= upper
) {
2690 /* original; don't touch */
2694 if ( !BER_BVISNULL( &ctrls
[ i
]->ldctl_value
) ) {
2695 op
->o_tmpfree( ctrls
[ i
]->ldctl_value
.bv_val
, op
->o_tmpmemctx
);
2699 op
->o_tmpfree( ctrls
, op
->o_tmpmemctx
);