1 /* $NetBSD: extended.c,v 1.2 2021/08/14 16:14:58 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2021 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.2 2021/08/14 16:14:58 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 BerElement *copy; 134 struct berval bv; 135 ber_tag_t tag; 136 137 if ( (copy = ber_alloc()) == NULL ) { 138 operation_send_reject( op, LDAP_OTHER, "internal error", 0 ); 139 CONNECTION_LOCK_DESTROY(c); 140 return -1; 141 } 142 143 ber_init2( copy, &op->o_request, 0 ); 144 145 tag = ber_skip_element( copy, &bv ); 146 if ( tag != LDAP_TAG_EXOP_REQ_OID ) { 147 Debug( LDAP_DEBUG_STATS, "request_extended: " 148 "no OID present in extended request\n" ); 149 operation_send_reject( op, LDAP_PROTOCOL_ERROR, "decoding error", 0 ); 150 CONNECTION_LOCK_DESTROY(c); 151 return -1; 152 } 153 154 needle.oid = bv; 155 156 handler = ldap_avl_find( lload_exop_handlers, &needle, exop_handler_cmp ); 157 if ( handler ) { 158 Debug( LDAP_DEBUG_TRACE, "request_extended: " 159 "handling exop OID %.*s internally\n", 160 (int)bv.bv_len, bv.bv_val ); 161 ber_free( copy, 0 ); 162 return handler->func( c, op ); 163 } 164 ber_free( copy, 0 ); 165 166 if ( c->c_state == LLOAD_C_BINDING ) { 167 operation_send_reject( op, LDAP_PROTOCOL_ERROR, "bind in progress", 0 ); 168 return LDAP_SUCCESS; 169 } 170 return request_process( c, op ); 171 } 172 173 ExopHandler lload_exops[] = { 174 { BER_BVC(LDAP_EXOP_START_TLS), handle_starttls }, 175 { BER_BVNULL } 176 }; 177 178 int 179 exop_handler_cmp( const void *left, const void *right ) 180 { 181 const struct lload_exop_handlers_t *l = left, *r = right; 182 return ber_bvcmp( &l->oid, &r->oid ); 183 } 184 185 int 186 lload_register_exop_handlers( struct lload_exop_handlers_t *handler ) 187 { 188 for ( ; !BER_BVISNULL( &handler->oid ); handler++ ) { 189 Debug( LDAP_DEBUG_TRACE, "lload_register_exop_handlers: " 190 "registering handler for exop oid=%s\n", 191 handler->oid.bv_val ); 192 if ( ldap_avl_insert( &lload_exop_handlers, handler, exop_handler_cmp, 193 ldap_avl_dup_error ) ) { 194 Debug( LDAP_DEBUG_ANY, "lload_register_exop_handlers: " 195 "failed to register handler for exop oid=%s\n", 196 handler->oid.bv_val ); 197 return -1; 198 } 199 } 200 201 return LDAP_SUCCESS; 202 } 203 204 int 205 lload_exop_init( void ) 206 { 207 if ( lload_register_exop_handlers( lload_exops ) ) { 208 return -1; 209 } 210 211 return LDAP_SUCCESS; 212 } 213