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