xref: /netbsd-src/external/bsd/openldap/dist/servers/lloadd/extended.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
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
handle_starttls(LloadConnection * c,LloadOperation * op)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
request_extended(LloadConnection * c,LloadOperation * op)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
exop_handler_cmp(const void * left,const void * right)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
lload_register_exop_handlers(struct lload_exop_handlers_t * handler)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
lload_exop_init(void)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