From: Ondřej Kuzník Date: Fri, 17 Mar 2017 14:32:06 +0000 (+0000) Subject: Authenticate the upstream connection if configured X-Git-Tag: OPENLDAP_REL_ENG_2_5_1ALPHA~18^2~211 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3d1ea4693e8420940703fd30d349254c6bbed645;p=thirdparty%2Fopenldap.git Authenticate the upstream connection if configured --- diff --git a/servers/lloadd/config.c b/servers/lloadd/config.c index 9b6e82fd9a..405f311b36 100644 --- a/servers/lloadd/config.c +++ b/servers/lloadd/config.c @@ -448,6 +448,20 @@ config_backend( ConfigArgs *c ) } } + if ( b->b_bindconf.sb_method == LDAP_AUTH_SASL ) { +#ifndef HAVE_CYRUS_SASL + Debug( LDAP_DEBUG_ANY, "config_backend: " + "no sasl support available\n" ); + rc = -1; + goto done; +#else /* HAVE_CYRUS_SASL */ + Debug( LDAP_DEBUG_ANY, "config_backend: " + "no sasl support yet\n" ); + rc = -1; + goto done; +#endif + } + if ( BER_BVISNULL( &b->b_bindconf.sb_uri ) ) { Debug( LDAP_DEBUG_ANY, "config_backend: " "backend address not specified\n" ); diff --git a/servers/lloadd/upstream.c b/servers/lloadd/upstream.c index bdc62acfab..e72465edd2 100644 --- a/servers/lloadd/upstream.c +++ b/servers/lloadd/upstream.c @@ -138,6 +138,136 @@ fail: upstream_destroy( c ); } +void +upstream_finish( Connection *c ) +{ + struct event_base *base; + struct event *event; + evutil_socket_t s = c->c_fd; + + Debug( LDAP_DEBUG_CONNS, "upstream_finish: " + "connection %lu is ready for use\n", c->c_connid ); + + base = slap_get_base( s ); + + event = event_new( base, s, EV_READ|EV_PERSIST, upstream_read_cb, c ); + if ( !event ) { + Debug( LDAP_DEBUG_ANY, "Read event could not be allocated\n" ); + goto fail; + } + event_add( event, NULL ); + if ( c->c_read_event ) { + event_del( c->c_read_event ); + event_free( c->c_read_event ); + } + c->c_read_event = event; + + c->c_state = SLAP_C_READY; + + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + return; +fail: + if ( c->c_write_event ) { + event_del( c->c_write_event ); + event_free( c->c_write_event ); + } + if ( c->c_read_event ) { + event_del( c->c_read_event ); + event_free( c->c_read_event ); + } + upstream_destroy( c ); + return; +} + +void +upstream_bind_cb( evutil_socket_t s, short what, void *arg ) +{ + Connection *c = arg; + BerElement *ber; + char *matcheddn = NULL, *message = NULL; + ber_tag_t tag; + ber_len_t len; + ber_int_t msgid, result; + + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + Debug( LDAP_DEBUG_CONNS, "upstream_bind_cb: " + "connection %lu ready to read\n", + c->c_connid ); + + ber = c->c_currentber; + if ( ber == NULL && (ber = ber_alloc()) == NULL ) { + Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n" ); + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + return; + } + + tag = ber_get_next( c->c_sb, &len, ber ); + if ( tag != LDAP_TAG_MESSAGE ) { + int err = sock_errno(); + + if ( err != EWOULDBLOCK && err != EAGAIN ) { + char ebuf[128]; + Debug( LDAP_DEBUG_ANY, "ber_get_next on fd %d failed errno=%d (%s)\n", c->c_fd, + err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); + + c->c_currentber = NULL; + goto fail; + } + c->c_currentber = ber; + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + return; + } + c->c_currentber = NULL; + + if ( ber_scanf( ber, "it", &msgid, &tag ) == LBER_ERROR ) { + Debug( LDAP_DEBUG_ANY, "upstream_bind_cb:" + " protocol violation from server\n" ); + goto fail; + } + + if ( msgid != ( c->c_next_msgid - 1 ) || tag != LDAP_RES_BIND ) { + Debug( LDAP_DEBUG_ANY, "upstream_bind_cb:" + " unexpected response from server, msgid=%d tag=%lu\n", + msgid, tag ); + goto fail; + } + + if ( ber_scanf( ber, "{eAA" /* "}" */, &result, &matcheddn, &message ) == + LBER_ERROR ) { + Debug( LDAP_DEBUG_ANY, "upstream_bind_cb:" + " response does not conform with a bind response\n" ); + goto fail; + } + + switch ( result ) { + case LDAP_SUCCESS: + upstream_finish( c ); + break; +#ifdef HAVE_CYRUS_SASL + case LDAP_SASL_BIND_IN_PROGRESS: + /* TODO: fallthrough until we implement SASL */ +#endif /* HAVE_CYRUS_SASL */ + default: + Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: " + "upstream bind failed, rc=%d, message='%s'\n", + result, message ); + goto fail; + } + + if ( matcheddn ) ber_memfree( matcheddn ); + if ( message ) ber_memfree( message ); + + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + + return; +fail: + if ( matcheddn ) ber_memfree( matcheddn ); + if ( message ) ber_memfree( message ); + + ber_free( ber, 1 ); + upstream_destroy( c ); +} + void upstream_write_cb( evutil_socket_t s, short what, void *arg ) { @@ -159,32 +289,96 @@ upstream_write_cb( evutil_socket_t s, short what, void *arg ) upstream_destroy( c ); return; } - event_add( c->c_write_event, 0 ); + event_add( c->c_write_event, NULL ); } c->c_pendingber = NULL; ldap_pvt_thread_mutex_unlock( &c->c_io_mutex ); } -Connection * -upstream_init( ber_socket_t s, Backend *backend ) +void * +upstream_bind( void *ctx, void *arg ) { - Connection *c; - struct event_base *base = slap_get_base( s ); + Connection *c = arg; + Backend *b; + BerElement *ber = ber_alloc(); + struct event_base *base; struct event *event; - int flags = (backend->b_tls == LLOAD_LDAPS) ? CONN_IS_TLS : 0; + ber_int_t msgid; + evutil_socket_t s; + int rc; - assert( backend != NULL ); + assert( ber ); - c = connection_init( s, backend->b_host, flags ); + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + b = c->c_private; + s = c->c_fd; + base = slap_get_base( s ); - event = event_new( base, s, EV_READ|EV_PERSIST, upstream_read_cb, c ); + event = event_new( base, s, EV_READ|EV_PERSIST, upstream_bind_cb, c ); if ( !event ) { Debug( LDAP_DEBUG_ANY, "Read event could not be allocated\n" ); - goto fail; + upstream_destroy( c ); + return NULL; } event_add( event, NULL ); + if ( c->c_read_event ) { + event_del( c->c_read_event ); + event_free( c->c_read_event ); + } c->c_read_event = event; + msgid = c->c_next_msgid++; + + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + + ldap_pvt_thread_mutex_lock( &b->b_lock ); + if ( b->b_bindconf.sb_method == LDAP_AUTH_SIMPLE ) { + /* simple bind */ + rc = ber_printf( ber, "{it{iOtON}}", + msgid, LDAP_REQ_BIND, LDAP_VERSION3, + &b->b_bindconf.sb_binddn, LDAP_AUTH_SIMPLE, + &b->b_bindconf.sb_cred ); + +#ifdef HAVE_CYRUS_SASL + } else { + BerValue cred; + if ( BER_BVISNULL( &cred ) ) { + rc = ber_printf( ber, "{it{iOt{sN}N}}", + msgid, LDAP_REQ_BIND, LDAP_VERSION3, + &b->b_bindconf.sb_binddn, LDAP_AUTH_SASL, + b->b_bindconf.sb_method ); + } else { + rc = ber_printf( ber, "{it{iOt{sON}N}}", + msgid, LDAP_REQ_BIND, LDAP_VERSION3, + &b->b_bindconf.sb_binddn, LDAP_AUTH_SASL, + b->b_bindconf.sb_method, &cred ); + } +#endif /* HAVE_CYRUS_SASL */ + } + ldap_pvt_thread_mutex_unlock( &b->b_lock ); + + ldap_pvt_thread_mutex_lock( &c->c_io_mutex ); + c->c_pendingber = ber; + ldap_pvt_thread_mutex_unlock( &c->c_io_mutex ); + + upstream_write_cb( -1, 0, c ); + + return NULL; +} + +Connection * +upstream_init( ber_socket_t s, Backend *b ) +{ + Connection *c; + struct event_base *base = slap_get_base( s ); + struct event *event; + int flags = (b->b_tls == LLOAD_LDAPS) ? CONN_IS_TLS : 0; + + assert( b != NULL ); + + c = connection_init( s, b->b_host, flags ); + c->c_private = b; + event = event_new( base, s, EV_WRITE, upstream_write_cb, c ); if ( !event ) { Debug( LDAP_DEBUG_ANY, "Write event could not be allocated\n" ); @@ -193,9 +387,12 @@ upstream_init( ber_socket_t s, Backend *backend ) /* We only register the write event when we have data pending */ c->c_write_event = event; - c->c_private = backend; + if ( b->b_bindconf.sb_method == LDAP_AUTH_NONE ) { + upstream_finish( c ); + } else { + ldap_pvt_thread_pool_submit( &connection_pool, upstream_bind, c ); + } - c->c_state = SLAP_C_READY; ldap_pvt_thread_mutex_unlock( &c->c_mutex ); return c;