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