diff options
Diffstat (limited to 'ldap/servers/plugins/chainingdb/cb_bind.c')
-rw-r--r-- | ldap/servers/plugins/chainingdb/cb_bind.c | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/ldap/servers/plugins/chainingdb/cb_bind.c b/ldap/servers/plugins/chainingdb/cb_bind.c new file mode 100644 index 00000000..495b672f --- /dev/null +++ b/ldap/servers/plugins/chainingdb/cb_bind.c @@ -0,0 +1,290 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#include "cb.h" + +static void +cb_free_bervals( struct berval **bvs ); + + +static int +cb_sasl_bind_once_s( cb_conn_pool *pool, char *dn, int method, char * mechanism, + struct berval *creds, LDAPControl **reqctrls, + char **matcheddnp, char **errmsgp, struct berval ***refurlsp, + LDAPControl ***resctrlsp , int * status); + +/* + * Attempt to chain a bind request off to "srvr." We return an LDAP error + * code that indicates whether we successfully got a response from the + * other server or not. If we succeed, we return LDAP_SUCCESS and *lderrnop + * is set to the result code from the remote server. + * + * Note that in the face of "ldap server down" or "ldap connect failed" errors + * we make up to "tries" attempts to bind to the remote server. Since we + * are only interested in recovering silently when the remote server is up + * but decided to close our connection, we retry without pausing between + * attempts. + */ + +static int +cb_sasl_bind_s(Slapi_PBlock * pb, cb_conn_pool *pool, int tries, + char *dn, int method,char * mechanism, struct berval *creds, LDAPControl **reqctrls, + char **matcheddnp, char **errmsgp, struct berval ***refurlsp, + LDAPControl ***resctrlsp ,int *status) { + + int rc; + + do { + /* check to see if operation has been abandoned...*/ + + if (LDAP_AUTH_SIMPLE!=method) + return LDAP_AUTH_METHOD_NOT_SUPPORTED; + + if ( slapi_op_abandoned( pb )) { + rc = LDAP_USER_CANCELLED; + } else { + rc = cb_sasl_bind_once_s( pool, dn, method,mechanism, creds, reqctrls, + matcheddnp, errmsgp, refurlsp, resctrlsp ,status); + } + } while ( CB_LDAP_CONN_ERROR( rc ) && --tries > 0 ); + + return( rc ); +} + +static int +cb_sasl_bind_once_s( cb_conn_pool *pool, char *dn, int method, char * mechanism, + struct berval *creds, LDAPControl **reqctrls, + char **matcheddnp, char **errmsgp, struct berval ***refurlsp, + LDAPControl ***resctrlsp , int * status) { + + int rc, msgid; + char **referrals; + struct timeval timeout_copy, *timeout; + LDAPMessage *result=NULL; + LDAP *ld=NULL; + char *cnxerrbuf=NULL; + cb_outgoing_conn *cnx; + int version=LDAP_VERSION3; + + /* Grab an LDAP connection to use for this bind. */ + + PR_RWLock_Rlock(pool->rwl_config_lock); + timeout_copy.tv_sec = pool->conn.bind_timeout.tv_sec; + timeout_copy.tv_usec = pool->conn.bind_timeout.tv_usec; + PR_RWLock_Unlock(pool->rwl_config_lock); + + if (( rc = cb_get_connection( pool, &ld ,&cnx, NULL, &cnxerrbuf)) != LDAP_SUCCESS ) { + *errmsgp=cnxerrbuf; + goto release_and_return; + } + + /* Send the bind operation (need to retry on LDAP_SERVER_DOWN) */ + + ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); + + if (( rc = ldap_sasl_bind( ld, dn, LDAP_SASL_SIMPLE, creds, reqctrls, + NULL, &msgid )) != LDAP_SUCCESS ) { + goto release_and_return; + } + + /* XXXSD what is the exact semantics of bind_to ? it is used to get a + connection handle and later to bind ==> bind op may last 2*bind_to + from the user point of view + confusion comes from teh fact that bind to is used 2for 3 differnt thinks, + */ + + /* + * determine timeout value (how long we will wait for a response) + * if timeout is zero'd, we wait indefinitely. + */ + if ( timeout_copy.tv_sec == 0 && timeout_copy.tv_usec == 0 ) { + timeout = NULL; + } else { + timeout = &timeout_copy; + } + + /* + * Wait for a result. + */ + rc = ldap_result( ld, msgid, 1, timeout, &result ); + + /* + * Interpret the result. + */ + + if ( rc == 0 ) { /* timeout */ + /* + * Timed out waiting for a reply from the server. + */ + rc = LDAP_TIMEOUT; + } else if ( rc < 0 ) { + + /* Some other error occurred (no result received). */ + char * matcheddnp2, * errmsgp2; + matcheddnp2=errmsgp2=NULL; + + rc = ldap_get_lderrno( ld, &matcheddnp2, &errmsgp2 ); + + /* Need to allocate errmsgs */ + if (matcheddnp2) + *matcheddnp=slapi_ch_strdup(matcheddnp2); + if (errmsgp2) + *errmsgp=slapi_ch_strdup(errmsgp2); + + if ( LDAP_SUCCESS != rc ) { + slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM, + "cb_sasl_bind_once_s failed (%s)\n",ldap_err2string(rc)); + } + } else { + + /* Got a result from remote server -- parse it.*/ + + char * matcheddnp2, * errmsgp2; + matcheddnp2=errmsgp2=NULL; + *resctrlsp=NULL; + rc = ldap_parse_result( ld, result, status, matcheddnp, errmsgp, + &referrals, resctrlsp, 1 ); + if ( referrals != NULL ) { + *refurlsp = referrals2berval( referrals ); + ldap_value_free( referrals ); + } + /* realloc matcheddn & errmsg because the mem alloc model */ + /* may differ from malloc */ + if (matcheddnp2) { + *matcheddnp=slapi_ch_strdup(matcheddnp2); + ldap_memfree(matcheddnp2); + } + if (errmsgp2) { + *errmsgp=slapi_ch_strdup(errmsgp2); + ldap_memfree(errmsgp2); + } + + } + +release_and_return: + if ( ld != NULL ) { + cb_release_op_connection( pool, ld, CB_LDAP_CONN_ERROR( rc )); + } + + return( rc ); +} + +int +chainingdb_bind( Slapi_PBlock *pb ) { + + int status=LDAP_SUCCESS; + int allocated_errmsg; + int rc=LDAP_SUCCESS; + cb_backend_instance *cb; + Slapi_Backend *be; + char *dn; + int method; + struct berval *creds, **urls; + char *matcheddn,*errmsg; + LDAPControl **reqctrls, **resctrls, **ctrls; + char * mechanism; + int freectrls=1; + int bind_retry; + + if ( LDAP_SUCCESS != (rc = cb_forward_operation(pb) )) { + cb_send_ldap_result( pb, rc, NULL, "Chaining forbidden", 0, NULL ); + return SLAPI_BIND_FAIL; + } + + ctrls=NULL; + /* don't add proxy auth control. use this call to check for supported */ + /* controls only. */ + if ( LDAP_SUCCESS != ( rc = cb_update_controls( pb, NULL, &ctrls, 0 )) ) { + cb_send_ldap_result( pb, rc, NULL, NULL, 0, NULL ); + if (ctrls) + ldap_controls_free(ctrls); + return SLAPI_BIND_FAIL; + } + if (ctrls) + ldap_controls_free(ctrls); + + slapi_pblock_get( pb, SLAPI_BACKEND, &be ); + slapi_pblock_get( pb, SLAPI_BIND_TARGET, &dn ); + slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ); + slapi_pblock_get( pb, SLAPI_BIND_SASLMECHANISM, &mechanism); + slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &creds ); + slapi_pblock_get( pb, SLAPI_REQCONTROLS, &reqctrls ); + cb = cb_get_instance(be); + + if ( NULL == dn ) + dn=""; + + /* always allow noauth simple binds */ + if (( method == LDAP_AUTH_SIMPLE) && creds->bv_len == 0 ) { + return( SLAPI_BIND_ANONYMOUS ); + } + + cb_update_monitor_info(pb,cb,SLAPI_OPERATION_BIND); + + matcheddn=errmsg=NULL; + allocated_errmsg = 0; + resctrls=NULL; + urls=NULL; + + /* Check wether the chaining BE is available or not */ + if ( cb_check_availability( cb, pb ) == FARMSERVER_UNAVAILABLE ){ + return -1; + } + + PR_RWLock_Rlock(cb->rwl_config_lock); + bind_retry=cb->bind_retry; + PR_RWLock_Unlock(cb->rwl_config_lock); + + if ( LDAP_SUCCESS == (rc = cb_sasl_bind_s(pb, cb->bind_pool, bind_retry, dn,method,mechanism, + creds,reqctrls,&matcheddn,&errmsg,&urls,&resctrls, &status))) { + rc = status; + allocated_errmsg = 1; + } else + if ( LDAP_USER_CANCELLED != rc ) { + errmsg = ldap_err2string( rc ); + if (rc == LDAP_TIMEOUT) { + cb_ping_farm(cb,NULL,NULL); + } + rc = LDAP_OPERATIONS_ERROR; + } + + if ( rc != LDAP_USER_CANCELLED ) { /* not abandoned */ + if ( resctrls != NULL ) { + slapi_pblock_set( pb, SLAPI_RESCONTROLS, resctrls ); + freectrls=0; + } + + if ( rc != LDAP_SUCCESS ) { + cb_send_ldap_result( pb, rc, matcheddn, errmsg, 0, urls ); + } + } + + if ( urls != NULL ) { + cb_free_bervals( urls ); + } + if ( freectrls && ( resctrls != NULL )) { + ldap_controls_free( resctrls ); + } + slapi_ch_free((void **)& matcheddn ); + if ( allocated_errmsg && errmsg != NULL ) { + slapi_ch_free((void **)& errmsg ); + } + + return ((rc == LDAP_SUCCESS ) ? SLAPI_BIND_SUCCESS : SLAPI_BIND_FAIL ); +} + +static void +cb_free_bervals( struct berval **bvs ) +{ + int i; + + if ( bvs != NULL ) { + for ( i = 0; bvs[ i ] != NULL; ++i ) { + slapi_ch_free( (void **)&bvs[ i ] ); + } + } + slapi_ch_free( (void **)&bvs ); +} + |