X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldap%2Fbind.c;h=9ef163c879d61cca0c537fed119f413947bfc518;hb=6018fe9671dcbb90e3845bc14851858c5d9fdf2a;hp=bc0b3d9a3c51e5c272efc4b67c922b1612d0af5e;hpb=c428a163323283ad7c7c0dfaf1c3d5ea9772037b;p=openldap diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index bc0b3d9a3c..9ef163c879 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1999-2007 The OpenLDAP Foundation. + * Copyright 1999-2011 The OpenLDAP Foundation. * Portions Copyright 2000-2003 Pierangelo Masarati. * Portions Copyright 1999-2003 Howard Chu. * All rights reserved. @@ -32,14 +32,55 @@ #define AVL_INTERNAL #include "slap.h" #include "back-ldap.h" -#undef ldap_debug /* silence a warning in ldap-int.h */ -#include "../../../libraries/libldap/ldap-int.h" - +#include "lutil.h" #include "lutil_ldap.h" #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ "2.16.840.1.113730.3.4.12" +#ifdef LDAP_DEVEL +#define SLAP_AUTH_DN 1 +#endif + #if LDAP_BACK_PRINT_CONNTREE > 0 + +static const struct { + slap_mask_t f; + char c; +} flagsmap[] = { + { LDAP_BACK_FCONN_ISBOUND, 'B' }, + { LDAP_BACK_FCONN_ISANON, 'A' }, + { LDAP_BACK_FCONN_ISPRIV, 'P' }, + { LDAP_BACK_FCONN_ISTLS, 'T' }, + { LDAP_BACK_FCONN_BINDING, 'X' }, + { LDAP_BACK_FCONN_TAINTED, 'E' }, + { LDAP_BACK_FCONN_ABANDON, 'N' }, + { LDAP_BACK_FCONN_ISIDASR, 'S' }, + { LDAP_BACK_FCONN_CACHED, 'C' }, + { 0, '\0' } +}; + +static void +ldap_back_conn_print( ldapconn_t *lc, const char *avlstr ) +{ + char buf[ SLAP_TEXT_BUFLEN ]; + char fbuf[ sizeof("BAPTIENSC") ]; + int i; + + ldap_back_conn2str( &lc->lc_base, buf, sizeof( buf ) ); + for ( i = 0; flagsmap[ i ].c != '\0'; i++ ) { + if ( lc->lc_lcflags & flagsmap[i].f ) { + fbuf[i] = flagsmap[i].c; + + } else { + fbuf[i] = '.'; + } + } + fbuf[i] = '\0'; + + fprintf( stderr, "lc=%p %s %s flags=0x%08x (%s)\n", + (void *)lc, buf, avlstr, lc->lc_lcflags, fbuf ); +} + static void ldap_back_ravl_print( Avlnode *root, int depth ) { @@ -57,13 +98,9 @@ ldap_back_ravl_print( Avlnode *root, int depth ) } lc = root->avl_data; - fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d flags=0x%08x\n", - (void *)lc, - lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "", - (void *)lc->lc_conn, - avl_bf2str( root->avl_bf ), lc->lc_refcnt, lc->lc_lcflags ); - - ldap_back_ravl_print( root->avl_left, depth+1 ); + ldap_back_conn_print( lc, avl_bf2str( root->avl_bf ) ); + + ldap_back_ravl_print( root->avl_left, depth + 1 ); } static char* priv2str[] = { @@ -91,11 +128,8 @@ ldap_back_print_conntree( ldapinfo_t *li, char *msg ) LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q ) { - fprintf( stderr, " [%d] lc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n", - i, - (void *)lc, - lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "", - (void *)lc->lc_conn, lc->lc_refcnt, lc->lc_lcflags ); + fprintf( stderr, " [%d] ", i ); + ldap_back_conn_print( lc, "" ); i++; } } @@ -244,6 +278,8 @@ retry:; ldap_back_controls_free( op, rs, &ctrls ); if ( rc == LDAP_SUCCESS ) { + op->o_conn->c_authz_cookie = op->o_bd->be_private; + /* If defined, proxyAuthz will be used also when * back-ldap is the authorizing backend; for this * purpose, after a successful bind the connection @@ -303,9 +339,10 @@ retry_lock:; if ( LDAP_BACK_SINGLECONN( li ) ) { while ( ( tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL ) { + assert( !LDAP_BACK_PCONN_ISPRIV( lc ) ); Debug( LDAP_DEBUG_TRACE, - "=>ldap_back_bind: destroying conn %ld (refcnt=%u)\n", - LDAP_BACK_PCONN_ID( lc ), lc->lc_refcnt, 0 ); + "=>ldap_back_bind: destroying conn %lu (refcnt=%u)\n", + lc->lc_conn->c_connid, lc->lc_refcnt, 0 ); if ( tmplc->lc_refcnt != 0 ) { /* taint it */ @@ -548,12 +585,13 @@ retry:; rc = ldap_parse_extended_result( ld, res, NULL, &data, 0 ); if ( rc == LDAP_SUCCESS ) { - int err; - rc = ldap_parse_result( ld, res, &err, + SlapReply rs; + rc = ldap_parse_result( ld, res, &rs.sr_err, NULL, NULL, NULL, NULL, 1 ); - if ( rc == LDAP_SUCCESS ) { - rc = err; + if ( rc != LDAP_SUCCESS ) { + rs.sr_err = rc; } + rc = slap_map_api2result( &rs ); res = NULL; /* FIXME: in case a referral @@ -631,7 +669,8 @@ ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_ LDAP *ld = NULL; #ifdef HAVE_TLS int is_tls = op->o_conn->c_is_tls; - time_t lc_time = (time_t)(-1); + int flags = li->li_flags; + time_t lctime = (time_t)(-1); slap_bindconf *sb; #endif /* HAVE_TLS */ @@ -675,7 +714,12 @@ ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_ #ifdef HAVE_TLS if ( LDAP_BACK_CONN_ISPRIV( lc ) ) { - sb = &li->li_acl; + /* See "rationale" comment in ldap_back_getconn() */ + if ( li->li_acl_authmethod == LDAP_AUTH_NONE && + li->li_idassert_authmethod != LDAP_AUTH_NONE ) + sb = &li->li_idassert.si_bc; + else + sb = &li->li_acl; } else if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) { sb = &li->li_idassert.si_bc; @@ -690,9 +734,19 @@ ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_ ldap_set_option( ld, LDAP_OPT_X_TLS_CTX, sb->sb_tls_ctx ); } + /* if required by the bindconf configuration, force TLS */ + if ( ( sb == &li->li_acl || sb == &li->li_idassert.si_bc ) && + sb->sb_tls_ctx ) + { + flags |= LDAP_BACK_F_USE_TLS; + } + ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); + assert( li->li_uri_mutex_do_not_lock == 0 ); + li->li_uri_mutex_do_not_lock = 1; rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls, - li->li_uri, li->li_flags, li->li_nretries, &rs->sr_text ); + li->li_uri, flags, li->li_nretries, &rs->sr_text ); + li->li_uri_mutex_do_not_lock = 0; ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); if ( rs->sr_err != LDAP_SUCCESS ) { ldap_unbind_ext( ld, NULL, NULL ); @@ -701,7 +755,7 @@ ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_ } else if ( li->li_idle_timeout ) { /* only touch when activity actually took place... */ - lc_time = op->o_time; + lctime = op->o_time; } #endif /* HAVE_TLS */ @@ -713,8 +767,8 @@ ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_ } else { LDAP_BACK_CONN_ISTLS_CLEAR( lc ); } - if ( lc_time != (time_t)(-1) ) { - lc->lc_time = lc_time; + if ( lctime != (time_t)(-1) ) { + lc->lc_time = lctime; } #endif /* HAVE_TLS */ @@ -747,7 +801,7 @@ ldap_back_getconn( { ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; ldapconn_t *lc = NULL, - lc_curr = { 0 }; + lc_curr = {{ 0 }}; int refcnt = 1, lookupconn = !( sendok & LDAP_BACK_BINDING ); @@ -931,10 +985,10 @@ retry_lock: /* * the rationale is: connections as the rootdn are privileged, - * so acl_authcDN is to be used; however, in some cases + * so li_acl is to be used; however, in some cases * one already configured identity assertion with a highly - * privileged idassert_authcDN, so if acl_authcDN is NULL - * and idassert_authcDN is not, use the second instead. + * privileged idassert_authcDN, so if li_acl is not configured + * and idassert is, use idassert instead. * * might change in the future, because it's preferable * to make clear what identity is being used, since @@ -942,7 +996,8 @@ retry_lock: * the same identity twice... */ if ( LDAP_BACK_CONN_ISPRIV( &lc_curr ) ) { - if ( BER_BVISNULL( &li->li_acl_authcDN ) && !BER_BVISNULL( &li->li_idassert_authcDN ) ) { + if ( li->li_acl_authmethod == LDAP_AUTH_NONE && + li->li_idassert_authmethod != LDAP_AUTH_NONE ) { ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN ); ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd ); @@ -1228,6 +1283,8 @@ ldap_back_dobind_cb( { ber_tag_t *tptr = op->o_callback->sc_private; op->o_tag = *tptr; + rs->sr_tag = slap_req2res( op->o_tag ); + return SLAP_CB_CONTINUE; } @@ -1257,6 +1314,7 @@ ldap_back_dobind_int( ber_int_t msgid; ber_tag_t o_tag = op->o_tag; slap_callback cb = {0}; + char *tmp_dn; assert( lcp != NULL ); assert( retries >= 0 ); @@ -1350,28 +1408,33 @@ retry_lock:; } #ifdef HAVE_CYRUS_SASL - if ( LDAP_BACK_CONN_ISPRIV( lc ) - && li->li_acl_authmethod == LDAP_AUTH_SASL ) - { + if ( LDAP_BACK_CONN_ISPRIV( lc )) { + slap_bindconf *sb; + if ( li->li_acl_authmethod != LDAP_AUTH_NONE ) + sb = &li->li_acl; + else + sb = &li->li_idassert.si_bc; + + if ( sb->sb_method == LDAP_AUTH_SASL ) { void *defaults = NULL; - if ( li->li_acl_secprops != NULL ) { + if ( sb->sb_secprops != NULL ) { rc = ldap_set_option( lc->lc_ld, - LDAP_OPT_X_SASL_SECPROPS, li->li_acl_secprops ); + LDAP_OPT_X_SASL_SECPROPS, sb->sb_secprops ); if ( rc != LDAP_OPT_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option " "(SECPROPS,\"%s\") failed!\n", - li->li_acl_secprops, 0, 0 ); + sb->sb_secprops, 0, 0 ); goto done; } } defaults = lutil_sasl_defaults( lc->lc_ld, - li->li_acl_sasl_mech.bv_val, - li->li_acl_sasl_realm.bv_val, - li->li_acl_authcID.bv_val, - li->li_acl_passwd.bv_val, + sb->sb_saslmech.bv_val, + sb->sb_realm.bv_val, + sb->sb_authcId.bv_val, + sb->sb_cred.bv_val, NULL ); if ( defaults == NULL ) { rs->sr_err = LDAP_OTHER; @@ -1383,22 +1446,33 @@ retry_lock:; } rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, - li->li_acl_authcDN.bv_val, - li->li_acl_sasl_mech.bv_val, NULL, NULL, + sb->sb_binddn.bv_val, + sb->sb_saslmech.bv_val, NULL, NULL, LDAP_SASL_QUIET, lutil_sasl_interact, defaults ); lutil_sasl_freedefs( defaults ); - rs->sr_err = slap_map_api2result( rs ); - if ( rs->sr_err != LDAP_SUCCESS ) { + switch ( rs->sr_err ) { + case LDAP_SUCCESS: + LDAP_BACK_CONN_ISBOUND_SET( lc ); + break; + + case LDAP_LOCAL_ERROR: + /* list client API error codes that require + * to taint the connection */ + /* FIXME: should actually retry? */ + LDAP_BACK_CONN_TAINTED_SET( lc ); + + /* fallthru */ + + default: LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); + rs->sr_err = slap_map_api2result( rs ); if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); } - - } else { - LDAP_BACK_CONN_ISBOUND_SET( lc ); + break; } if ( LDAP_BACK_QUARANTINE( li ) ) { @@ -1407,11 +1481,22 @@ retry_lock:; goto done; } + } #endif /* HAVE_CYRUS_SASL */ retry:; + if ( BER_BVISNULL( &lc->lc_cred ) ) { + tmp_dn = ""; + if ( !BER_BVISNULL( &lc->lc_bound_ndn ) && !BER_BVISEMPTY( &lc->lc_bound_ndn ) ) { + Debug( LDAP_DEBUG_ANY, "%s ldap_back_dobind_int: DN=\"%s\" without creds, binding anonymously", + op->o_log_prefix, lc->lc_bound_ndn.bv_val, 0 ); + } + + } else { + tmp_dn = lc->lc_bound_ndn.bv_val; + } rs->sr_err = ldap_sasl_bind( lc->lc_ld, - BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val, + tmp_dn, LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, &msgid ); @@ -1467,12 +1552,13 @@ retry:; } rc = 0; - goto leave; + goto func_leave; } rc = ldap_back_op_result( lc, op, rs, msgid, -1, ( sendok | LDAP_BACK_BINDING ) ); if ( rc == LDAP_SUCCESS ) { + op->o_conn->c_authz_cookie = op->o_bd->be_private; LDAP_BACK_CONN_ISBOUND_SET( lc ); } @@ -1486,7 +1572,7 @@ done:; ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc ); } -leave:; +func_leave:; if ( op->o_callback == &cb ) op->o_callback = cb.sc_next; op->o_tag = o_tag; @@ -1568,13 +1654,19 @@ ldap_back_default_urllist( *urllist = *url; *url = NULL; - ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); + if ( !li->li_uri_mutex_do_not_lock ) { + ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); + } + if ( li->li_uri ) { ch_free( li->li_uri ); } ldap_get_option( ld, LDAP_OPT_URI, (void *)&li->li_uri ); - ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); + + if ( !li->li_uri_mutex_do_not_lock ) { + ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); + } return LDAP_SUCCESS; } @@ -1624,8 +1716,6 @@ ldap_back_op_result( char **refs = NULL; LDAPControl **ctrls = NULL; -#define ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE) - rs->sr_text = NULL; rs->sr_matched = NULL; rs->sr_ref = NULL; @@ -1634,7 +1724,7 @@ ldap_back_op_result( /* if the error recorded in the reply corresponds * to a successful state, get the error from the * remote server response */ - if ( ERR_OK( rs->sr_err ) ) { + if ( LDAP_ERR_OK( rs->sr_err ) ) { int rc; struct timeval tv; LDAPMessage *res = NULL; @@ -1736,10 +1826,12 @@ retry:; rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err, &match, &text, &refs, &ctrls, 1 ); - rs->sr_text = text; - if ( rc != LDAP_SUCCESS ) { + if ( rc == LDAP_SUCCESS ) { + rs->sr_text = text; + } else { rs->sr_err = rc; } + rs->sr_err = slap_map_api2result( rs ); /* RFC 4511: referrals can only appear * if result code is LDAP_REFERRAL */ @@ -1787,7 +1879,7 @@ retry:; /* if the error in the reply structure is not * LDAP_SUCCESS, try to map it from client * to server error */ - if ( !ERR_OK( rs->sr_err ) ) { + if ( !LDAP_ERR_OK( rs->sr_err ) ) { rs->sr_err = slap_map_api2result( rs ); /* internal ops ( op->o_conn == NULL ) @@ -1812,25 +1904,18 @@ retry:; } } else if ( op->o_conn && - ( ( ( sendok & LDAP_BACK_SENDOK ) && ERR_OK( rs->sr_err ) ) - || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) ) + ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) ) + || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) ) { send_ldap_result( op, rs ); } - if ( match ) { - if ( rs->sr_matched != match ) { - free( (char *)rs->sr_matched ); - } - rs->sr_matched = NULL; - ldap_memfree( match ); - } - if ( text ) { ldap_memfree( text ); } rs->sr_text = NULL; + /* there can't be refs with a (successful) bind */ if ( rs->sr_ref ) { op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); rs->sr_ref = NULL; @@ -1840,13 +1925,53 @@ retry:; ber_memvfree( (void **)refs ); } - if ( ctrls ) { - assert( rs->sr_ctrls != NULL ); + /* match should not be possible with a successful bind */ + if ( match ) { + if ( rs->sr_matched != match ) { + free( (char *)rs->sr_matched ); + } + rs->sr_matched = NULL; + ldap_memfree( match ); + } + + if ( ctrls != NULL ) { + if ( op->o_tag == LDAP_REQ_BIND && rs->sr_err == LDAP_SUCCESS ) { + int i; + + for ( i = 0; ctrls[i] != NULL; i++ ); + + rs->sr_ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( i + 1 ), + op->o_tmpmemctx ); + for ( i = 0; ctrls[ i ] != NULL; i++ ) { + char *ptr; + ber_len_t oidlen = strlen( ctrls[i]->ldctl_oid ); + ber_len_t size = sizeof( LDAPControl ) + + oidlen + 1 + + ctrls[i]->ldctl_value.bv_len + 1; + + rs->sr_ctrls[ i ] = op->o_tmpalloc( size, op->o_tmpmemctx ); + rs->sr_ctrls[ i ]->ldctl_oid = (char *)&rs->sr_ctrls[ i ][ 1 ]; + lutil_strcopy( rs->sr_ctrls[ i ]->ldctl_oid, ctrls[i]->ldctl_oid ); + rs->sr_ctrls[ i ]->ldctl_value.bv_val + = (char *)&rs->sr_ctrls[ i ]->ldctl_oid[oidlen + 1]; + rs->sr_ctrls[ i ]->ldctl_value.bv_len + = ctrls[i]->ldctl_value.bv_len; + ptr = lutil_memcopy( rs->sr_ctrls[ i ]->ldctl_value.bv_val, + ctrls[i]->ldctl_value.bv_val, ctrls[i]->ldctl_value.bv_len ); + *ptr = '\0'; + } + rs->sr_ctrls[ i ] = NULL; + rs->sr_flags |= REP_CTRLS_MUSTBEFREED; + + } else { + assert( rs->sr_ctrls != NULL ); + rs->sr_ctrls = NULL; + } + ldap_controls_free( ctrls ); - rs->sr_ctrls = NULL; } - return( ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err ); + return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err ); } /* return true if bound, false if failed */ @@ -2000,32 +2125,51 @@ ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok, goto done; - } else if ( li->li_idassert_authz && !be_isroot( op ) ) { - struct berval authcDN; - - if ( BER_BVISNULL( &ndn ) ) { - authcDN = slap_empty_bv; + } else if ( !be_isroot( op ) ) { + if ( li->li_idassert_passthru ) { + struct berval authcDN; - } else { - authcDN = ndn; - } - rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz, - &authcDN, &authcDN ); - if ( rs->sr_err != LDAP_SUCCESS ) { - if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { - if ( sendok & LDAP_BACK_SENDERR ) { - send_ldap_result( op, rs ); - dobind = -1; - } + if ( BER_BVISNULL( &ndn ) ) { + authcDN = slap_empty_bv; } else { - rs->sr_err = LDAP_SUCCESS; - *binddn = slap_empty_bv; - *bindcred = slap_empty_bv; + authcDN = ndn; + } + rs->sr_err = slap_sasl_matches( op, li->li_idassert_passthru, + &authcDN, &authcDN ); + if ( rs->sr_err == LDAP_SUCCESS ) { + dobind = 0; break; } + } - goto done; + if ( li->li_idassert_authz ) { + struct berval authcDN; + + if ( BER_BVISNULL( &ndn ) ) { + authcDN = slap_empty_bv; + + } else { + authcDN = ndn; + } + rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz, + &authcDN, &authcDN ); + if ( rs->sr_err != LDAP_SUCCESS ) { + if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + dobind = -1; + } + + } else { + rs->sr_err = LDAP_SUCCESS; + *binddn = slap_empty_bv; + *bindcred = slap_empty_bv; + break; + } + + goto done; + } } } @@ -2065,6 +2209,15 @@ ldap_back_proxy_authz_bind( void *defaults = NULL; struct berval authzID = BER_BVNULL; int freeauthz = 0; + LDAPControl **ctrlsp = NULL; + LDAPMessage *result = NULL; + const char *rmech = NULL; + const char *save_text = rs->sr_text; + +#ifdef SLAP_AUTH_DN + LDAPControl ctrl, *ctrls[2]; + int msgid; +#endif /* SLAP_AUTH_DN */ /* if SASL supports native authz, prepare for it */ if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) && @@ -2129,22 +2282,122 @@ ldap_back_proxy_authz_bind( goto done; } - rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, binddn->bv_val, - li->li_idassert_sasl_mech.bv_val, NULL, NULL, - LDAP_SASL_QUIET, lutil_sasl_interact, - defaults ); +#ifdef SLAP_AUTH_DN + if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) { + assert( BER_BVISNULL( binddn ) ); - rs->sr_err = slap_map_api2result( rs ); - if ( rs->sr_err != LDAP_SUCCESS ) { + ctrl.ldctl_oid = LDAP_CONTROL_AUTHZID_REQUEST; + ctrl.ldctl_iscritical = 0; + BER_BVZERO( &ctrl.ldctl_value ); + ctrls[0] = &ctrl; + ctrls[1] = NULL; + ctrlsp = ctrls; + } +#endif /* SLAP_AUTH_DN */ + + do { + rs->sr_err = ldap_sasl_interactive_bind( lc->lc_ld, binddn->bv_val, + li->li_idassert_sasl_mech.bv_val, + ctrlsp, NULL, LDAP_SASL_QUIET, lutil_sasl_interact, defaults, + result, &rmech, &msgid ); + + if ( rs->sr_err != LDAP_SASL_BIND_IN_PROGRESS ) + break; + + ldap_msgfree( result ); + + if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) { + ldap_get_option( lc->lc_ld, LDAP_OPT_RESULT_CODE, (void*)&rs->sr_err ); + ldap_get_option( lc->lc_ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&rs->sr_text ); + break; + } + } while ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS ); + + switch ( rs->sr_err ) { + case LDAP_SUCCESS: +#ifdef SLAP_AUTH_DN + /* FIXME: right now, the only reason to check + * response controls is RFC 3829 authzid */ + if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) { + ctrlsp = NULL; + rc = ldap_parse_result( lc->lc_ld, result, NULL, NULL, NULL, NULL, + &ctrlsp, 0 ); + if ( rc == LDAP_SUCCESS && ctrlsp ) { + LDAPControl *ctrl; + + ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE, + ctrlsp, NULL ); + if ( ctrl ) { + Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (authzid)\n", + op->o_log_prefix, ctrl->ldctl_value.bv_val, 0 ); + if ( ctrl->ldctl_value.bv_len > STRLENOF("dn:") && + strncasecmp( ctrl->ldctl_value.bv_val, "dn:", STRLENOF("dn:") ) == 0 ) + { + struct berval bv; + bv.bv_val = &ctrl->ldctl_value.bv_val[STRLENOF("dn:")]; + bv.bv_len = ctrl->ldctl_value.bv_len - STRLENOF("dn:"); + ber_bvreplace( &lc->lc_bound_ndn, &bv ); + } + } + } + + ldap_controls_free( ctrlsp ); + + } else if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_WHOAMI ) { + struct berval *val = NULL; + rc = ldap_whoami_s( lc->lc_ld, &val, NULL, NULL ); + if ( rc == LDAP_SUCCESS && val != NULL ) { + Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (whoami)\n", + op->o_log_prefix, val->bv_val, 0 ); + if ( val->bv_len > STRLENOF("dn:") && + strncasecmp( val->bv_val, "dn:", STRLENOF("dn:") ) == 0 ) + { + struct berval bv; + bv.bv_val = &val->bv_val[STRLENOF("dn:")]; + bv.bv_len = val->bv_len - STRLENOF("dn:"); + ber_bvreplace( &lc->lc_bound_ndn, &bv ); + } + ber_bvfree( val ); + } + } + + if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_MASK ) && + BER_BVISNULL( &lc->lc_bound_ndn ) ) + { + /* all in all, we only need it to be non-null */ + /* FIXME: should this be configurable? */ + static struct berval bv = BER_BVC("cn=authzdn"); + ber_bvreplace( &lc->lc_bound_ndn, &bv ); + } +#endif /* SLAP_AUTH_DN */ + op->o_conn->c_authz_cookie = op->o_bd->be_private; + LDAP_BACK_CONN_ISBOUND_SET( lc ); + break; + + case LDAP_LOCAL_ERROR: + /* list client API error codes that require + * to taint the connection */ + /* FIXME: should actually retry? */ + LDAP_BACK_CONN_TAINTED_SET( lc ); + + /* fallthru */ + + default: LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); + rs->sr_err = slap_map_api2result( rs ); if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); } + break; + } - } else { - LDAP_BACK_CONN_ISBOUND_SET( lc ); + if ( save_text != rs->sr_text ) { + ldap_memfree( (char *)rs->sr_text ); + rs->sr_text = save_text; } + ldap_msgfree( result ); + lutil_sasl_freedefs( defaults ); if ( freeauthz ) { slap_sl_free( authzID.bv_val, op->o_tmpmemctx ); @@ -2184,7 +2437,10 @@ ldap_back_proxy_authz_bind( * so that referral chasing is attempted using the right * identity */ LDAP_BACK_CONN_ISBOUND_SET( lc ); - ber_bvreplace( &lc->lc_bound_ndn, binddn ); + op->o_conn->c_authz_cookie = op->o_bd->be_private; + if ( !BER_BVISNULL( binddn ) ) { + ber_bvreplace( &lc->lc_bound_ndn, binddn ); + } if ( !BER_BVISNULL( &lc->lc_cred ) ) { memset( lc->lc_cred.bv_val, 0, @@ -2192,13 +2448,16 @@ ldap_back_proxy_authz_bind( } if ( LDAP_BACK_SAVECRED( li ) ) { - ber_bvreplace( &lc->lc_cred, bindcred ); - ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc ); + if ( !BER_BVISNULL( bindcred ) ) { + ber_bvreplace( &lc->lc_cred, bindcred ); + ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc ); + } } else { lc->lc_cred.bv_len = 0; } } + done:; return LDAP_BACK_CONN_ISBOUND( lc ); } @@ -2395,6 +2654,7 @@ ldap_back_proxy_authz_ctrl( } ctrl->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; + ctrl->ldctl_iscritical = ( ( si->si_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) == LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ); switch ( si->si_mode ) { /* already in u:ID or dn:DN form */ @@ -2518,7 +2778,7 @@ ldap_back_controls_add( LDAPControl **ctrls = NULL; /* set to the maximum number of controls this backend can add */ - LDAPControl c[ 2 ] = { 0 }; + LDAPControl c[ 2 ] = { { 0 } }; int n = 0, i, j1 = 0, j2 = 0; *pctrls = NULL; @@ -2589,7 +2849,7 @@ ldap_back_controls_add( goto done; } - assert( j1 + j1 <= sizeof( c )/sizeof(LDAPControl) ); + assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) ); if ( op->o_ctrls ) { for ( n = 0; op->o_ctrls[ n ]; n++ ) @@ -2644,8 +2904,8 @@ ldap_back_controls_free( Operation *op, SlapReply *rs, LDAPControl ***pctrls ) /* we assume that the controls added by the proxy come first, * so as soon as we find op->o_ctrls[ 0 ] we can stop */ if ( ctrls && ctrls != op->o_ctrls ) { - int i = 0, n = 0, n_added; - void *lower, *upper; + int i = 0, n = 0, n_added; + LDAPControl *lower, *upper; assert( ctrls[ 0 ] != NULL ); @@ -2658,8 +2918,8 @@ ldap_back_controls_free( Operation *op, SlapReply *rs, LDAPControl ***pctrls ) } n_added = n - i; - lower = ctrls + n; - upper = lower + sizeof( LDAPControl ) * n_added; + lower = (LDAPControl *)&ctrls[ n ]; + upper = &lower[ n_added ]; for ( i = 0; ctrls[ i ] != NULL; i++ ) { if ( ctrls[ i ] < lower || ctrls[ i ] >= upper ) { @@ -2679,3 +2939,84 @@ ldap_back_controls_free( Operation *op, SlapReply *rs, LDAPControl ***pctrls ) return 0; } + +int +ldap_back_conn2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen ) +{ + char tbuf[ SLAP_TEXT_BUFLEN ]; + char *ptr = buf, *end = buf + buflen; + int len; + + if ( ptr + sizeof("conn=") > end ) return -1; + ptr = lutil_strcopy( ptr, "conn=" ); + + len = ldap_back_connid2str( lc, ptr, (ber_len_t)(end - ptr) ); + ptr += len; + if ( ptr >= end ) return -1; + + if ( !BER_BVISNULL( &lc->lcb_local_ndn ) ) { + if ( ptr + sizeof(" DN=\"\"") + lc->lcb_local_ndn.bv_len > end ) return -1; + ptr = lutil_strcopy( ptr, " DN=\"" ); + ptr = lutil_strncopy( ptr, lc->lcb_local_ndn.bv_val, lc->lcb_local_ndn.bv_len ); + *ptr++ = '"'; + } + + if ( lc->lcb_create_time != 0 ) { + len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_create_time ); + if ( ptr + sizeof(" created=") + len >= end ) return -1; + ptr = lutil_strcopy( ptr, " created=" ); + ptr = lutil_strcopy( ptr, tbuf ); + } + + if ( lc->lcb_time != 0 ) { + len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_time ); + if ( ptr + sizeof(" modified=") + len >= end ) return -1; + ptr = lutil_strcopy( ptr, " modified=" ); + ptr = lutil_strcopy( ptr, tbuf ); + } + + len = snprintf( tbuf, sizeof(tbuf), "%u", lc->lcb_refcnt ); + if ( ptr + sizeof(" refcnt=") + len >= end ) return -1; + ptr = lutil_strcopy( ptr, " refcnt=" ); + ptr = lutil_strcopy( ptr, tbuf ); + + return ptr - buf; +} + +int +ldap_back_connid2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen ) +{ + static struct berval conns[] = { + BER_BVC("ROOTDN"), + BER_BVC("ROOTDN-TLS"), + BER_BVC("ANON"), + BER_BVC("ANON-TLS"), + BER_BVC("BIND"), + BER_BVC("BIND-TLS"), + BER_BVNULL + }; + + int len = 0; + + if ( LDAP_BACK_PCONN_ISPRIV( (const ldapconn_t *)lc ) ) { + long cid; + struct berval *bv; + + cid = (long)lc->lcb_conn; + assert( cid >= LDAP_BACK_PCONN_FIRST && cid < LDAP_BACK_PCONN_LAST ); + + bv = &conns[ cid ]; + + if ( bv->bv_len >= buflen ) { + return bv->bv_len + 1; + } + + len = bv->bv_len; + lutil_strncopy( buf, bv->bv_val, bv->bv_len + 1 ); + + } else { + len = snprintf( buf, buflen, "%lu", lc->lcb_conn->c_connid ); + } + + return len; +}