Home | History | Annotate | Line # | Download | only in lloadd
      1 /*	$NetBSD: extended.c,v 1.3 2025/09/05 21:16:24 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1998-2024 The OpenLDAP Foundation.
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted only as authorized by the OpenLDAP
     11  * Public License.
     12  *
     13  * A copy of this license is available in the file LICENSE in the
     14  * top-level directory of the distribution or, alternatively, at
     15  * <http://www.OpenLDAP.org/license.html>.
     16  */
     17 
     18 #include <sys/cdefs.h>
     19 __RCSID("$NetBSD: extended.c,v 1.3 2025/09/05 21:16:24 christos Exp $");
     20 
     21 #include "portable.h"
     22 
     23 #include <ac/string.h>
     24 
     25 #include "lutil.h"
     26 #include "lload.h"
     27 
     28 Avlnode *lload_exop_handlers = NULL;
     29 
     30 #ifdef HAVE_TLS
     31 void *lload_tls_ctx;
     32 LDAP *lload_tls_ld, *lload_tls_backend_ld;
     33 #ifdef BALANCER_MODULE
     34 int lload_use_slap_tls_ctx = 0;
     35 #endif
     36 #endif /* HAVE_TLS */
     37 
     38 int
     39 handle_starttls( LloadConnection *c, LloadOperation *op )
     40 {
     41     struct event_base *base = event_get_base( c->c_read_event );
     42     LloadOperation *found;
     43     BerElement *output;
     44     char *msg = NULL;
     45     int rc = LDAP_SUCCESS;
     46 
     47     CONNECTION_LOCK(c);
     48     found = ldap_tavl_delete( &c->c_ops, op, operation_client_cmp );
     49     assert( op == found );
     50     c->c_n_ops_executing--;
     51 
     52 #ifdef HAVE_TLS
     53     if ( c->c_is_tls == LLOAD_TLS_ESTABLISHED ) {
     54         rc = LDAP_OPERATIONS_ERROR;
     55         msg = "TLS layer already in effect";
     56     } else if ( c->c_state == LLOAD_C_BINDING ) {
     57         rc = LDAP_OPERATIONS_ERROR;
     58         msg = "bind in progress";
     59     } else if ( c->c_ops ) {
     60         rc = LDAP_OPERATIONS_ERROR;
     61         msg = "cannot start TLS when operations are outstanding";
     62     } else if ( !LLOAD_TLS_CTX ) {
     63         rc = LDAP_UNAVAILABLE;
     64         msg = "Could not initialize TLS";
     65     }
     66 #else /* ! HAVE_TLS */
     67     rc = LDAP_UNAVAILABLE;
     68     msg = "Could not initialize TLS";
     69 #endif /* ! HAVE_TLS */
     70 
     71     CONNECTION_UNLOCK(c);
     72 
     73     Debug( LDAP_DEBUG_STATS, "handle_starttls: "
     74             "handling StartTLS exop connid=%lu rc=%d msg=%s\n",
     75             c->c_connid, rc, msg );
     76 
     77     if ( rc ) {
     78         /* We've already removed the operation from the queue */
     79         operation_send_reject( op, rc, msg, 1 );
     80         return LDAP_SUCCESS;
     81     }
     82 
     83 #ifdef HAVE_TLS
     84     event_del( c->c_read_event );
     85     event_del( c->c_write_event );
     86     /*
     87      * At this point, we are the only thread handling the connection:
     88      * - there are no upstream operations
     89      * - the I/O callbacks have been successfully removed
     90      *
     91      * This means we can safely reconfigure both I/O events now.
     92      */
     93 
     94     checked_lock( &c->c_io_mutex );
     95     output = c->c_pendingber;
     96     if ( output == NULL && (output = ber_alloc()) == NULL ) {
     97         checked_unlock( &c->c_io_mutex );
     98         OPERATION_UNLINK(op);
     99         CONNECTION_LOCK_DESTROY(c);
    100         return -1;
    101     }
    102     c->c_pendingber = output;
    103     ber_printf( output, "t{tit{ess}}", LDAP_TAG_MESSAGE,
    104             LDAP_TAG_MSGID, op->o_client_msgid,
    105             LDAP_RES_EXTENDED, LDAP_SUCCESS, "", "" );
    106     c->c_io_state &= ~LLOAD_C_READ_HANDOVER;
    107     checked_unlock( &c->c_io_mutex );
    108 
    109     CONNECTION_LOCK(c);
    110     c->c_read_timeout = lload_timeout_net;
    111     event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST,
    112             client_tls_handshake_cb, c );
    113     event_add( c->c_read_event, c->c_read_timeout );
    114 
    115     event_assign( c->c_write_event, base, c->c_fd, EV_WRITE,
    116             client_tls_handshake_cb, c );
    117     /* We already have something to write */
    118     event_add( c->c_write_event, lload_write_timeout );
    119 
    120     op->o_res = LLOAD_OP_COMPLETED;
    121     CONNECTION_UNLOCK(c);
    122 
    123     OPERATION_UNLINK(op);
    124 
    125     return -1;
    126 #endif /* HAVE_TLS */
    127 }
    128 
    129 int
    130 request_extended( LloadConnection *c, LloadOperation *op )
    131 {
    132     ExopHandler *handler, needle = {};
    133     struct restriction_entry *restriction, rneedle = {};
    134     BerElement *copy;
    135     struct berval bv;
    136     ber_tag_t tag;
    137 
    138     if ( (copy = ber_alloc()) == NULL ) {
    139         operation_send_reject( op, LDAP_OTHER, "internal error", 0 );
    140         CONNECTION_LOCK_DESTROY(c);
    141         return -1;
    142     }
    143 
    144     ber_init2( copy, &op->o_request, 0 );
    145 
    146     tag = ber_skip_element( copy, &bv );
    147     if ( tag != LDAP_TAG_EXOP_REQ_OID ) {
    148         Debug( LDAP_DEBUG_STATS, "request_extended: "
    149                 "no OID present in extended request\n" );
    150         operation_send_reject( op, LDAP_PROTOCOL_ERROR, "decoding error", 0 );
    151         CONNECTION_LOCK_DESTROY(c);
    152         return -1;
    153     }
    154 
    155     needle.oid = bv;
    156 
    157     handler = ldap_avl_find( lload_exop_handlers, &needle, exop_handler_cmp );
    158     if ( handler ) {
    159         Debug( LDAP_DEBUG_TRACE, "request_extended: "
    160                 "handling exop OID %.*s internally\n",
    161                 (int)bv.bv_len, bv.bv_val );
    162         ber_free( copy, 0 );
    163         return handler->func( c, op );
    164     }
    165     ber_free( copy, 0 );
    166 
    167     rneedle.oid = bv;
    168     restriction = ldap_tavl_find( lload_exop_actions, &rneedle,
    169             lload_restriction_cmp );
    170     if ( restriction ) {
    171         op->o_restricted = restriction->action;
    172     } else {
    173         op->o_restricted = lload_default_exop_action;
    174     }
    175 
    176     return request_process( c, op );
    177 }
    178 
    179 ExopHandler lload_exops[] = {
    180         { BER_BVC(LDAP_EXOP_START_TLS), handle_starttls },
    181         { BER_BVNULL }
    182 };
    183 
    184 int
    185 exop_handler_cmp( const void *left, const void *right )
    186 {
    187     const struct lload_exop_handlers_t *l = left, *r = right;
    188     return ber_bvcmp( &l->oid, &r->oid );
    189 }
    190 
    191 int
    192 lload_register_exop_handlers( struct lload_exop_handlers_t *handler )
    193 {
    194     for ( ; !BER_BVISNULL( &handler->oid ); handler++ ) {
    195         Debug( LDAP_DEBUG_TRACE, "lload_register_exop_handlers: "
    196                 "registering handler for exop oid=%s\n",
    197                 handler->oid.bv_val );
    198         if ( ldap_avl_insert( &lload_exop_handlers, handler, exop_handler_cmp,
    199                      ldap_avl_dup_error ) ) {
    200             Debug( LDAP_DEBUG_ANY, "lload_register_exop_handlers: "
    201                     "failed to register handler for exop oid=%s\n",
    202                     handler->oid.bv_val );
    203             return -1;
    204         }
    205     }
    206 
    207     return LDAP_SUCCESS;
    208 }
    209 
    210 int
    211 lload_exop_init( void )
    212 {
    213     if ( lload_register_exop_handlers( lload_exops ) ) {
    214         return -1;
    215     }
    216 
    217     return LDAP_SUCCESS;
    218 }
    219 
    220 void
    221 lload_exop_destroy( void )
    222 {
    223     ldap_avl_free( lload_exop_handlers, NULL );
    224     lload_exop_handlers = NULL;
    225 }
    226