mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-21 07:09:34 -05:00
Upstream TLS support
This commit is contained in:
parent
063981a06d
commit
a0cd41ecd2
4 changed files with 213 additions and 31 deletions
|
|
@ -569,13 +569,14 @@ config_backend( ConfigArgs *c )
|
|||
}
|
||||
|
||||
#else /* HAVE_TLS */
|
||||
/* Specifying ldaps:// overrides starttls= settings */
|
||||
tmp = ldap_pvt_url_scheme2tls( lud->lud_scheme );
|
||||
if ( tmp ) {
|
||||
b->b_tls = LLOAD_LDAPS;
|
||||
}
|
||||
|
||||
if ( !lud->lud_port ) {
|
||||
b->b_port = b->b_tls ? LDAPS_PORT : LDAP_PORT;
|
||||
b->b_port = tmp ? LDAPS_PORT : LDAP_PORT;
|
||||
} else {
|
||||
b->b_port = lud->lud_port;
|
||||
}
|
||||
|
|
@ -1829,9 +1830,9 @@ config_push_cleanup( ConfigArgs *ca, ConfigDriver *cleanup )
|
|||
}
|
||||
|
||||
static slap_verbmasks tlskey[] = {
|
||||
{ BER_BVC("no"), SB_TLS_OFF },
|
||||
{ BER_BVC("yes"), SB_TLS_ON },
|
||||
{ BER_BVC("critical"), SB_TLS_CRITICAL },
|
||||
{ BER_BVC("no"), LLOAD_CLEARTEXT },
|
||||
{ BER_BVC("yes"), LLOAD_STARTTLS_OPTIONAL },
|
||||
{ BER_BVC("critical"), LLOAD_STARTTLS },
|
||||
{ BER_BVNULL, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -1955,6 +1956,7 @@ static slap_cf_aux_table backendkey[] = {
|
|||
|
||||
{ BER_BVC("max-pending-ops="), offsetof(Backend, b_max_pending), 'i', 0, NULL },
|
||||
{ BER_BVC("conn-max-pending="), offsetof(Backend, b_max_conn_pending), 'i', 0, NULL },
|
||||
{ BER_BVC("starttls="), offsetof(Backend, b_tls), 'i', 0, tlskey },
|
||||
{ BER_BVNULL, 0, 0, 0, NULL }
|
||||
};
|
||||
|
||||
|
|
@ -1971,7 +1973,6 @@ static slap_cf_aux_table bindkey[] = {
|
|||
{ BER_BVC("authzID="), offsetof(slap_bindconf, sb_authzId), 'b', 1, NULL },
|
||||
{ BER_BVC("keepalive="), offsetof(slap_bindconf, sb_keepalive), 'x', 0, (slap_verbmasks *)slap_keepalive_parse },
|
||||
#ifdef HAVE_TLS
|
||||
{ BER_BVC("starttls="), offsetof(slap_bindconf, sb_tls), 'i', 0, tlskey },
|
||||
{ BER_BVC("tls_cert="), offsetof(slap_bindconf, sb_tls_cert), 's', 1, NULL },
|
||||
{ BER_BVC("tls_key="), offsetof(slap_bindconf, sb_tls_key), 's', 1, NULL },
|
||||
{ BER_BVC("tls_cacert="), offsetof(slap_bindconf, sb_tls_cacert), 's', 1, NULL },
|
||||
|
|
|
|||
|
|
@ -335,10 +335,6 @@ connection_init( ber_socket_t s, const char *peername, int flags )
|
|||
|
||||
assert( peername != NULL );
|
||||
|
||||
#ifndef HAVE_TLS
|
||||
assert( !(flags & CONN_IS_TLS) );
|
||||
#endif
|
||||
|
||||
if ( s == AC_SOCKET_INVALID ) {
|
||||
Debug( LDAP_DEBUG_ANY, "connection_init: "
|
||||
"init of socket fd=%ld invalid\n",
|
||||
|
|
@ -362,10 +358,6 @@ connection_init( ber_socket_t s, const char *peername, int flags )
|
|||
#endif
|
||||
ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_fd,
|
||||
LBER_SBIOD_LEVEL_PROVIDER, (void *)&s );
|
||||
#ifdef LDAP_PF_LOCAL_SENDMSG
|
||||
if ( !BER_BVISEMPTY( peerbv ) )
|
||||
ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_UNGET_BUF, peerbv );
|
||||
#endif
|
||||
} else
|
||||
#endif /* LDAP_PF_LOCAL */
|
||||
{
|
||||
|
|
@ -382,18 +374,6 @@ connection_init( ber_socket_t s, const char *peername, int flags )
|
|||
c->c_sb, &ber_sockbuf_io_debug, INT_MAX, (void *)"lload_" );
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TLS
|
||||
if ( flags & CONN_IS_TLS ) {
|
||||
/* TODO: will need an asynchronous TLS implementation in libldap */
|
||||
assert(0);
|
||||
c->c_is_tls = 1;
|
||||
c->c_needs_tls_accept = 1;
|
||||
} else {
|
||||
c->c_is_tls = 0;
|
||||
c->c_needs_tls_accept = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
c->c_next_msgid = 1;
|
||||
c->c_refcnt = c->c_live = 1;
|
||||
c->c_destroy = connection_destroy;
|
||||
|
|
|
|||
|
|
@ -244,7 +244,9 @@ typedef enum {
|
|||
enum lload_tls_type {
|
||||
LLOAD_CLEARTEXT = 0,
|
||||
LLOAD_LDAPS,
|
||||
LLOAD_STARTTLS_OPTIONAL,
|
||||
LLOAD_STARTTLS,
|
||||
LLOAD_TLS_ESTABLISHED,
|
||||
};
|
||||
|
||||
struct PendingConnection {
|
||||
|
|
@ -405,7 +407,6 @@ struct Connection {
|
|||
|
||||
#ifdef HAVE_TLS
|
||||
enum lload_tls_type c_is_tls; /* true if this LDAP over raw TLS */
|
||||
char c_needs_tls_accept; /* true if SSL_accept should be called */
|
||||
#endif
|
||||
|
||||
long c_n_ops_executing; /* num of ops currently executing */
|
||||
|
|
|
|||
|
|
@ -426,6 +426,180 @@ upstream_finish( Connection *c )
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
upstream_tls_handshake_cb( evutil_socket_t s, short what, void *arg )
|
||||
{
|
||||
Connection *c = arg;
|
||||
Backend *b;
|
||||
int rc = LDAP_SUCCESS;
|
||||
|
||||
CONNECTION_LOCK(c);
|
||||
if ( what & EV_TIMEOUT ) {
|
||||
Debug( LDAP_DEBUG_CONNS, "upstream_tls_handshake_cb: "
|
||||
"connid=%lu, timeout reached, destroying\n",
|
||||
c->c_connid );
|
||||
goto fail;
|
||||
}
|
||||
b = c->c_private;
|
||||
|
||||
rc = ldap_pvt_tls_connect( slap_tls_ld, c->c_sb, b->b_host );
|
||||
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, "upstream_tls_handshake_cb: "
|
||||
"connid=%lu finished\n",
|
||||
c->c_connid );
|
||||
c->c_is_tls = LLOAD_TLS_ESTABLISHED;
|
||||
|
||||
CONNECTION_UNLOCK_INCREF(c);
|
||||
ldap_pvt_thread_mutex_lock( &b->b_mutex );
|
||||
CONNECTION_LOCK_DECREF(c);
|
||||
|
||||
rc = upstream_finish( c );
|
||||
|
||||
ldap_pvt_thread_mutex_unlock( &b->b_mutex );
|
||||
|
||||
if ( rc == LDAP_SUCCESS ) {
|
||||
backend_retry( b );
|
||||
}
|
||||
} 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, "upstream_tls_handshake_cb: "
|
||||
"connid=%lu need write rc=%d\n",
|
||||
c->c_connid, rc );
|
||||
}
|
||||
CONNECTION_UNLOCK_OR_DESTROY(c);
|
||||
return;
|
||||
|
||||
fail:
|
||||
Debug( LDAP_DEBUG_CONNS, "upstream_tls_handshake_cb: "
|
||||
"connid=%lu failed rc=%d\n",
|
||||
c->c_connid, rc );
|
||||
CONNECTION_DESTROY(c);
|
||||
}
|
||||
|
||||
static int
|
||||
upstream_starttls( Connection *c )
|
||||
{
|
||||
BerValue matcheddn, message, responseOid,
|
||||
startTLSOid = BER_BVC(LDAP_EXOP_START_TLS);
|
||||
BerElement *ber = c->c_currentber;
|
||||
struct event_base *base;
|
||||
ber_int_t msgid, result;
|
||||
ber_tag_t tag;
|
||||
|
||||
c->c_currentber = NULL;
|
||||
|
||||
if ( ber_scanf( ber, "it", &msgid, &tag ) == LBER_ERROR ) {
|
||||
Debug( LDAP_DEBUG_ANY, "upstream_starttls: "
|
||||
"protocol violation from server\n" );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( msgid != ( c->c_next_msgid - 1 ) || tag != LDAP_RES_EXTENDED ) {
|
||||
Debug( LDAP_DEBUG_ANY, "upstream_starttls: "
|
||||
"unexpected %s from server, msgid=%d\n",
|
||||
slap_msgtype2str( tag ), msgid );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( ber_scanf( ber, "{emm}", &result, &matcheddn, &message ) ==
|
||||
LBER_ERROR ) {
|
||||
Debug( LDAP_DEBUG_ANY, "upstream_starttls: "
|
||||
"protocol violation on StartTLS response\n" );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( (tag = ber_get_tag( ber )) != LBER_DEFAULT ) {
|
||||
if ( tag != LDAP_TAG_EXOP_RES_OID ||
|
||||
ber_scanf( ber, "{m}", &responseOid ) == LBER_DEFAULT ) {
|
||||
Debug( LDAP_DEBUG_ANY, "upstream_starttls: "
|
||||
"protocol violation on StartTLS response\n" );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( ber_bvcmp( &responseOid, &startTLSOid ) ) {
|
||||
Debug( LDAP_DEBUG_ANY, "upstream_starttls: "
|
||||
"oid=%s not a StartTLS response\n",
|
||||
responseOid.bv_val );
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if ( result != LDAP_SUCCESS ) {
|
||||
Backend *b = c->c_private;
|
||||
int rc;
|
||||
|
||||
Debug( LDAP_DEBUG_STATS, "upstream_starttls: "
|
||||
"server doesn't support StartTLS rc=%d message='%s'%s\n",
|
||||
result, message.bv_val,
|
||||
(c->c_is_tls == LLOAD_STARTTLS_OPTIONAL) ? ", ignored" : "" );
|
||||
if ( c->c_is_tls != LLOAD_STARTTLS_OPTIONAL ) {
|
||||
goto fail;
|
||||
}
|
||||
c->c_is_tls = LLOAD_CLEARTEXT;
|
||||
|
||||
ber_free( ber, 1 );
|
||||
|
||||
CONNECTION_UNLOCK_INCREF(c);
|
||||
ldap_pvt_thread_mutex_lock( &b->b_mutex );
|
||||
CONNECTION_LOCK_DECREF(c);
|
||||
|
||||
rc = upstream_finish( c );
|
||||
|
||||
ldap_pvt_thread_mutex_unlock( &b->b_mutex );
|
||||
|
||||
if ( rc == LDAP_SUCCESS ) {
|
||||
backend_retry( b );
|
||||
}
|
||||
|
||||
CONNECTION_UNLOCK_OR_DESTROY(c);
|
||||
return rc;
|
||||
}
|
||||
|
||||
base = event_get_base( c->c_read_event );
|
||||
|
||||
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,
|
||||
upstream_tls_handshake_cb, c );
|
||||
event_assign( c->c_write_event, base, c->c_fd, EV_WRITE,
|
||||
upstream_tls_handshake_cb, c );
|
||||
|
||||
event_add( c->c_read_event, NULL );
|
||||
event_add( c->c_write_event, lload_write_timeout );
|
||||
|
||||
CONNECTION_UNLOCK(c);
|
||||
|
||||
ber_free( ber, 1 );
|
||||
return -1;
|
||||
|
||||
fail:
|
||||
ber_free( ber, 1 );
|
||||
CONNECTION_DESTROY(c);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We must already hold b->b_mutex when called.
|
||||
*/
|
||||
|
|
@ -439,7 +613,7 @@ upstream_init( ber_socket_t s, Backend *b )
|
|||
|
||||
assert( b != NULL );
|
||||
|
||||
flags = (b->b_tls == LLOAD_LDAPS) ? CONN_IS_TLS : 0;
|
||||
flags = (b->b_proto == LDAP_PROTO_IPC) ? CONN_IS_IPC : 0;
|
||||
if ( (c = connection_init( s, b->b_host, flags )) == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -473,11 +647,37 @@ upstream_init( ber_socket_t s, Backend *b )
|
|||
/* We only add the write event when we have data pending */
|
||||
c->c_write_event = event;
|
||||
|
||||
rc = upstream_finish( c );
|
||||
if ( rc < 0 ) {
|
||||
goto fail;
|
||||
}
|
||||
if ( c->c_is_tls == LLOAD_CLEARTEXT ) {
|
||||
rc = upstream_finish( c );
|
||||
if ( rc < 0 ) {
|
||||
goto fail;
|
||||
}
|
||||
} else if ( c->c_is_tls == LLOAD_LDAPS ) {
|
||||
event_assign( c->c_read_event, base, s, EV_READ|EV_PERSIST,
|
||||
upstream_tls_handshake_cb, c );
|
||||
event_assign( c->c_write_event, base, s, EV_WRITE,
|
||||
upstream_tls_handshake_cb, c );
|
||||
event_add( c->c_write_event, lload_write_timeout );
|
||||
} else if ( c->c_is_tls == LLOAD_STARTTLS ||
|
||||
c->c_is_tls == LLOAD_STARTTLS_OPTIONAL ) {
|
||||
BerElement *output;
|
||||
|
||||
ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
|
||||
if ( (output = c->c_pendingber = ber_alloc()) == NULL ) {
|
||||
ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
|
||||
goto fail;
|
||||
}
|
||||
ber_printf( output, "t{tit{ts}}", LDAP_TAG_MESSAGE,
|
||||
LDAP_TAG_MSGID, c->c_next_msgid++,
|
||||
LDAP_REQ_EXTENDED,
|
||||
LDAP_TAG_EXOP_REQ_OID, LDAP_EXOP_START_TLS );
|
||||
ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
|
||||
|
||||
c->c_pdu_cb = upstream_starttls;
|
||||
CONNECTION_UNLOCK_INCREF(c);
|
||||
connection_write_cb( s, 0, c );
|
||||
CONNECTION_LOCK_DECREF(c);
|
||||
}
|
||||
event_add( c->c_read_event, NULL );
|
||||
|
||||
c->c_destroy = upstream_destroy;
|
||||
|
|
|
|||
Loading…
Reference in a new issue