xref: /netbsd-src/external/bsd/openldap/dist/servers/lloadd/lload.h (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: lload.h,v 1.2 2021/08/14 16:14:58 christos Exp $	*/
2 
3 /* lload.h - load balancer include file */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2021 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
19  * All rights reserved.
20  *
21  * Redistribution and use in source and binary forms are permitted
22  * provided that this notice is preserved and that due credit is given
23  * to the University of Michigan at Ann Arbor. The name of the University
24  * may not be used to endorse or promote products derived from this
25  * software without specific prior written permission. This software
26  * is provided ``as is'' without express or implied warranty.
27  */
28 
29 #ifndef _LLOAD_H_
30 #define _LLOAD_H_
31 
32 #include "ldap_defaults.h"
33 
34 #include <stdio.h>
35 #include <ac/stdlib.h>
36 
37 #include <sys/types.h>
38 #include <ac/syslog.h>
39 #include <ac/regex.h>
40 #include <ac/signal.h>
41 #include <ac/socket.h>
42 #include <ac/time.h>
43 #include <ac/param.h>
44 
45 #include "ldap_avl.h"
46 
47 #include "../servers/slapd/slap.h"
48 #include "../slapd/back-monitor/back-monitor.h"
49 
50 #ifndef ldap_debug
51 #define ldap_debug slap_debug
52 #endif
53 
54 #include "ldap_log.h"
55 
56 #include <ldap.h>
57 #include <ldap_schema.h>
58 
59 #include "lber_pvt.h"
60 #include "ldap_pvt.h"
61 #include "ldap_pvt_thread.h"
62 #include "ldap_queue.h"
63 
64 #include <event2/event.h>
65 
66 #ifdef HAVE_CYRUS_SASL
67 #ifdef HAVE_SASL_SASL_H
68 #include <sasl/sasl.h>
69 #else
70 #include <sasl.h>
71 #endif
72 #endif /* HAVE_CYRUS_SASL */
73 
74 LDAP_BEGIN_DECL
75 
76 #ifdef SERVICE_NAME
77 #undef SERVICE_NAME
78 #endif
79 
80 #define SERVICE_NAME OPENLDAP_PACKAGE "-lloadd"
81 
82 #define LLOAD_SB_MAX_INCOMING_CLIENT ( ( 1 << 24 ) - 1 )
83 #define LLOAD_SB_MAX_INCOMING_UPSTREAM ( ( 1 << 24 ) - 1 )
84 
85 #define LLOAD_CONN_MAX_PDUS_PER_CYCLE_DEFAULT 10
86 
87 #define BER_BV_OPTIONAL( bv ) ( BER_BVISNULL( bv ) ? NULL : ( bv ) )
88 
89 #include <epoch.h>
90 
91 #define checked_lock( mutex ) \
92     if ( ldap_pvt_thread_mutex_lock( mutex ) != 0 ) assert(0)
93 #define checked_unlock( mutex ) \
94     if ( ldap_pvt_thread_mutex_unlock( mutex ) != 0 ) assert(0)
95 
96 #ifdef LDAP_THREAD_DEBUG
97 #define assert_locked( mutex ) \
98     if ( ldap_pvt_thread_mutex_trylock( mutex ) == 0 ) assert(0)
99 #else
100 #define assert_locked( mutex ) ( (void)0 )
101 #endif
102 
103 typedef struct LloadBackend LloadBackend;
104 typedef struct LloadPendingConnection LloadPendingConnection;
105 typedef struct LloadConnection LloadConnection;
106 typedef struct LloadOperation LloadOperation;
107 typedef struct LloadChange LloadChange;
108 /* end of forward declarations */
109 
110 typedef LDAP_CIRCLEQ_HEAD(BeSt, LloadBackend) lload_b_head;
111 typedef LDAP_CIRCLEQ_HEAD(ConnSt, LloadConnection) lload_c_head;
112 
113 LDAP_SLAPD_V (lload_b_head) backend;
114 LDAP_SLAPD_V (lload_c_head) clients;
115 LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) backend_mutex;
116 LDAP_SLAPD_V (LloadBackend *) current_backend;
117 LDAP_SLAPD_V (struct slap_bindconf) bindconf;
118 LDAP_SLAPD_V (struct berval) lloadd_identity;
119 
120 /* Used to coordinate server (un)pause, shutdown */
121 LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) lload_wait_mutex;
122 LDAP_SLAPD_V (ldap_pvt_thread_cond_t) lload_pause_cond;
123 LDAP_SLAPD_V (ldap_pvt_thread_cond_t) lload_wait_cond;
124 
125 typedef int lload_cf_aux_table_parse_x( struct berval *val,
126         void *bc,
127         slap_cf_aux_table *tab0,
128         const char *tabmsg,
129         int unparse );
130 
131 typedef struct LloadListener LloadListener;
132 
133 enum lc_type {
134     LLOAD_CHANGE_UNDEFINED = 0,
135     LLOAD_CHANGE_MODIFY,
136     LLOAD_CHANGE_ADD,
137     LLOAD_CHANGE_DEL,
138 };
139 
140 enum lc_object {
141     LLOAD_UNDEFINED = 0,
142     LLOAD_DAEMON,
143     /*
144     LLOAD_BINDCONF,
145     */
146     LLOAD_BACKEND,
147 };
148 
149 enum lcf_daemon {
150     LLOAD_DAEMON_MOD_THREADS = 1 << 0,
151     LLOAD_DAEMON_MOD_FEATURES = 1 << 1,
152     LLOAD_DAEMON_MOD_TLS = 1 << 2,
153     LLOAD_DAEMON_MOD_LISTENER_ADD = 1 << 3,
154     LLOAD_DAEMON_MOD_LISTENER_REPLACE = 1 << 4,
155     LLOAD_DAEMON_MOD_BINDCONF = 1 << 5,
156 };
157 
158 enum lcf_backend {
159     LLOAD_BACKEND_MOD_OTHER = 1 << 0,
160     LLOAD_BACKEND_MOD_CONNS = 1 << 1,
161 };
162 
163 struct LloadChange {
164     enum lc_type type;
165     enum lc_object object;
166     union {
167         int generic;
168         enum lcf_daemon daemon;
169         enum lcf_backend backend;
170     } flags;
171     void *target;
172 };
173 
174 typedef enum {
175 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
176     LLOAD_FEATURE_VC = 1 << 0,
177 #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
178     LLOAD_FEATURE_PROXYAUTHZ = 1 << 1,
179     LLOAD_FEATURE_PAUSE = 1 << 2,
180 } lload_features_t;
181 
182 #define LLOAD_FEATURE_SUPPORTED_MASK ( \
183     LLOAD_FEATURE_PROXYAUTHZ | \
184     0 )
185 
186 #ifdef BALANCER_MODULE
187 #define LLOAD_TLS_CTX ( lload_use_slap_tls_ctx ? slap_tls_ctx : lload_tls_ctx )
188 #else
189 #define LLOAD_TLS_CTX ( lload_tls_ctx )
190 #endif
191 
192 enum lload_tls_type {
193     LLOAD_CLEARTEXT = 0,
194     LLOAD_LDAPS,
195     LLOAD_STARTTLS_OPTIONAL,
196     LLOAD_STARTTLS,
197     LLOAD_TLS_ESTABLISHED,
198 };
199 
200 struct LloadPendingConnection {
201     LloadBackend *backend;
202 
203     struct event *event;
204     ber_socket_t fd;
205 
206     LDAP_LIST_ENTRY(LloadPendingConnection) next;
207 };
208 
209 typedef struct lload_counters_t {
210     ldap_pvt_mp_t lc_ops_completed;
211     ldap_pvt_mp_t lc_ops_received;
212     ldap_pvt_mp_t lc_ops_forwarded;
213     ldap_pvt_mp_t lc_ops_rejected;
214     ldap_pvt_mp_t lc_ops_failed;
215 } lload_counters_t;
216 
217 enum {
218     LLOAD_STATS_OPS_BIND = 0,
219     LLOAD_STATS_OPS_OTHER,
220     LLOAD_STATS_OPS_LAST
221 };
222 
223 typedef struct lload_global_stats_t {
224     ldap_pvt_mp_t global_incoming;
225     ldap_pvt_mp_t global_outgoing;
226     lload_counters_t counters[LLOAD_STATS_OPS_LAST];
227 } lload_global_stats_t;
228 
229 /* Can hold mutex when locking a linked connection */
230 struct LloadBackend {
231     ldap_pvt_thread_mutex_t b_mutex;
232 
233     struct berval b_name, b_uri;
234     int b_proto, b_port;
235     enum lload_tls_type b_tls, b_tls_conf;
236     char *b_host;
237 
238     int b_retry_timeout, b_failed;
239     struct event *b_retry_event;
240     struct timeval b_retry_tv;
241 
242     int b_numconns, b_numbindconns;
243     int b_bindavail, b_active, b_opening;
244     lload_c_head b_conns, b_bindconns, b_preparing;
245     LDAP_LIST_HEAD(ConnectingSt, LloadPendingConnection) b_connecting;
246     LloadConnection *b_last_conn, *b_last_bindconn;
247 
248     long b_max_pending, b_max_conn_pending;
249     long b_n_ops_executing;
250 
251     lload_counters_t b_counters[LLOAD_STATS_OPS_LAST];
252 
253 #ifdef BALANCER_MODULE
254     monitor_subsys_t *b_monitor;
255 #endif /* BALANCER_MODULE */
256 
257     struct evdns_getaddrinfo_request *b_dns_req;
258     void *b_cookie;
259 
260     LDAP_CIRCLEQ_ENTRY(LloadBackend) b_next;
261 };
262 
263 typedef int (*LloadOperationHandler)( LloadConnection *client,
264         LloadOperation *op,
265         BerElement *ber );
266 typedef int (*RequestHandler)( LloadConnection *c, LloadOperation *op );
267 typedef struct lload_exop_handlers_t {
268     struct berval oid;
269     RequestHandler func;
270 } ExopHandler;
271 
272 typedef int (*CONNECTION_PDU_CB)( LloadConnection *c );
273 typedef void (*CONNECTION_DESTROY_CB)( LloadConnection *c );
274 
275 /* connection state (protected by c_mutex) */
276 enum sc_state {
277     LLOAD_C_INVALID = 0, /* MUST BE ZERO (0) */
278     LLOAD_C_READY,       /* ready */
279     LLOAD_C_CLOSING,     /* closing */
280     LLOAD_C_ACTIVE,      /* exclusive operation (tls setup, ...) in progress */
281     LLOAD_C_BINDING,     /* binding */
282     LLOAD_C_DYING,       /* part-processed dead waiting to be freed, someone
283                           * might still be observing it */
284 };
285 enum sc_type {
286     LLOAD_C_OPEN = 0,  /* regular connection */
287     LLOAD_C_PREPARING, /* upstream connection not assigned yet */
288     LLOAD_C_BIND, /* connection used to handle bind client requests if VC not enabled */
289     LLOAD_C_PRIVILEGED, /* connection can override proxyauthz control */
290 };
291 enum sc_io_state {
292     LLOAD_C_OPERATIONAL = 0,        /* all is good */
293     LLOAD_C_READ_HANDOVER = 1 << 0, /* A task to process PDUs is scheduled or
294                                      * running, do not re-enable c_read_event */
295     LLOAD_C_READ_PAUSE = 1 << 1,    /* We want to pause reading until the client
296                                      * has sufficiently caught up with what we
297                                      * sent */
298 };
299 
300 /*
301  * represents a connection from an ldap client/to ldap server
302  */
303 struct LloadConnection {
304     enum sc_state c_state; /* connection state */
305     enum sc_type c_type;
306     enum sc_io_state c_io_state;
307     ber_socket_t c_fd;
308 
309 /*
310  * LloadConnection reference counting:
311  * - connection has a reference counter in c_refcnt
312  * - also a liveness/validity token is added to c_refcnt during
313  *   lload_connection_init, its existence is tracked in c_live and is usually the
314  *   only one that prevents it from being destroyed
315  * - anyone who needs to be able to relock the connection after unlocking it has
316  *   to use acquire_ref(), they need to make sure a matching
317  *   RELEASE_REF( c, c_refcnt, c->c_destroy ); is run eventually
318  * - when a connection is considered dead, use CONNECTION_DESTROY on a locked
319  *   connection, it will be made unreachable from normal places and either
320  *   scheduled for reclamation when safe to do so or if anyone still holds a
321  *   reference, it just gets unlocked and reclaimed after the last ref is
322  *   released
323  * - CONNECTION_LOCK_DESTROY is a shorthand for locking and CONNECTION_DESTROY
324  */
325     ldap_pvt_thread_mutex_t c_mutex; /* protect the connection */
326     uintptr_t c_refcnt, c_live;
327     CONNECTION_DESTROY_CB c_unlink;
328     CONNECTION_DESTROY_CB c_destroy;
329     CONNECTION_PDU_CB c_pdu_cb;
330 #define CONNECTION_ASSERT_LOCKED(c) assert_locked( &(c)->c_mutex )
331 #define CONNECTION_LOCK(c) \
332     do { \
333         checked_lock( &(c)->c_mutex ); \
334     } while (0)
335 #define CONNECTION_UNLOCK(c) \
336     do { \
337         checked_unlock( &(c)->c_mutex ); \
338     } while (0)
339 #define CONNECTION_UNLINK_(c) \
340     do { \
341         if ( __atomic_exchange_n( &(c)->c_live, 0, __ATOMIC_ACQ_REL ) ) { \
342             RELEASE_REF( (c), c_refcnt, c->c_destroy ); \
343             (c)->c_unlink( (c) ); \
344         } \
345     } while (0)
346 #define CONNECTION_DESTROY(c) \
347     do { \
348         CONNECTION_UNLINK_(c); \
349         CONNECTION_UNLOCK(c); \
350     } while (0)
351 #define CONNECTION_LOCK_DESTROY(c) \
352     do { \
353         CONNECTION_LOCK(c); \
354         CONNECTION_DESTROY(c); \
355     } while (0);
356 
357     Sockbuf *c_sb; /* ber connection stuff */
358 
359     /* set by connection_init */
360     unsigned long c_connid;    /* unique id of this connection */
361     struct berval c_peer_name; /* peer name (trans=addr:port) */
362     time_t c_starttime;        /* when the connection was opened */
363 
364     time_t c_activitytime;  /* when the connection was last used */
365     ber_int_t c_next_msgid; /* msgid of the next message */
366 
367     /* must not be used while holding either mutex */
368     struct event *c_read_event, *c_write_event;
369     struct timeval *c_read_timeout;
370 
371     /* can only be changed by binding thread */
372     struct berval c_sasl_bind_mech; /* mech in progress */
373     struct berval c_auth;           /* authcDN (possibly in progress) */
374 
375     unsigned long c_pin_id;
376 
377 #ifdef HAVE_CYRUS_SASL
378     sasl_conn_t *c_sasl_authctx;
379     void *c_sasl_defaults;
380 #ifdef SASL_CHANNEL_BINDING /* 2.1.25+ */
381     sasl_channel_binding_t *c_sasl_cbinding; /* Else cyrus-sasl would happily
382                                               * leak it on sasl_dispose */
383 #endif /* SASL_CHANNEL_BINDING */
384 #endif /* HAVE_CYRUS_SASL */
385 
386 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
387     struct berval c_vc_cookie;
388 #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
389 
390     /* Can be held while acquiring c_mutex to inject things into c_ops or
391      * destroy the connection */
392     ldap_pvt_thread_mutex_t c_io_mutex; /* only one pdu written at a time */
393 
394     BerElement *c_currentber; /* ber we're attempting to read */
395     BerElement *c_pendingber; /* ber we're attempting to write */
396 
397     TAvlnode *c_ops; /* Operations pending on the connection */
398 
399 #ifdef HAVE_TLS
400     enum lload_tls_type c_is_tls; /* true if this LDAP over raw TLS */
401 #endif
402 
403     long c_n_ops_executing;      /* num of ops currently executing */
404     long c_n_ops_completed;      /* num of ops completed */
405     lload_counters_t c_counters; /* per connection operation counters */
406 
407     LloadBackend *c_backend;
408 
409     /*
410      * Protected by the CIRCLEQ mutex:
411      * - Client: clients_mutex
412      * - Upstream: b->b_mutex
413      */
414     LDAP_CIRCLEQ_ENTRY(LloadConnection) c_next;
415 };
416 
417 enum op_state {
418     LLOAD_OP_NOT_FREEING = 0,
419     LLOAD_OP_DETACHING_CLIENT = 1 << 1,
420     LLOAD_OP_DETACHING_UPSTREAM = 1 << 0,
421 };
422 
423 #define LLOAD_OP_DETACHING_MASK \
424     ( LLOAD_OP_DETACHING_UPSTREAM | LLOAD_OP_DETACHING_CLIENT )
425 
426 /* operation result for monitoring purposes */
427 enum op_result {
428     LLOAD_OP_REJECTED,  /* operation was not forwarded */
429     LLOAD_OP_COMPLETED, /* operation sent and response received */
430     LLOAD_OP_FAILED, /* operation was forwarded, but no response was received */
431 };
432 
433 /*
434  * Operation reference tracking:
435  * - o_refcnt is set to 1, never incremented
436  * - operation_unlink sets it to 0 and on transition from 1 clears both
437  *   connection links (o_client, o_upstream)
438  */
439 struct LloadOperation {
440     uintptr_t o_refcnt;
441 
442     LloadConnection *o_client;
443     unsigned long o_client_connid;
444     ber_int_t o_client_msgid;
445     ber_int_t o_saved_msgid;
446 
447     LloadConnection *o_upstream;
448     unsigned long o_upstream_connid;
449     ber_int_t o_upstream_msgid;
450     time_t o_last_response;
451 
452     /* Protects o_client, o_upstream links */
453     ldap_pvt_thread_mutex_t o_link_mutex;
454 
455     ber_tag_t o_tag;
456     time_t o_start;
457     unsigned long o_pin_id;
458 
459     enum op_result o_res;
460     BerElement *o_ber;
461     BerValue o_request, o_ctrls;
462 };
463 
464 /*
465  * listener; need to access it from monitor backend
466  */
467 struct LloadListener {
468     struct berval sl_url;
469     struct berval sl_name;
470     mode_t sl_perms;
471 #ifdef HAVE_TLS
472     int sl_is_tls;
473 #endif
474     int sl_is_proxied;
475     struct event_base *base;
476     struct evconnlistener *listener;
477     int sl_mute; /* Listener is temporarily disabled due to emfile */
478     int sl_busy; /* Listener is busy (accept thread activated) */
479     ber_socket_t sl_sd;
480     Sockaddr sl_sa;
481 #define sl_addr sl_sa.sa_in_addr
482 #define LDAP_TCP_BUFFER
483 #ifdef LDAP_TCP_BUFFER
484     int sl_tcp_rmem; /* custom TCP read buffer size */
485     int sl_tcp_wmem; /* custom TCP write buffer size */
486 #endif
487 };
488 
489 typedef int (*CONNCB)( LloadConnection *c, void *arg );
490 
491 struct lload_monitor_conn_arg {
492     Operation *op;
493     monitor_subsys_t *ms;
494     Entry **ep;
495 };
496 
497 /* config requires a bi_private with configuration data - dummy for now */
498 struct lload_conf_info {
499     int dummy;
500 };
501 LDAP_END_DECL
502 
503 #include "proto-lload.h"
504 #endif /* _LLOAD_H_ */
505