diff options
Diffstat (limited to 'servers/lloadd/extended.c')
-rw-r--r-- | servers/lloadd/extended.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/servers/lloadd/extended.c b/servers/lloadd/extended.c new file mode 100644 index 0000000..54d9700 --- /dev/null +++ b/servers/lloadd/extended.c @@ -0,0 +1,220 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2022 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include "portable.h" + +#include <ac/string.h> + +#include "lutil.h" +#include "lload.h" + +Avlnode *lload_exop_handlers = NULL; + +#ifdef HAVE_TLS +void *lload_tls_ctx; +LDAP *lload_tls_ld, *lload_tls_backend_ld; +#ifdef BALANCER_MODULE +int lload_use_slap_tls_ctx = 0; +#endif +#endif /* HAVE_TLS */ + +int +handle_starttls( LloadConnection *c, LloadOperation *op ) +{ + struct event_base *base = event_get_base( c->c_read_event ); + LloadOperation *found; + BerElement *output; + char *msg = NULL; + int rc = LDAP_SUCCESS; + + CONNECTION_LOCK(c); + found = ldap_tavl_delete( &c->c_ops, op, operation_client_cmp ); + assert( op == found ); + c->c_n_ops_executing--; + +#ifdef HAVE_TLS + 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 ( !LLOAD_TLS_CTX ) { + rc = LDAP_UNAVAILABLE; + msg = "Could not initialize TLS"; + } +#else /* ! HAVE_TLS */ + rc = LDAP_UNAVAILABLE; + msg = "Could not initialize TLS"; +#endif /* ! HAVE_TLS */ + + CONNECTION_UNLOCK(c); + + 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 */ + operation_send_reject( op, rc, msg, 1 ); + return LDAP_SUCCESS; + } + +#ifdef HAVE_TLS + 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. + */ + + checked_lock( &c->c_io_mutex ); + output = c->c_pendingber; + if ( output == NULL && (output = ber_alloc()) == NULL ) { + checked_unlock( &c->c_io_mutex ); + OPERATION_UNLINK(op); + CONNECTION_LOCK_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, "", "" ); + c->c_io_state &= ~LLOAD_C_READ_HANDOVER; + checked_unlock( &c->c_io_mutex ); + + CONNECTION_LOCK(c); + c->c_read_timeout = lload_timeout_net; + 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, c->c_read_timeout ); + + 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 ); + + op->o_res = LLOAD_OP_COMPLETED; + CONNECTION_UNLOCK(c); + + OPERATION_UNLINK(op); + + return -1; +#endif /* HAVE_TLS */ +} + +int +request_extended( LloadConnection *c, LloadOperation *op ) +{ + ExopHandler *handler, needle = {}; + struct restriction_entry *restriction, rneedle = {}; + BerElement *copy; + struct berval bv; + ber_tag_t tag; + + if ( (copy = ber_alloc()) == NULL ) { + operation_send_reject( op, LDAP_OTHER, "internal error", 0 ); + CONNECTION_LOCK_DESTROY(c); + return -1; + } + + ber_init2( copy, &op->o_request, 0 ); + + tag = ber_skip_element( copy, &bv ); + if ( tag != LDAP_TAG_EXOP_REQ_OID ) { + Debug( LDAP_DEBUG_STATS, "request_extended: " + "no OID present in extended request\n" ); + operation_send_reject( op, LDAP_PROTOCOL_ERROR, "decoding error", 0 ); + CONNECTION_LOCK_DESTROY(c); + return -1; + } + + needle.oid = bv; + + handler = ldap_avl_find( lload_exop_handlers, &needle, exop_handler_cmp ); + if ( handler ) { + Debug( LDAP_DEBUG_TRACE, "request_extended: " + "handling exop OID %.*s internally\n", + (int)bv.bv_len, bv.bv_val ); + ber_free( copy, 0 ); + return handler->func( c, op ); + } + ber_free( copy, 0 ); + + rneedle.oid = bv; + restriction = ldap_tavl_find( lload_exop_actions, &rneedle, + lload_restriction_cmp ); + if ( restriction ) { + op->o_restricted = restriction->action; + } else { + op->o_restricted = lload_default_exop_action; + } + + return request_process( c, op ); +} + +ExopHandler lload_exops[] = { + { BER_BVC(LDAP_EXOP_START_TLS), handle_starttls }, + { BER_BVNULL } +}; + +int +exop_handler_cmp( const void *left, const void *right ) +{ + const struct lload_exop_handlers_t *l = left, *r = right; + return ber_bvcmp( &l->oid, &r->oid ); +} + +int +lload_register_exop_handlers( struct lload_exop_handlers_t *handler ) +{ + for ( ; !BER_BVISNULL( &handler->oid ); handler++ ) { + Debug( LDAP_DEBUG_TRACE, "lload_register_exop_handlers: " + "registering handler for exop oid=%s\n", + handler->oid.bv_val ); + if ( ldap_avl_insert( &lload_exop_handlers, handler, exop_handler_cmp, + ldap_avl_dup_error ) ) { + Debug( LDAP_DEBUG_ANY, "lload_register_exop_handlers: " + "failed to register handler for exop oid=%s\n", + handler->oid.bv_val ); + return -1; + } + } + + return LDAP_SUCCESS; +} + +int +lload_exop_init( void ) +{ + if ( lload_register_exop_handlers( lload_exops ) ) { + return -1; + } + + return LDAP_SUCCESS; +} + +void +lload_exop_destroy( void ) +{ + ldap_avl_free( lload_exop_handlers, NULL ); + lload_exop_handlers = NULL; +} |