mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-01-30 13:30:57 +08:00
Client TLS support
This commit is contained in:
parent
a0cd41ecd2
commit
1b46f86627
@ -240,6 +240,99 @@ handle_one_request( Connection *c )
|
||||
return handler( c, op );
|
||||
}
|
||||
|
||||
/*
|
||||
* The connection has a token assigned to it when the callback is set up.
|
||||
*/
|
||||
void
|
||||
client_tls_handshake_cb( evutil_socket_t s, short what, void *arg )
|
||||
{
|
||||
Connection *c = arg;
|
||||
int rc = 0;
|
||||
|
||||
CONNECTION_LOCK_DECREF(c);
|
||||
if ( what & EV_TIMEOUT ) {
|
||||
Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: "
|
||||
"connid=%lu, timeout reached, destroying\n",
|
||||
c->c_connid );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case of StartTLS, make sure we flush the response first.
|
||||
* Also before we try to read anything from the connection, it isn't
|
||||
* permitted to Abandon a StartTLS exop per RFC4511 anyway.
|
||||
*/
|
||||
ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
|
||||
if ( c->c_pendingber ) {
|
||||
ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
|
||||
CONNECTION_UNLOCK_INCREF(c);
|
||||
connection_write_cb( s, what, arg );
|
||||
ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
|
||||
CONNECTION_LOCK_DECREF(c);
|
||||
|
||||
if ( !c->c_live ) {
|
||||
ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Do we still have data pending? If so, connection_write_cb would
|
||||
* already have arranged the write callback to trigger again */
|
||||
if ( c->c_pendingber ) {
|
||||
ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
|
||||
CONNECTION_UNLOCK_INCREF(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
|
||||
|
||||
rc = ldap_pvt_tls_accept( c->c_sb, slap_tls_ctx );
|
||||
if ( rc < 0 ) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( rc == 0 ) {
|
||||
struct event_base *base = event_get_base( c->c_read_event );
|
||||
|
||||
/*
|
||||
* We're finished, replace the callbacks
|
||||
*
|
||||
* This is deadlock-safe, since both share the same base - the one
|
||||
* that's just running us.
|
||||
*/
|
||||
event_del( c->c_read_event );
|
||||
event_del( c->c_write_event );
|
||||
|
||||
event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST,
|
||||
connection_read_cb, c );
|
||||
event_add( c->c_read_event, NULL );
|
||||
|
||||
event_assign( c->c_write_event, base, c->c_fd, EV_WRITE,
|
||||
connection_write_cb, c );
|
||||
Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: "
|
||||
"connid=%lu finished\n",
|
||||
c->c_connid );
|
||||
|
||||
c->c_is_tls = LLOAD_TLS_ESTABLISHED;
|
||||
|
||||
/* The temporary reference established for us is no longer needed */
|
||||
CONNECTION_UNLOCK_OR_DESTROY(c);
|
||||
return;
|
||||
} else if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) {
|
||||
event_add( c->c_write_event, lload_write_timeout );
|
||||
Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: "
|
||||
"connid=%lu need write rc=%d\n",
|
||||
c->c_connid, rc );
|
||||
}
|
||||
CONNECTION_UNLOCK_INCREF(c);
|
||||
return;
|
||||
|
||||
fail:
|
||||
Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: "
|
||||
"connid=%lu failed rc=%d\n",
|
||||
c->c_connid, rc );
|
||||
CONNECTION_DESTROY(c);
|
||||
}
|
||||
|
||||
Connection *
|
||||
client_init(
|
||||
ber_socket_t s,
|
||||
@ -266,6 +359,25 @@ client_init(
|
||||
|
||||
c->c_state = LLOAD_C_READY;
|
||||
|
||||
if ( flags & CONN_IS_TLS ) {
|
||||
int rc;
|
||||
|
||||
c->c_is_tls = LLOAD_LDAPS;
|
||||
|
||||
rc = ldap_pvt_tls_accept( c->c_sb, slap_tls_ctx );
|
||||
if ( rc < 0 ) {
|
||||
Debug( LDAP_DEBUG_CONNS, "client_init: "
|
||||
"connid=%lu failed initial TLS accept rc=%d\n",
|
||||
c->c_connid, rc );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( rc ) {
|
||||
c->c_refcnt++;
|
||||
read_cb = write_cb = client_tls_handshake_cb;
|
||||
}
|
||||
}
|
||||
|
||||
event = event_new( base, s, EV_READ|EV_PERSIST, read_cb, c );
|
||||
if ( !event ) {
|
||||
Debug( LDAP_DEBUG_ANY, "client_init: "
|
||||
|
@ -22,6 +22,82 @@
|
||||
|
||||
Avlnode *lload_exop_handlers = NULL;
|
||||
|
||||
int
|
||||
handle_starttls( Connection *c, Operation *op )
|
||||
{
|
||||
struct event_base *base = event_get_base( c->c_read_event );
|
||||
BerElement *output;
|
||||
char *msg = NULL;
|
||||
int rc = LDAP_SUCCESS;
|
||||
|
||||
tavl_delete( &c->c_ops, op, operation_client_cmp );
|
||||
|
||||
if ( c->c_is_tls == LLOAD_TLS_ESTABLISHED ) {
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
msg = "TLS layer already in effect";
|
||||
} else if ( c->c_state == LLOAD_C_BINDING ) {
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
msg = "bind in progress";
|
||||
} else if ( c->c_ops ) {
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
msg = "cannot start TLS when operations are outstanding";
|
||||
} else if ( !slap_tls_ctx ) {
|
||||
rc = LDAP_UNAVAILABLE;
|
||||
msg = "Could not initialize TLS";
|
||||
}
|
||||
|
||||
Debug( LDAP_DEBUG_STATS, "handle_starttls: "
|
||||
"handling StartTLS exop connid=%lu rc=%d msg=%s\n",
|
||||
c->c_connid, rc, msg );
|
||||
|
||||
if ( rc ) {
|
||||
/* We've already removed the operation from the queue */
|
||||
return operation_send_reject_locked( op, rc, msg, 1 );
|
||||
}
|
||||
|
||||
CONNECTION_UNLOCK_INCREF(c);
|
||||
|
||||
event_del( c->c_read_event );
|
||||
event_del( c->c_write_event );
|
||||
/*
|
||||
* At this point, we are the only thread handling the connection:
|
||||
* - there are no upstream operations
|
||||
* - the I/O callbacks have been successfully removed
|
||||
*
|
||||
* This means we can safely reconfigure both I/O events now.
|
||||
*/
|
||||
|
||||
ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
|
||||
output = c->c_pendingber;
|
||||
if ( output == NULL && (output = ber_alloc()) == NULL ) {
|
||||
ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
|
||||
CONNECTION_LOCK_DECREF(c);
|
||||
operation_destroy_from_client( op );
|
||||
CONNECTION_DESTROY(c);
|
||||
return -1;
|
||||
}
|
||||
c->c_pendingber = output;
|
||||
ber_printf( output, "t{tit{ess}}", LDAP_TAG_MESSAGE,
|
||||
LDAP_TAG_MSGID, op->o_client_msgid,
|
||||
LDAP_RES_EXTENDED, LDAP_SUCCESS, "", "" );
|
||||
ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
|
||||
|
||||
CONNECTION_LOCK_DECREF(c);
|
||||
event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST,
|
||||
client_tls_handshake_cb, c );
|
||||
event_add( c->c_read_event, NULL );
|
||||
|
||||
event_assign( c->c_write_event, base, c->c_fd, EV_WRITE,
|
||||
client_tls_handshake_cb, c );
|
||||
/* We already have something to write */
|
||||
event_add( c->c_write_event, lload_write_timeout );
|
||||
|
||||
operation_destroy_from_client( op );
|
||||
CONNECTION_UNLOCK_INCREF(c);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
request_extended( Connection *c, Operation *op )
|
||||
{
|
||||
@ -67,7 +143,9 @@ request_extended( Connection *c, Operation *op )
|
||||
return request_process( c, op );
|
||||
}
|
||||
|
||||
ExopHandler lload_exops[] = { { BER_BVNULL }
|
||||
ExopHandler lload_exops[] = {
|
||||
{ BER_BVC(LDAP_EXOP_START_TLS), handle_starttls },
|
||||
{ BER_BVNULL }
|
||||
};
|
||||
|
||||
int
|
||||
|
@ -74,6 +74,7 @@ LDAP_SLAPD_F (int) handle_vc_bind_response( Operation *op, BerElement *ber );
|
||||
LDAP_SLAPD_F (int) request_abandon( Connection *c, Operation *op );
|
||||
LDAP_SLAPD_F (int) request_process( Connection *c, Operation *op );
|
||||
LDAP_SLAPD_F (int) handle_one_request( Connection *c );
|
||||
LDAP_SLAPD_F (void) client_tls_handshake_cb( evutil_socket_t s, short what, void *arg );
|
||||
LDAP_SLAPD_F (Connection *) client_init( ber_socket_t s, Listener *url, const char *peername, struct event_base *base, int use_tls );
|
||||
LDAP_SLAPD_F (void) client_reset( Connection *c );
|
||||
LDAP_SLAPD_F (void) client_destroy( Connection *c );
|
||||
|
Loading…
Reference in New Issue
Block a user