1 /* bind.c - ldap backend bind function */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1999-2006 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( Operation *op, 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 **lcp, Operation *op, SlapReply *rs,
131 ldap_back_send_t sendok );
134 ldap_back_conndnlc_cmp( const void *c1, const void *c2 );
137 ldap_back_bind( Operation *op, SlapReply *rs )
139 ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
144 ldap_back_send_t retrying = LDAP_BACK_RETRYING;
146 lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );
151 /* we can do (almost) whatever we want with this conn,
152 * because either it's temporary, or it's marked as binding */
153 if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
154 ch_free( lc->lc_bound_ndn.bv_val );
155 BER_BVZERO( &lc->lc_bound_ndn );
157 if ( !BER_BVISNULL( &lc->lc_cred ) ) {
158 memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len );
159 ch_free( lc->lc_cred.bv_val );
160 BER_BVZERO( &lc->lc_cred );
162 LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
165 /* method is always LDAP_AUTH_SIMPLE if we got here */
166 rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
168 &op->orb_cred, op->o_ctrls, NULL, &msgid );
169 /* FIXME: should we always retry, or only when piping the bind
170 * in the "override" connection pool? */
171 rc = ldap_back_op_result( lc, op, rs, msgid,
172 li->li_timeout[ SLAP_OP_BIND ],
173 LDAP_BACK_BIND_SERR | retrying );
174 if ( rc == LDAP_UNAVAILABLE && retrying ) {
175 retrying &= ~LDAP_BACK_RETRYING;
176 if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_BIND_SERR ) ) {
181 if ( rc == LDAP_SUCCESS ) {
182 /* If defined, proxyAuthz will be used also when
183 * back-ldap is the authorizing backend; for this
184 * purpose, after a successful bind the connection
185 * is left for further binds, and further operations
186 * on this client connection will use a default
187 * connection with identity assertion */
188 /* NOTE: use with care */
189 if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
190 assert( lc->lc_binding == 1 );
192 ldap_back_release_conn( op, rs, lc );
196 /* rebind is now done inside ldap_back_proxy_authz_bind()
197 * in case of success */
198 LDAP_BACK_CONN_ISBOUND_SET( lc );
199 ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
201 if ( !BER_BVISNULL( &lc->lc_cred ) ) {
202 memset( lc->lc_cred.bv_val, 0,
203 lc->lc_cred.bv_len );
206 if ( LDAP_BACK_SAVECRED( li ) ) {
207 ber_bvreplace( &lc->lc_cred, &op->orb_cred );
208 ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
211 lc->lc_cred.bv_len = 0;
215 assert( lc->lc_binding == 1 );
218 /* must re-insert if local DN changed as result of bind */
219 if ( !LDAP_BACK_CONN_ISBOUND( lc )
220 || ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )
221 && !LDAP_BACK_PCONN_ISPRIV( lc ) ) )
226 /* wait for all other ops to release the connection */
228 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
229 if ( lc->lc_refcnt > 1 ) {
230 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
231 ldap_pvt_thread_yield();
235 #if LDAP_BACK_PRINT_CONNTREE > 0
236 ldap_back_print_conntree( li, ">>> ldap_back_bind" );
237 #endif /* LDAP_BACK_PRINT_CONNTREE */
239 assert( lc->lc_refcnt == 1 );
240 if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
241 /* this can happen, for example, if the bind fails
242 * for some reason... */
243 if ( lc->lc_q.tqe_prev != NULL ) {
244 assert( LDAP_BACK_CONN_CACHED( lc ) );
245 assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
246 LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
247 li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
248 lc->lc_q.tqe_prev = NULL;
249 lc->lc_q.tqe_next = NULL;
252 assert( !LDAP_BACK_CONN_CACHED( lc ) );
256 tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
257 ldap_back_conndnlc_cmp );
258 assert( ( LDAP_BACK_CONN_TAINTED( lc ) && tmplc == NULL ) || lc == tmplc );
260 LDAP_BACK_CONN_CACHED_CLEAR( lc );
262 /* delete all cached connections with the current connection */
263 if ( LDAP_BACK_SINGLECONN( li ) ) {
264 while ( ( tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )
266 Debug( LDAP_DEBUG_TRACE,
267 "=>ldap_back_bind: destroying conn %ld (refcnt=%u)\n",
268 LDAP_BACK_PCONN_ID( lc ), lc->lc_refcnt, 0 );
270 if ( tmplc->lc_refcnt != 0 ) {
272 LDAP_BACK_CONN_TAINTED_SET( tmplc );
273 LDAP_BACK_CONN_CACHED_CLEAR( tmplc );
277 * Needs a test because the handler may be corrupted,
278 * and calling ldap_unbind on a corrupted header results
279 * in a segmentation fault
281 ldap_back_conn_free( tmplc );
286 if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
287 ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
288 if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
289 LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
291 lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
292 ldap_back_conndn_cmp, ldap_back_conndn_dup );
295 #if LDAP_BACK_PRINT_CONNTREE > 0
296 ldap_back_print_conntree( li, "<<< ldap_back_bind" );
297 #endif /* LDAP_BACK_PRINT_CONNTREE */
299 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
302 LDAP_BACK_CONN_CACHED_SET( lc );
306 /* duplicate; someone else successfully bound
307 * on the same connection with the same identity;
308 * we can do this because lc_refcnt == 1 */
309 ldap_back_conn_free( lc );
315 ldap_back_release_conn( op, rs, lc );
322 * ldap_back_conndn_cmp
324 * compares two ldapconn_t based on the value of the conn pointer
325 * and of the local DN; used by avl stuff for insert, lookup
329 ldap_back_conndn_cmp( const void *c1, const void *c2 )
331 const ldapconn_t *lc1 = (const ldapconn_t *)c1;
332 const ldapconn_t *lc2 = (const ldapconn_t *)c2;
335 /* If local DNs don't match, it is definitely not a match */
336 /* For shared sessions, conn is NULL. Only explicitly
337 * bound sessions will have non-NULL conn.
339 rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
341 rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
348 * ldap_back_conndnlc_cmp
350 * compares two ldapconn_t based on the value of the conn pointer,
351 * the local DN and the lc pointer; used by avl stuff for insert, lookup
355 ldap_back_conndnlc_cmp( const void *c1, const void *c2 )
357 const ldapconn_t *lc1 = (const ldapconn_t *)c1;
358 const ldapconn_t *lc2 = (const ldapconn_t *)c2;
361 /* If local DNs don't match, it is definitely not a match */
362 /* For shared sessions, conn is NULL. Only explicitly
363 * bound sessions will have non-NULL conn.
365 rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
367 rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
369 rc = SLAP_PTRCMP( lc1, lc2 );
379 * compares two ldapconn_t based on the value of the conn pointer;
380 * used by avl stuff for delete of all conns with the same connid
383 ldap_back_conn_cmp( const void *c1, const void *c2 )
385 const ldapconn_t *lc1 = (const ldapconn_t *)c1;
386 const ldapconn_t *lc2 = (const ldapconn_t *)c2;
388 /* For shared sessions, conn is NULL. Only explicitly
389 * bound sessions will have non-NULL conn.
391 return SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
395 * ldap_back_conndn_dup
397 * returns -1 in case a duplicate ldapconn_t has been inserted;
401 ldap_back_conndn_dup( void *c1, void *c2 )
403 ldapconn_t *lc1 = (ldapconn_t *)c1;
404 ldapconn_t *lc2 = (ldapconn_t *)c2;
406 /* Cannot have more than one shared session with same DN */
407 if ( lc1->lc_conn == lc2->lc_conn &&
408 dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) )
417 ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock )
419 ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
422 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
425 #if LDAP_BACK_PRINT_CONNTREE > 0
426 ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );
427 #endif /* LDAP_BACK_PRINT_CONNTREE */
429 if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
430 if ( lc->lc_q.tqe_prev != NULL ) {
431 assert( LDAP_BACK_CONN_CACHED( lc ) );
432 assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
433 li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
434 LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
435 LDAP_BACK_CONN_CACHED_CLEAR( lc );
438 assert( !LDAP_BACK_CONN_CACHED( lc ) );
440 lc->lc_q.tqe_prev = NULL;
441 lc->lc_q.tqe_next = NULL;
444 ldapconn_t *tmplc = NULL;
446 if ( LDAP_BACK_CONN_CACHED( lc ) ) {
447 tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
448 ldap_back_conndnlc_cmp );
449 assert( tmplc == lc );
450 LDAP_BACK_CONN_CACHED_CLEAR( lc );
452 assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
455 if ( lc->lc_refcnt == 0 ) {
456 ldap_back_conn_free( (void *)lc );
459 #if LDAP_BACK_PRINT_CONNTREE > 0
460 ldap_back_print_conntree( li, "<<< ldap_back_freeconn" );
461 #endif /* LDAP_BACK_PRINT_CONNTREE */
464 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
481 int rc = LDAP_SUCCESS;
483 /* start TLS ("tls-[try-]{start,propagate}" statements) */
484 if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )
485 && !ldap_is_ldaps_url( url ) )
487 #ifdef SLAP_STARTTLS_ASYNCHRONOUS
489 * use asynchronous StartTLS
490 * in case, chase referral (not implemented yet)
494 if ( protocol == 0 ) {
495 ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION,
499 if ( protocol < LDAP_VERSION3 ) {
500 /* we should rather bail out... */
501 rc = LDAP_UNWILLING_TO_PERFORM;
502 *text = "invalid protocol version";
505 if ( rc == LDAP_SUCCESS ) {
506 rc = ldap_start_tls( ld, NULL, NULL, &msgid );
509 if ( rc == LDAP_SUCCESS ) {
510 LDAPMessage *res = NULL;
513 LDAP_BACK_TV_SET( &tv );
516 rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
518 rc = LDAP_UNAVAILABLE;
520 } else if ( rc == 0 ) {
521 if ( retries != LDAP_BACK_RETRY_NEVER ) {
522 ldap_pvt_thread_yield();
526 LDAP_BACK_TV_SET( &tv );
529 rc = LDAP_UNAVAILABLE;
531 } else if ( rc == LDAP_RES_EXTENDED ) {
532 struct berval *data = NULL;
534 rc = ldap_parse_extended_result( ld, res,
536 if ( rc == LDAP_SUCCESS ) {
538 rc = ldap_parse_result( ld, res, &err,
539 NULL, NULL, NULL, NULL, 1 );
540 if ( rc == LDAP_SUCCESS ) {
545 /* FIXME: in case a referral
546 * is returned, should we try
547 * using it instead of the
549 if ( rc == LDAP_SUCCESS ) {
550 rc = ldap_install_tls( ld );
552 } else if ( rc == LDAP_REFERRAL ) {
553 rc = LDAP_UNWILLING_TO_PERFORM;
554 *text = "unwilling to chase referral returned by Start TLS exop";
558 if ( data->bv_val ) {
559 ber_memfree( data->bv_val );
573 #else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
575 * use synchronous StartTLS
577 rc = ldap_start_tls_s( ld, NULL, NULL );
578 #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
580 /* if StartTLS is requested, only attempt it if the URL
581 * is not "ldaps://"; this may occur not only in case
582 * of misconfiguration, but also when used in the chain
583 * overlay, where the "uri" can be parsed out of a referral */
589 case LDAP_SERVER_DOWN:
593 if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
594 *text = "could not start TLS";
598 /* in case Start TLS is not critical */
610 #endif /* HAVE_TLS */
613 ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
615 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
619 int is_tls = op->o_conn->c_is_tls;
620 time_t lc_time = (time_t)(-1);
621 #endif /* HAVE_TLS */
623 assert( lcp != NULL );
625 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
626 rs->sr_err = ldap_initialize( &ld, li->li_uri );
627 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
628 if ( rs->sr_err != LDAP_SUCCESS ) {
632 if ( li->li_urllist_f ) {
633 ldap_set_urllist_proc( ld, li->li_urllist_f, li->li_urllist_p );
636 /* Set LDAP version. This will always succeed: If the client
637 * bound with a particular version, then so can we.
639 if ( li->li_version != 0 ) {
640 version = li->li_version;
642 } else if ( op->o_protocol != 0 ) {
643 version = op->o_protocol;
646 /* assume it's an internal op; set to LDAPv3 */
647 version = LDAP_VERSION3;
649 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version );
651 /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
652 ldap_set_option( ld, LDAP_OPT_REFERRALS,
653 LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
655 if ( li->li_network_timeout > 0 ) {
658 tv.tv_sec = li->li_network_timeout;
660 ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&tv );
664 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
665 rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
666 li->li_uri, li->li_flags, li->li_nretries, &rs->sr_text );
667 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
668 if ( rs->sr_err != LDAP_SUCCESS ) {
669 ldap_unbind_ext( ld, NULL, NULL );
672 } else if ( li->li_idle_timeout ) {
673 /* only touch when activity actually took place... */
674 lc_time = op->o_time;
676 #endif /* HAVE_TLS */
678 if ( *lcp == NULL ) {
679 *lcp = (ldapconn_t *)ch_calloc( 1, sizeof( ldapconn_t ) );
680 (*lcp)->lc_flags = li->li_flags;
683 (*lcp)->lc_refcnt = 1;
684 (*lcp)->lc_binding = 1;
687 LDAP_BACK_CONN_ISTLS_SET( *lcp );
689 LDAP_BACK_CONN_ISTLS_CLEAR( *lcp );
691 if ( lc_time != (time_t)(-1) ) {
692 (*lcp)->lc_time = lc_time;
694 #endif /* HAVE_TLS */
697 if ( rs->sr_err != LDAP_SUCCESS ) {
698 rs->sr_err = slap_map_api2result( rs );
699 if ( sendok & LDAP_BACK_SENDERR ) {
700 if ( rs->sr_text == NULL ) {
701 rs->sr_text = "ldap_initialize() failed";
703 send_ldap_result( op, rs );
708 if ( li->li_conn_ttl > 0 ) {
709 (*lcp)->lc_create_time = op->o_time;
720 ldap_back_send_t sendok,
721 struct berval *binddn,
722 struct berval *bindcred )
724 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
725 ldapconn_t *lc = NULL,
729 lookupconn = !( sendok & LDAP_BACK_BINDING );
731 /* if the server is quarantined, and
732 * - the current interval did not expire yet, or
733 * - no more retries should occur,
734 * don't return the connection */
735 if ( li->li_isquarantined ) {
736 slap_retry_info_t *ri = &li->li_quarantine;
739 if ( li->li_quarantine.ri_interval ) {
740 ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
741 if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) {
742 dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
743 || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
745 Debug( LDAP_DEBUG_ANY,
746 "%s: ldap_back_getconn quarantine "
747 "retry block #%d try #%d.\n",
748 op->o_log_prefix, ri->ri_idx, ri->ri_count );
749 li->li_isquarantined = LDAP_BACK_FQ_RETRYING;
752 ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
756 rs->sr_err = LDAP_UNAVAILABLE;
757 if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
758 send_ldap_result( op, rs );
764 /* Internal searches are privileged and shared. So is root. */
765 if ( op->o_do_not_cache || be_isroot( op ) ) {
766 LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
767 lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
768 LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
771 struct berval tmpbinddn,
778 if ( binddn == NULL ) {
781 if ( bindcred == NULL ) {
782 bindcred = &tmpbindcred;
784 if ( op->o_tag == LDAP_REQ_BIND ) {
785 save_o_dn = op->o_dn;
786 save_o_ndn = op->o_ndn;
787 op->o_dn = op->o_req_dn;
788 op->o_ndn = op->o_req_ndn;
790 isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred );
791 if ( isproxyauthz == -1 ) {
794 if ( op->o_tag == LDAP_REQ_BIND ) {
795 op->o_dn = save_o_dn;
796 op->o_ndn = save_o_ndn;
799 lc_curr.lc_local_ndn = op->o_ndn;
800 /* Explicit binds must not be shared;
801 * however, explicit binds are piped in a special connection
802 * when idassert is to occur with "override" set */
803 if ( op->o_tag == LDAP_REQ_BIND && !isproxyauthz ) {
804 lc_curr.lc_conn = op->o_conn;
807 if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
808 lc_curr.lc_local_ndn = *binddn;
809 LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
810 LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
812 } else if ( isproxyauthz && ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) {
813 lc_curr.lc_local_ndn = slap_empty_bv;
814 LDAP_BACK_PCONN_BIND_SET( &lc_curr, op );
815 LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
818 } else if ( SLAP_IS_AUTHZ_BACKEND( op ) ) {
819 lc_curr.lc_conn = op->o_conn;
822 LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
827 /* Explicit Bind requests always get their own conn */
830 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
831 if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr ) ) {
832 /* lookup a conn that's not binding */
833 LDAP_TAILQ_FOREACH( lc,
834 &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv,
837 if ( !LDAP_BACK_CONN_BINDING( lc ) && lc->lc_refcnt == 0 ) {
843 if ( lc != LDAP_TAILQ_LAST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
846 LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
848 lc->lc_q.tqe_prev = NULL;
849 lc->lc_q.tqe_next = NULL;
850 LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
854 } else if ( !LDAP_BACK_USE_TEMPORARIES( li )
855 && li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_num == li->li_conn_priv_max )
857 lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv );
862 /* Searches for a ldapconn in the avl tree */
863 lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
864 (caddr_t)&lc_curr, ldap_back_conndn_cmp );
868 /* Don't reuse connections while they're still binding */
869 if ( LDAP_BACK_CONN_BINDING( lc ) ) {
870 if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) {
871 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
873 ldap_pvt_thread_yield();
880 if ( op->o_tag == LDAP_REQ_BIND ) {
881 /* right now, this is the only possible case */
882 assert( ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) );
883 LDAP_BACK_CONN_BINDING_SET( lc );
886 refcnt = ++lc->lc_refcnt;
887 binding = ++lc->lc_binding;
890 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
893 /* Looks like we didn't get a bind. Open a new session... */
895 if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) {
899 if ( sendok & LDAP_BACK_BINDING ) {
900 LDAP_BACK_CONN_BINDING_SET( lc );
903 lc->lc_conn = lc_curr.lc_conn;
904 ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn );
907 * the rationale is: connections as the rootdn are privileged,
908 * so acl_authcDN is to be used; however, in some cases
909 * one already configured identity assertion with a highly
910 * privileged idassert_authcDN, so if acl_authcDN is NULL
911 * and idassert_authcDN is not, use the second instead.
913 * might change in the future, because it's preferable
914 * to make clear what identity is being used, since
915 * the only drawback is that one risks to configure
916 * the same identity twice...
918 if ( LDAP_BACK_CONN_ISPRIV( &lc_curr ) ) {
919 if ( BER_BVISNULL( &li->li_acl_authcDN ) && !BER_BVISNULL( &li->li_idassert_authcDN ) ) {
920 ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
921 ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
924 ber_dupbv( &lc->lc_bound_ndn, &li->li_acl_authcDN );
925 ber_dupbv( &lc->lc_cred, &li->li_acl_passwd );
927 LDAP_BACK_CONN_ISPRIV_SET( lc );
929 } else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr ) ) {
930 if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr ) ) {
931 ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
932 ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
934 LDAP_BACK_CONN_ISIDASSERT_SET( lc );
937 BER_BVZERO( &lc->lc_cred );
938 BER_BVZERO( &lc->lc_bound_ndn );
939 if ( !BER_BVISEMPTY( &op->o_ndn )
940 && SLAP_IS_AUTHZ_BACKEND( op ) )
942 ber_dupbv( &lc->lc_bound_ndn, &op->o_ndn );
947 /* if start TLS failed but it was not mandatory,
948 * check if the non-TLS connection was already
949 * in cache; in case, destroy the newly created
950 * connection and use the existing one */
951 if ( LDAP_BACK_PCONN_ISTLS( lc )
952 && !ldap_tls_inplace( lc->lc_ld ) )
954 ldapconn_t *tmplc = NULL;
955 int idx = LDAP_BACK_CONN2PRIV( &lc_curr ) - 1;
957 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
958 LDAP_TAILQ_FOREACH( tmplc,
959 &li->li_conn_priv[ idx ].lic_priv,
962 if ( !LDAP_BACK_CONN_BINDING( tmplc ) ) {
967 if ( tmplc != NULL ) {
968 refcnt = ++tmplc->lc_refcnt;
969 binding = ++tmplc->lc_binding;
970 ldap_back_conn_free( lc );
973 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
975 if ( tmplc != NULL ) {
979 #endif /* HAVE_TLS */
981 /* Inserts the newly created ldapconn in the avl tree */
982 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
984 LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
986 assert( lc->lc_refcnt == 1 );
987 assert( lc->lc_binding == 1 );
989 #if LDAP_BACK_PRINT_CONNTREE > 0
990 ldap_back_print_conntree( li, ">>> ldap_back_getconn(insert)" );
991 #endif /* LDAP_BACK_PRINT_CONNTREE */
993 if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
994 if ( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num < li->li_conn_priv_max ) {
995 LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
996 li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num++;
997 LDAP_BACK_CONN_CACHED_SET( lc );
1000 LDAP_BACK_CONN_TAINTED_SET( lc );
1005 rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
1006 ldap_back_conndn_cmp, ldap_back_conndn_dup );
1007 LDAP_BACK_CONN_CACHED_SET( lc );
1010 #if LDAP_BACK_PRINT_CONNTREE > 0
1011 ldap_back_print_conntree( li, "<<< ldap_back_getconn(insert)" );
1012 #endif /* LDAP_BACK_PRINT_CONNTREE */
1014 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1016 if ( LogTest( LDAP_DEBUG_TRACE ) ) {
1017 char buf[ SLAP_TEXT_BUFLEN ];
1019 snprintf( buf, sizeof( buf ),
1020 "lc=%p inserted refcnt=%u binding=%u rc=%d",
1021 (void *)lc, refcnt, binding, rs->sr_err );
1023 Debug( LDAP_DEBUG_TRACE,
1024 "=>ldap_back_getconn: %s: %s\n",
1025 op->o_log_prefix, buf, 0 );
1028 if ( !LDAP_BACK_PCONN_ISPRIV( lc ) ) {
1029 /* Err could be -1 in case a duplicate ldapconn is inserted */
1030 switch ( rs->sr_err ) {
1035 LDAP_BACK_CONN_CACHED_CLEAR( lc );
1036 if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) {
1037 /* duplicate: free and try to get the newly created one */
1038 ldap_back_conn_free( lc );
1043 /* taint connection, so that it'll be freed when released */
1044 LDAP_BACK_CONN_TAINTED_SET( lc );
1048 LDAP_BACK_CONN_CACHED_CLEAR( lc );
1049 ldap_back_conn_free( lc );
1050 rs->sr_err = LDAP_OTHER;
1051 rs->sr_text = "proxy bind collision";
1052 if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
1053 send_ldap_result( op, rs );
1063 if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout )
1064 || ( li->li_conn_ttl != 0 && op->o_time > lc->lc_create_time + li->li_conn_ttl ) )
1068 /* let it be used, but taint/delete it so that
1069 * no-one else can look it up any further */
1070 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1072 #if LDAP_BACK_PRINT_CONNTREE > 0
1073 ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
1074 #endif /* LDAP_BACK_PRINT_CONNTREE */
1076 if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
1077 if ( lc->lc_q.tqe_prev != NULL ) {
1078 assert( LDAP_BACK_CONN_CACHED( lc ) );
1079 assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
1080 LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
1082 li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
1083 lc->lc_q.tqe_prev = NULL;
1084 lc->lc_q.tqe_next = NULL;
1087 assert( !LDAP_BACK_CONN_CACHED( lc ) );
1091 (void)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
1092 ldap_back_conndnlc_cmp );
1094 LDAP_BACK_CONN_TAINTED_SET( lc );
1095 LDAP_BACK_CONN_CACHED_CLEAR( lc );
1097 #if LDAP_BACK_PRINT_CONNTREE > 0
1098 ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
1099 #endif /* LDAP_BACK_PRINT_CONNTREE */
1101 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1104 if ( LogTest( LDAP_DEBUG_TRACE ) ) {
1105 char buf[ SLAP_TEXT_BUFLEN ];
1107 snprintf( buf, sizeof( buf ),
1108 "conn %p fetched refcnt=%u binding=%u%s",
1109 (void *)lc, refcnt, binding, expiring ? " expiring" : "" );
1110 Debug( LDAP_DEBUG_TRACE,
1111 "=>ldap_back_getconn: %s.\n", buf, 0, 0 );
1117 #endif /* HAVE_TLS */
1123 ldap_back_release_conn_lock(
1129 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
1131 ldapconn_t *lc = *lcp;
1134 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1136 assert( lc->lc_refcnt > 0 );
1137 LDAP_BACK_CONN_BINDING_CLEAR( lc );
1139 if ( LDAP_BACK_CONN_TAINTED( lc ) ) {
1140 ldap_back_freeconn( op, lc, 0 );
1144 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1149 ldap_back_quarantine(
1153 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
1155 slap_retry_info_t *ri = &li->li_quarantine;
1157 ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
1159 if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1160 time_t new_last = slap_get_time();
1162 switch ( li->li_isquarantined ) {
1163 case LDAP_BACK_FQ_NO:
1164 if ( ri->ri_last == new_last ) {
1168 Debug( LDAP_DEBUG_ANY,
1169 "%s: ldap_back_quarantine enter.\n",
1170 op->o_log_prefix, 0, 0 );
1176 case LDAP_BACK_FQ_RETRYING:
1177 Debug( LDAP_DEBUG_ANY,
1178 "%s: ldap_back_quarantine block #%d try #%d failed.\n",
1179 op->o_log_prefix, ri->ri_idx, ri->ri_count );
1182 if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER
1183 && ri->ri_count == ri->ri_num[ ri->ri_idx ] )
1194 li->li_isquarantined = LDAP_BACK_FQ_YES;
1195 ri->ri_last = new_last;
1197 } else if ( li->li_isquarantined != LDAP_BACK_FQ_NO ) {
1198 if ( ri->ri_last == slap_get_time() ) {
1202 Debug( LDAP_DEBUG_ANY,
1203 "%s: ldap_back_quarantine exit (%d) err=%d.\n",
1204 op->o_log_prefix, li->li_isquarantined, rs->sr_err );
1206 if ( li->li_quarantine_f ) {
1207 (void)li->li_quarantine_f( li, li->li_quarantine_p );
1212 li->li_isquarantined = LDAP_BACK_FQ_NO;
1216 ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
1220 * ldap_back_dobind_int
1222 * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
1225 ldap_back_dobind_int(
1229 ldap_back_send_t sendok,
1233 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
1236 struct berval binddn = slap_empty_bv,
1237 bindcred = slap_empty_bv;
1244 assert( lcp != NULL );
1245 assert( retries >= 0 );
1247 if ( sendok & LDAP_BACK_GETCONN ) {
1248 assert( *lcp == NULL );
1250 lc = ldap_back_getconn( op, rs, sendok, &binddn, &bindcred );
1260 assert( lc != NULL );
1264 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1267 if ( binding == 0 ) {
1268 /* check if already bound */
1269 rc = isbound = LDAP_BACK_CONN_ISBOUND( lc );
1273 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1278 if ( LDAP_BACK_CONN_BINDING( lc ) ) {
1279 /* if someone else is about to bind it, give up and retry */
1281 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1283 ldap_pvt_thread_yield();
1287 /* otherwise this thread will bind it */
1288 LDAP_BACK_CONN_BINDING_SET( lc );
1293 /* wait for pending operations to finish */
1294 /* FIXME: may become a bottleneck! */
1295 if ( lc->lc_refcnt != lc->lc_binding ) {
1297 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1299 ldap_pvt_thread_yield();
1304 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1308 * FIXME: we need to let clients use proxyAuthz
1309 * otherwise we cannot do symmetric pools of servers;
1310 * we have to live with the fact that a user can
1311 * authorize itself as any ID that is allowed
1312 * by the authzTo directive of the "proxyauthzdn".
1315 * NOTE: current Proxy Authorization specification
1316 * and implementation do not allow proxy authorization
1317 * control to be provided with Bind requests
1320 * if no bind took place yet, but the connection is bound
1321 * and the "idassert-authcDN" (or other ID) is set,
1322 * then bind as the asserting identity and explicitly
1323 * add the proxyAuthz control to every operation with the
1324 * dn bound to the connection as control value.
1325 * This is done also if this is the authrizing backend,
1326 * but the "override" flag is given to idassert.
1327 * It allows to use SASL bind and yet proxyAuthz users
1329 if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) {
1330 if ( BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &bindcred ) ) {
1331 /* if we got here, it shouldn't return result */
1332 rc = ldap_back_is_proxy_authz( op, rs,
1333 LDAP_BACK_DONTSEND, &binddn, &bindcred );
1336 rc = ldap_back_proxy_authz_bind( lc, op, rs, sendok, &binddn, &bindcred );
1340 #ifdef HAVE_CYRUS_SASL
1341 if ( LDAP_BACK_CONN_ISPRIV( lc )
1342 && li->li_acl_authmethod == LDAP_AUTH_SASL )
1344 void *defaults = NULL;
1346 if ( li->li_acl_secprops != NULL ) {
1347 rc = ldap_set_option( lc->lc_ld,
1348 LDAP_OPT_X_SASL_SECPROPS, li->li_acl_secprops );
1350 if ( rc != LDAP_OPT_SUCCESS ) {
1351 Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
1352 "(SECPROPS,\"%s\") failed!\n",
1353 li->li_acl_secprops, 0, 0 );
1358 defaults = lutil_sasl_defaults( lc->lc_ld,
1359 li->li_acl_sasl_mech.bv_val,
1360 li->li_acl_sasl_realm.bv_val,
1361 li->li_acl_authcID.bv_val,
1362 li->li_acl_passwd.bv_val,
1365 rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld,
1366 li->li_acl_authcDN.bv_val,
1367 li->li_acl_sasl_mech.bv_val, NULL, NULL,
1368 LDAP_SASL_QUIET, lutil_sasl_interact,
1371 lutil_sasl_freedefs( defaults );
1373 rs->sr_err = slap_map_api2result( rs );
1374 if ( rs->sr_err != LDAP_SUCCESS ) {
1375 LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
1376 if ( sendok & LDAP_BACK_SENDERR ) {
1377 send_ldap_result( op, rs );
1381 LDAP_BACK_CONN_ISBOUND_SET( lc );
1384 if ( LDAP_BACK_QUARANTINE( li ) ) {
1385 ldap_back_quarantine( op, rs );
1390 #endif /* HAVE_CYRUS_SASL */
1393 rs->sr_err = ldap_sasl_bind( lc->lc_ld,
1394 BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val,
1395 LDAP_SASL_SIMPLE, &lc->lc_cred,
1396 NULL, NULL, &msgid );
1398 if ( rs->sr_err == LDAP_SERVER_DOWN ) {
1399 if ( retries != LDAP_BACK_RETRY_NEVER ) {
1401 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1404 assert( lc->lc_refcnt > 0 );
1405 if ( lc->lc_refcnt == 1 ) {
1406 ldap_unbind_ext( lc->lc_ld, NULL, NULL );
1409 /* lc here must be the regular lc, reset and ready for init */
1410 rs->sr_err = ldap_back_prepare_conn( &lc, op, rs, sendok );
1411 if ( rs->sr_err != LDAP_SUCCESS ) {
1418 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1421 if ( rs->sr_err == LDAP_SUCCESS ) {
1422 if ( retries > 0 ) {
1430 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1434 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1438 /* FIXME: one binding-- too many? */
1440 assert( lc->lc_refcnt == 1 );
1442 ldap_back_freeconn( op, lc, dolock );
1444 rs->sr_err = slap_map_api2result( rs );
1446 if ( LDAP_BACK_QUARANTINE( li ) ) {
1447 ldap_back_quarantine( op, rs );
1450 if ( rs->sr_err != LDAP_SUCCESS &&
1451 ( sendok & LDAP_BACK_SENDERR ) )
1453 send_ldap_result( op, rs );
1459 rc = ldap_back_op_result( lc, op, rs, msgid,
1460 -1, (sendok|LDAP_BACK_BINDING) );
1461 if ( rc == LDAP_SUCCESS ) {
1462 LDAP_BACK_CONN_ISBOUND_SET( lc );
1467 LDAP_BACK_CONN_BINDING_CLEAR( lc );
1468 rc = LDAP_BACK_CONN_ISBOUND( lc );
1470 ldap_back_release_conn_lock( op, rs, lcp, dolock );
1472 } else if ( LDAP_BACK_SAVECRED( li ) ) {
1473 ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
1482 * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
1485 ldap_back_dobind( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
1487 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
1489 return ldap_back_dobind_int( lcp, op, rs,
1490 ( sendok | LDAP_BACK_GETCONN ), li->li_nretries, 1 );
1494 * ldap_back_default_rebind
1496 * This is a callback used for chasing referrals using the same
1497 * credentials as the original user on this session.
1500 ldap_back_default_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
1501 ber_int_t msgid, void *params )
1503 ldapconn_t *lc = (ldapconn_t *)params;
1506 /* ... otherwise we couldn't get here */
1507 assert( lc != NULL );
1509 if ( !ldap_tls_inplace( ld ) ) {
1510 int is_tls = LDAP_BACK_CONN_ISTLS( lc ),
1512 const char *text = NULL;
1514 rc = ldap_back_start_tls( ld, 0, &is_tls, url, lc->lc_flags,
1515 LDAP_BACK_RETRY_DEFAULT, &text );
1516 if ( rc != LDAP_SUCCESS ) {
1520 #endif /* HAVE_TLS */
1522 /* FIXME: add checks on the URL/identity? */
1524 return ldap_sasl_bind_s( ld,
1525 BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val,
1526 LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, NULL );
1530 * ldap_back_default_urllist
1533 ldap_back_default_urllist(
1535 LDAPURLDesc **urllist,
1539 ldapinfo_t *li = (ldapinfo_t *)params;
1540 LDAPURLDesc **urltail;
1542 if ( urllist == url ) {
1543 return LDAP_SUCCESS;
1546 for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
1549 *urltail = *urllist;
1553 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
1555 ch_free( li->li_uri );
1558 ldap_get_option( ld, LDAP_OPT_URI, (void *)&li->li_uri );
1559 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
1561 return LDAP_SUCCESS;
1570 ldap_back_send_t sendok )
1572 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
1574 /* default behavior */
1575 if ( LDAP_BACK_ABANDON( li ) ) {
1576 return ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
1579 if ( LDAP_BACK_IGNORE( li ) ) {
1580 return ldap_pvt_discard( lc->lc_ld, msgid );
1583 if ( LDAP_BACK_CANCEL( li ) ) {
1584 /* FIXME: asynchronous? */
1585 return ldap_cancel_s( lc->lc_ld, msgid, NULL, NULL );
1594 ldap_back_op_result(
1600 ldap_back_send_t sendok )
1602 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
1607 LDAPControl **ctrls = NULL;
1609 #define ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE)
1612 rs->sr_matched = NULL;
1614 rs->sr_ctrls = NULL;
1616 /* if the error recorded in the reply corresponds
1617 * to a successful state, get the error from the
1618 * remote server response */
1619 if ( ERR_OK( rs->sr_err ) ) {
1622 LDAPMessage *res = NULL;
1623 time_t stoptime = (time_t)(-1);
1624 int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
1625 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
1626 const char *timeout_text = "Operation timed out";
1628 /* if timeout is not specified, compute and use
1629 * the one specific to the ongoing operation */
1630 if ( timeout == (time_t)(-1) ) {
1631 slap_op_t opidx = slap_req2op( op->o_tag );
1633 if ( opidx == SLAP_OP_SEARCH ) {
1634 if ( op->ors_tlimit <= 0 ) {
1638 timeout = op->ors_tlimit;
1639 timeout_err = LDAP_TIMELIMIT_EXCEEDED;
1640 timeout_text = NULL;
1644 timeout = li->li_timeout[ opidx ];
1648 /* better than nothing :) */
1649 if ( timeout == 0 ) {
1650 if ( li->li_idle_timeout ) {
1651 timeout = li->li_idle_timeout;
1653 } else if ( li->li_conn_ttl ) {
1654 timeout = li->li_conn_ttl;
1659 stoptime = op->o_time + timeout;
1662 LDAP_BACK_TV_SET( &tv );
1665 /* if result parsing fails, note the failure reason */
1666 rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
1669 if ( timeout && slap_get_time() > stoptime ) {
1670 if ( sendok & LDAP_BACK_BINDING ) {
1671 ldap_unbind_ext( lc->lc_ld, NULL, NULL );
1673 LDAP_BACK_CONN_TAINTED_SET( lc );
1676 (void)ldap_back_cancel( lc, op, rs, msgid, sendok );
1678 rs->sr_err = timeout_err;
1679 rs->sr_text = timeout_text;
1684 LDAP_BACK_TV_SET( &tv );
1685 ldap_pvt_thread_yield();
1689 ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER,
1694 /* otherwise get the result; if it is not
1695 * LDAP_SUCCESS, record it in the reply
1696 * structure (this includes
1697 * LDAP_COMPARE_{TRUE|FALSE}) */
1699 /* only touch when activity actually took place... */
1700 if ( li->li_idle_timeout && lc ) {
1701 lc->lc_time = op->o_time;
1704 rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
1705 &match, &text, &refs, &ctrls, 1 );
1707 if ( rc != LDAP_SUCCESS ) {
1710 if ( refs != NULL ) {
1713 for ( i = 0; refs[ i ] != NULL; i++ )
1715 rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
1717 for ( i = 0; refs[ i ] != NULL; i++ ) {
1718 ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
1720 BER_BVZERO( &rs->sr_ref[ i ] );
1722 if ( ctrls != NULL ) {
1723 rs->sr_ctrls = ctrls;
1728 /* if the error in the reply structure is not
1729 * LDAP_SUCCESS, try to map it from client
1730 * to server error */
1731 if ( !ERR_OK( rs->sr_err ) ) {
1732 rs->sr_err = slap_map_api2result( rs );
1734 /* internal ops ( op->o_conn == NULL )
1735 * must not reply to client */
1736 if ( op->o_conn && !op->o_do_not_cache && match ) {
1738 /* record the (massaged) matched
1739 * DN into the reply structure */
1740 rs->sr_matched = match;
1744 if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1745 if ( !( sendok & LDAP_BACK_RETRYING ) ) {
1746 if ( LDAP_BACK_QUARANTINE( li ) ) {
1747 ldap_back_quarantine( op, rs );
1749 if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
1750 send_ldap_result( op, rs );
1754 } else if ( op->o_conn &&
1755 ( ( ( sendok & LDAP_BACK_SENDOK ) && ERR_OK( rs->sr_err ) )
1756 || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) )
1758 send_ldap_result( op, rs );
1762 if ( rs->sr_matched != match ) {
1763 free( (char *)rs->sr_matched );
1765 rs->sr_matched = NULL;
1766 ldap_memfree( match );
1770 ldap_memfree( text );
1775 assert( refs != NULL );
1776 ber_memvfree( (void **)refs );
1777 op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
1782 assert( rs->sr_ctrls != NULL );
1783 ldap_controls_free( ctrls );
1784 rs->sr_ctrls = NULL;
1787 return( ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
1790 /* return true if bound, false if failed */
1792 ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
1794 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
1798 assert( lcp != NULL );
1799 assert( *lcp != NULL );
1801 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1803 if ( (*lcp)->lc_refcnt == 1 ) {
1804 binding = LDAP_BACK_CONN_BINDING( *lcp );
1806 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
1807 Debug( LDAP_DEBUG_ANY,
1808 "%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
1809 op->o_log_prefix, li->li_uri,
1810 BER_BVISNULL( &(*lcp)->lc_bound_ndn ) ?
1811 "" : (*lcp)->lc_bound_ndn.bv_val );
1812 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
1814 ldap_unbind_ext( (*lcp)->lc_ld, NULL, NULL );
1815 (*lcp)->lc_ld = NULL;
1816 LDAP_BACK_CONN_ISBOUND_CLEAR( (*lcp) );
1818 /* lc here must be the regular lc, reset and ready for init */
1819 rc = ldap_back_prepare_conn( lcp, op, rs, sendok );
1820 if ( rc != LDAP_SUCCESS ) {
1821 /* freeit, because lc_refcnt == 1 */
1822 (*lcp)->lc_refcnt = 0;
1823 (void)ldap_back_freeconn( op, *lcp, 0 );
1827 } else if ( ( sendok & LDAP_BACK_BINDING ) ) {
1829 LDAP_BACK_CONN_BINDING_SET( *lcp );
1834 rc = ldap_back_dobind_int( lcp, op, rs, sendok, 0, 0 );
1835 if ( rc == 0 && *lcp != NULL ) {
1836 /* freeit, because lc_refcnt == 1 */
1837 (*lcp)->lc_refcnt = 0;
1838 LDAP_BACK_CONN_TAINTED_SET( *lcp );
1839 (void)ldap_back_freeconn( op, *lcp, 0 );
1845 Debug( LDAP_DEBUG_TRACE,
1846 "ldap_back_retry: conn %p refcnt=%u unable to retry.\n",
1847 (void *)(*lcp), (*lcp)->lc_refcnt, 0 );
1849 LDAP_BACK_CONN_TAINTED_SET( *lcp );
1850 ldap_back_release_conn_lock( op, rs, lcp, 0 );
1851 assert( *lcp == NULL );
1854 rs->sr_err = LDAP_UNAVAILABLE;
1855 rs->sr_text = "unable to retry";
1856 send_ldap_result( op, rs );
1860 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1866 ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
1867 struct berval *binddn, struct berval *bindcred )
1869 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
1873 if ( op->o_conn == NULL || op->o_do_not_cache ) {
1877 /* don't proxyAuthz if protocol is not LDAPv3 */
1878 switch ( li->li_version ) {
1883 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
1889 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1890 if ( sendok & LDAP_BACK_SENDERR ) {
1891 send_ldap_result( op, rs );
1898 *binddn = slap_empty_bv;
1899 *bindcred = slap_empty_bv;
1901 if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
1902 ndn = op->o_conn->c_ndn;
1908 switch ( li->li_idassert_mode ) {
1909 case LDAP_BACK_IDASSERT_LEGACY:
1910 if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
1911 if ( !BER_BVISNULL( &li->li_idassert_authcDN ) && !BER_BVISEMPTY( &li->li_idassert_authcDN ) )
1913 *binddn = li->li_idassert_authcDN;
1914 *bindcred = li->li_idassert_passwd;
1921 /* NOTE: rootdn can always idassert */
1922 if ( BER_BVISNULL( &ndn ) && li->li_idassert_authz == NULL ) {
1923 if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1924 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1925 if ( sendok & LDAP_BACK_SENDERR ) {
1926 send_ldap_result( op, rs );
1931 rs->sr_err = LDAP_SUCCESS;
1932 *binddn = slap_empty_bv;
1933 *bindcred = slap_empty_bv;
1939 } else if ( li->li_idassert_authz && !be_isroot( op ) ) {
1940 struct berval authcDN;
1942 if ( BER_BVISNULL( &ndn ) ) {
1943 authcDN = slap_empty_bv;
1948 rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz,
1949 &authcDN, &authcDN );
1950 if ( rs->sr_err != LDAP_SUCCESS ) {
1951 if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1952 if ( sendok & LDAP_BACK_SENDERR ) {
1953 send_ldap_result( op, rs );
1958 rs->sr_err = LDAP_SUCCESS;
1959 *binddn = slap_empty_bv;
1960 *bindcred = slap_empty_bv;
1968 *binddn = li->li_idassert_authcDN;
1969 *bindcred = li->li_idassert_passwd;
1979 ldap_back_proxy_authz_bind(
1983 ldap_back_send_t sendok,
1984 struct berval *binddn,
1985 struct berval *bindcred )
1987 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
1992 if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
1993 ndn = op->o_conn->c_ndn;
1999 if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
2000 #ifdef HAVE_CYRUS_SASL
2001 void *defaults = NULL;
2002 struct berval authzID = BER_BVNULL;
2005 /* if SASL supports native authz, prepare for it */
2006 if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
2007 ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
2009 switch ( li->li_idassert_mode ) {
2010 case LDAP_BACK_IDASSERT_OTHERID:
2011 case LDAP_BACK_IDASSERT_OTHERDN:
2012 authzID = li->li_idassert_authzID;
2015 case LDAP_BACK_IDASSERT_ANONYMOUS:
2016 BER_BVSTR( &authzID, "dn:" );
2019 case LDAP_BACK_IDASSERT_SELF:
2020 if ( BER_BVISNULL( &ndn ) ) {
2021 /* connection is not authc'd, so don't idassert */
2022 BER_BVSTR( &authzID, "dn:" );
2025 authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
2026 authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
2027 AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
2028 AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
2029 ndn.bv_val, ndn.bv_len + 1 );
2038 if ( li->li_idassert_secprops != NULL ) {
2039 rs->sr_err = ldap_set_option( lc->lc_ld,
2040 LDAP_OPT_X_SASL_SECPROPS,
2041 (void *)li->li_idassert_secprops );
2043 if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
2044 rs->sr_err = LDAP_OTHER;
2045 if ( sendok & LDAP_BACK_SENDERR ) {
2046 send_ldap_result( op, rs );
2048 LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2053 defaults = lutil_sasl_defaults( lc->lc_ld,
2054 li->li_idassert_sasl_mech.bv_val,
2055 li->li_idassert_sasl_realm.bv_val,
2056 li->li_idassert_authcID.bv_val,
2057 li->li_idassert_passwd.bv_val,
2060 rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, binddn->bv_val,
2061 li->li_idassert_sasl_mech.bv_val, NULL, NULL,
2062 LDAP_SASL_QUIET, lutil_sasl_interact,
2065 rs->sr_err = slap_map_api2result( rs );
2066 if ( rs->sr_err != LDAP_SUCCESS ) {
2067 LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2068 if ( sendok & LDAP_BACK_SENDERR ) {
2069 send_ldap_result( op, rs );
2073 LDAP_BACK_CONN_ISBOUND_SET( lc );
2076 lutil_sasl_freedefs( defaults );
2078 slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
2082 #endif /* HAVE_CYRUS_SASL */
2085 switch ( li->li_idassert_authmethod ) {
2086 case LDAP_AUTH_NONE:
2087 /* FIXME: do we really need this? */
2088 BER_BVSTR( binddn, "" );
2089 BER_BVSTR( bindcred, "" );
2092 case LDAP_AUTH_SIMPLE:
2093 rs->sr_err = ldap_sasl_bind( lc->lc_ld,
2094 binddn->bv_val, LDAP_SASL_SIMPLE,
2095 bindcred, NULL, NULL, &msgid );
2096 rc = ldap_back_op_result( lc, op, rs, msgid,
2097 -1, (sendok|LDAP_BACK_BINDING) );
2102 LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2103 rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
2104 if ( sendok & LDAP_BACK_SENDERR ) {
2105 send_ldap_result( op, rs );
2110 if ( rc == LDAP_SUCCESS ) {
2111 /* set rebind stuff in case of successful proxyAuthz bind,
2112 * so that referral chasing is attempted using the right
2114 LDAP_BACK_CONN_ISBOUND_SET( lc );
2115 ber_bvreplace( &lc->lc_bound_ndn, binddn );
2117 if ( !BER_BVISNULL( &lc->lc_cred ) ) {
2118 memset( lc->lc_cred.bv_val, 0,
2119 lc->lc_cred.bv_len );
2122 if ( LDAP_BACK_SAVECRED( li ) ) {
2123 ber_bvreplace( &lc->lc_cred, bindcred );
2124 ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
2127 lc->lc_cred.bv_len = 0;
2131 return LDAP_BACK_CONN_ISBOUND( lc );
2135 * ldap_back_proxy_authz_ctrl() prepends a proxyAuthz control
2136 * to existing server-side controls if required; if not,
2137 * the existing server-side controls are placed in *pctrls.
2138 * The caller, after using the controls in client API
2139 * operations, if ( *pctrls != op->o_ctrls ), should
2140 * free( (*pctrls)[ 0 ] ) and free( *pctrls ).
2141 * The function returns success if the control could
2142 * be added if required, or if it did nothing; in the future,
2143 * it might return some error if it failed.
2145 * if no bind took place yet, but the connection is bound
2146 * and the "proxyauthzdn" is set, then bind as "proxyauthzdn"
2147 * and explicitly add proxyAuthz the control to every operation
2148 * with the dn bound to the connection as control value.
2150 * If no server-side controls are defined for the operation,
2151 * simply add the proxyAuthz control; otherwise, if the
2152 * proxyAuthz control is not already set, add it as
2155 * FIXME: is controls order significant for security?
2156 * ANSWER: controls ordering and interoperability
2157 * must be indicated by the specs of each control; if none
2158 * is specified, the order is irrelevant.
2161 ldap_back_proxy_authz_ctrl(
2162 struct berval *bound_ndn,
2164 slap_idassert_t *si,
2167 LDAPControl ***pctrls )
2169 LDAPControl **ctrls = NULL;
2171 slap_idassert_mode_t mode;
2172 struct berval assertedID,
2177 rs->sr_err = LDAP_SUCCESS;
2179 /* don't proxyAuthz if protocol is not LDAPv3 */
2180 switch ( version ) {
2185 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
2194 /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID,
2195 * but if it is not set this test fails. We need a different
2196 * means to detect if idassert is enabled */
2197 if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) )
2198 && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) ) )
2203 if ( !op->o_conn || op->o_do_not_cache || be_isroot( op ) ) {
2207 if ( op->o_tag == LDAP_REQ_BIND ) {
2208 ndn = op->o_req_ndn;
2210 } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
2211 ndn = op->o_conn->c_ndn;
2217 if ( si->si_mode == LDAP_BACK_IDASSERT_LEGACY ) {
2218 if ( op->o_proxy_authz ) {
2220 * FIXME: we do not want to perform proxyAuthz
2221 * on behalf of the client, because this would
2222 * be performed with "proxyauthzdn" privileges.
2224 * This might actually be too strict, since
2225 * the "proxyauthzdn" authzTo, and each entry's
2226 * authzFrom attributes may be crafted
2227 * to avoid unwanted proxyAuthz to take place.
2230 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
2231 rs->sr_text = "proxyAuthz not allowed within namingContext";
2236 if ( !BER_BVISNULL( bound_ndn ) ) {
2240 if ( BER_BVISNULL( &ndn ) ) {
2244 if ( BER_BVISNULL( &si->si_bc.sb_binddn ) ) {
2248 } else if ( si->si_bc.sb_method == LDAP_AUTH_SASL ) {
2249 if ( ( si->si_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
2251 /* already asserted in SASL via native authz */
2255 } else if ( si->si_authz && !be_isroot( op ) ) {
2257 struct berval authcDN;
2259 if ( BER_BVISNULL( &ndn ) ) {
2260 authcDN = slap_empty_bv;
2264 rc = slap_sasl_matches( op, si->si_authz,
2265 &authcDN, & authcDN );
2266 if ( rc != LDAP_SUCCESS ) {
2267 if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
2268 /* ndn is not authorized
2269 * to use idassert */
2276 if ( op->o_proxy_authz ) {
2279 * 1) ignore the already set proxyAuthz control
2280 * 2) leave it in place, and don't set ours
2282 * 4) reject the operation
2284 * option (4) is very drastic
2285 * option (3) will make the remote server reject
2286 * the operation, thus being equivalent to (4)
2287 * option (2) will likely break the idassert
2288 * assumptions, so we cannot accept it;
2289 * option (1) means that we are contradicting
2290 * the client's reques.
2292 * I think (4) is the only correct choice.
2294 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
2295 rs->sr_text = "proxyAuthz not allowed within namingContext";
2298 if ( op->o_is_auth_check ) {
2299 mode = LDAP_BACK_IDASSERT_NOASSERT;
2306 case LDAP_BACK_IDASSERT_SELF:
2307 if ( BER_BVISNULL( &ndn ) ) {
2313 case LDAP_BACK_IDASSERT_LEGACY:
2314 /* original behavior:
2315 * assert the client's identity */
2316 if ( BER_BVISNULL( &ndn ) ) {
2317 assertedID = slap_empty_bv;
2323 case LDAP_BACK_IDASSERT_ANONYMOUS:
2324 /* assert "anonymous" */
2325 assertedID = slap_empty_bv;
2328 case LDAP_BACK_IDASSERT_NOASSERT:
2329 /* don't assert; bind as proxyauthzdn */
2332 case LDAP_BACK_IDASSERT_OTHERID:
2333 case LDAP_BACK_IDASSERT_OTHERDN:
2334 /* assert idassert DN */
2335 assertedID = si->si_bc.sb_authzId;
2342 if ( BER_BVISNULL( &assertedID ) ) {
2343 assertedID = slap_empty_bv;
2346 /* don't idassert the bound DN (ITS#4497) */
2347 if ( dn_match( &assertedID, bound_ndn ) ) {
2351 if ( op->o_ctrls ) {
2352 for ( i = 0; op->o_ctrls[ i ]; i++ )
2353 /* just count ctrls */ ;
2356 ctrls = op->o_tmpalloc( sizeof( LDAPControl * ) * (i + 2) + sizeof( LDAPControl ),
2358 ctrls[ 0 ] = (LDAPControl *)&ctrls[ i + 2 ];
2360 ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
2361 ctrls[ 0 ]->ldctl_iscritical = 1;
2363 switch ( si->si_mode ) {
2364 /* already in u:ID or dn:DN form */
2365 case LDAP_BACK_IDASSERT_OTHERID:
2366 case LDAP_BACK_IDASSERT_OTHERDN:
2367 ber_dupbv_x( &ctrls[ 0 ]->ldctl_value, &assertedID, op->o_tmpmemctx );
2370 /* needs the dn: prefix */
2372 ctrls[ 0 ]->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" );
2373 ctrls[ 0 ]->ldctl_value.bv_val = op->o_tmpalloc( ctrls[ 0 ]->ldctl_value.bv_len + 1,
2375 AC_MEMCPY( ctrls[ 0 ]->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) );
2376 AC_MEMCPY( &ctrls[ 0 ]->ldctl_value.bv_val[ STRLENOF( "dn:" ) ],
2377 assertedID.bv_val, assertedID.bv_len + 1 );
2381 /* Older versions of <draft-weltman-ldapv3-proxy> required
2382 * to encode the value of the authzID (and called it proxyDN);
2383 * this hack provides compatibility with those DSAs that
2384 * implement it this way */
2385 if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
2386 struct berval authzID = ctrls[ 0 ]->ldctl_value;
2387 BerElementBuffer berbuf;
2388 BerElement *ber = (BerElement *)&berbuf;
2391 ber_init2( ber, 0, LBER_USE_DER );
2392 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
2394 tag = ber_printf( ber, "O", &authzID );
2395 if ( tag == LBER_ERROR ) {
2396 rs->sr_err = LDAP_OTHER;
2400 if ( ber_flatten2( ber, &ctrls[ 0 ]->ldctl_value, 1 ) == -1 ) {
2401 rs->sr_err = LDAP_OTHER;
2406 op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
2407 ber_free_buf( ber );
2409 if ( rs->sr_err != LDAP_SUCCESS ) {
2410 op->o_tmpfree( ctrls, op->o_tmpmemctx );
2415 } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
2416 struct berval authzID = ctrls[ 0 ]->ldctl_value,
2418 BerElementBuffer berbuf;
2419 BerElement *ber = (BerElement *)&berbuf;
2422 if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) {
2423 op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx );
2424 op->o_tmpfree( ctrls, op->o_tmpmemctx );
2426 rs->sr_err = LDAP_PROTOCOL_ERROR;
2431 tmp.bv_val += STRLENOF( "dn:" );
2432 tmp.bv_len -= STRLENOF( "dn:" );
2434 ber_init2( ber, 0, LBER_USE_DER );
2435 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
2437 /* apparently, Mozilla API encodes this
2438 * as "SEQUENCE { LDAPDN }" */
2439 tag = ber_printf( ber, "{O}", &tmp );
2440 if ( tag == LBER_ERROR ) {
2441 rs->sr_err = LDAP_OTHER;
2445 if ( ber_flatten2( ber, &ctrls[ 0 ]->ldctl_value, 1 ) == -1 ) {
2446 rs->sr_err = LDAP_OTHER;
2451 op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
2452 ber_free_buf( ber );
2454 if ( rs->sr_err != LDAP_SUCCESS ) {
2455 op->o_tmpfree( ctrls, op->o_tmpmemctx );
2460 ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
2463 if ( op->o_ctrls ) {
2464 for ( i = 0; op->o_ctrls[ i ]; i++ ) {
2465 ctrls[ i + 1 ] = op->o_ctrls[ i ];
2468 ctrls[ i + 1 ] = NULL;
2471 if ( ctrls == NULL ) {
2472 ctrls = op->o_ctrls;
2481 ldap_back_proxy_authz_ctrl_free( Operation *op, LDAPControl ***pctrls )
2483 LDAPControl **ctrls = *pctrls;
2485 /* we assume that the first control is the proxyAuthz
2486 * added by back-ldap, so it's the only one we explicitly
2488 if ( ctrls && ctrls != op->o_ctrls ) {
2489 assert( ctrls[ 0 ] != NULL );
2491 if ( !BER_BVISNULL( &ctrls[ 0 ]->ldctl_value ) ) {
2492 op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx );
2495 op->o_tmpfree( ctrls, op->o_tmpmemctx );