1 /* $NetBSD: client.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: client.c,v 1.2 2021/08/14 16:14:58 christos Exp $"); 20 21 #include "portable.h" 22 23 #include <ac/socket.h> 24 #include <ac/errno.h> 25 #include <ac/string.h> 26 #include <ac/time.h> 27 #include <ac/unistd.h> 28 29 #include "lutil.h" 30 #include "lload.h" 31 32 long lload_client_max_pending = 0; 33 34 lload_c_head clients = LDAP_CIRCLEQ_HEAD_INITIALIZER( clients ); 35 36 ldap_pvt_thread_mutex_t clients_mutex; 37 38 static void client_unlink( LloadConnection *upstream ); 39 40 int 41 request_abandon( LloadConnection *c, LloadOperation *op ) 42 { 43 LloadOperation *request, needle = { .o_client_connid = c->c_connid }; 44 int rc = LDAP_SUCCESS; 45 46 op->o_res = LLOAD_OP_COMPLETED; 47 48 if ( ber_decode_int( &op->o_request, &needle.o_client_msgid ) ) { 49 Debug( LDAP_DEBUG_STATS, "request_abandon: " 50 "connid=%lu msgid=%d invalid integer sent in abandon request\n", 51 c->c_connid, op->o_client_msgid ); 52 53 operation_unlink( op ); 54 CONNECTION_LOCK_DESTROY(c); 55 return -1; 56 } 57 58 CONNECTION_LOCK(c); 59 request = ldap_tavl_find( c->c_ops, &needle, operation_client_cmp ); 60 if ( !request ) { 61 Debug( LDAP_DEBUG_STATS, "request_abandon: " 62 "connid=%lu msgid=%d requests abandon of an operation " 63 "msgid=%d not being processed anymore\n", 64 c->c_connid, op->o_client_msgid, needle.o_client_msgid ); 65 CONNECTION_UNLOCK(c); 66 goto done; 67 } else if ( request->o_tag == LDAP_REQ_BIND ) { 68 /* RFC 4511 states we must not allow Abandon on Binds */ 69 Debug( LDAP_DEBUG_STATS, "request_abandon: " 70 "connid=%lu msgid=%d requests abandon of a bind operation " 71 "msgid=%d\n", 72 c->c_connid, op->o_client_msgid, needle.o_client_msgid ); 73 CONNECTION_UNLOCK(c); 74 goto done; 75 } 76 Debug( LDAP_DEBUG_STATS, "request_abandon: " 77 "connid=%lu msgid=%d abandoning %s msgid=%d\n", 78 c->c_connid, op->o_client_msgid, 79 lload_msgtype2str( request->o_tag ), needle.o_client_msgid ); 80 81 if ( c->c_state == LLOAD_C_BINDING ) { 82 assert(0); 83 } 84 85 CONNECTION_UNLOCK(c); 86 operation_abandon( request ); 87 88 done: 89 operation_unlink( op ); 90 return rc; 91 } 92 93 int 94 request_process( LloadConnection *client, LloadOperation *op ) 95 { 96 BerElement *output; 97 LloadConnection *upstream; 98 ber_int_t msgid; 99 int res, rc = LDAP_SUCCESS; 100 101 upstream = backend_select( op, &res ); 102 if ( !upstream ) { 103 Debug( LDAP_DEBUG_STATS, "request_process: " 104 "connid=%lu, msgid=%d no available connection found\n", 105 op->o_client_connid, op->o_client_msgid ); 106 107 operation_send_reject( op, res, "no connections available", 1 ); 108 goto fail; 109 } 110 CONNECTION_ASSERT_LOCKED(upstream); 111 assert_locked( &upstream->c_io_mutex ); 112 op->o_upstream = upstream; 113 op->o_upstream_connid = upstream->c_connid; 114 op->o_res = LLOAD_OP_FAILED; 115 116 /* Was it unlinked in the meantime? No need to send a response since the 117 * client is dead */ 118 if ( !IS_ALIVE( op, o_refcnt ) ) { 119 LloadBackend *b = upstream->c_backend; 120 121 upstream->c_n_ops_executing--; 122 checked_unlock( &upstream->c_io_mutex ); 123 CONNECTION_UNLOCK(upstream); 124 125 checked_lock( &b->b_mutex ); 126 b->b_n_ops_executing--; 127 checked_unlock( &b->b_mutex ); 128 129 assert( !IS_ALIVE( client, c_live ) ); 130 checked_lock( &op->o_link_mutex ); 131 if ( op->o_upstream ) { 132 op->o_upstream = NULL; 133 } 134 checked_unlock( &op->o_link_mutex ); 135 return -1; 136 } 137 138 output = upstream->c_pendingber; 139 if ( output == NULL && (output = ber_alloc()) == NULL ) { 140 LloadBackend *b = upstream->c_backend; 141 142 upstream->c_n_ops_executing--; 143 CONNECTION_UNLOCK(upstream); 144 checked_unlock( &upstream->c_io_mutex ); 145 146 checked_lock( &b->b_mutex ); 147 b->b_n_ops_executing--; 148 operation_update_backend_counters( op, b ); 149 checked_unlock( &b->b_mutex ); 150 151 Debug( LDAP_DEBUG_ANY, "request_process: " 152 "ber_alloc failed\n" ); 153 154 rc = -1; 155 goto fail; 156 } 157 upstream->c_pendingber = output; 158 159 op->o_upstream_msgid = msgid = upstream->c_next_msgid++; 160 rc = ldap_tavl_insert( 161 &upstream->c_ops, op, operation_upstream_cmp, ldap_avl_dup_error ); 162 CONNECTION_UNLOCK(upstream); 163 164 Debug( LDAP_DEBUG_TRACE, "request_process: " 165 "client connid=%lu added %s msgid=%d to upstream connid=%lu as " 166 "msgid=%d\n", 167 op->o_client_connid, lload_msgtype2str( op->o_tag ), 168 op->o_client_msgid, op->o_upstream_connid, op->o_upstream_msgid ); 169 assert( rc == LDAP_SUCCESS ); 170 171 lload_stats.counters[LLOAD_STATS_OPS_OTHER].lc_ops_forwarded++; 172 173 if ( (lload_features & LLOAD_FEATURE_PROXYAUTHZ) && 174 client->c_type != LLOAD_C_PRIVILEGED ) { 175 CONNECTION_LOCK(client); 176 Debug( LDAP_DEBUG_TRACE, "request_process: " 177 "proxying identity %s to upstream\n", 178 client->c_auth.bv_val ); 179 ber_printf( output, "t{titOt{{sbO}" /* "}}" */, LDAP_TAG_MESSAGE, 180 LDAP_TAG_MSGID, msgid, 181 op->o_tag, &op->o_request, 182 LDAP_TAG_CONTROLS, 183 LDAP_CONTROL_PROXY_AUTHZ, 1, &client->c_auth ); 184 CONNECTION_UNLOCK(client); 185 186 if ( !BER_BVISNULL( &op->o_ctrls ) ) { 187 ber_write( output, op->o_ctrls.bv_val, op->o_ctrls.bv_len, 0 ); 188 } 189 190 ber_printf( output, /* "{{" */ "}}" ); 191 } else { 192 ber_printf( output, "t{titOtO}", LDAP_TAG_MESSAGE, 193 LDAP_TAG_MSGID, msgid, 194 op->o_tag, &op->o_request, 195 LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &op->o_ctrls ) ); 196 } 197 checked_unlock( &upstream->c_io_mutex ); 198 199 connection_write_cb( -1, 0, upstream ); 200 return rc; 201 202 fail: 203 if ( upstream ) { 204 CONNECTION_LOCK_DESTROY(upstream); 205 206 operation_send_reject( op, LDAP_OTHER, "internal error", 0 ); 207 } 208 209 operation_unlink( op ); 210 if ( rc ) { 211 CONNECTION_LOCK_DESTROY(client); 212 } 213 return rc; 214 } 215 216 int 217 handle_one_request( LloadConnection *c ) 218 { 219 BerElement *ber; 220 LloadOperation *op = NULL; 221 RequestHandler handler = NULL; 222 int over_limit = 0; 223 224 ber = c->c_currentber; 225 c->c_currentber = NULL; 226 227 CONNECTION_LOCK(c); 228 op = operation_init( c, ber ); 229 if ( !op ) { 230 Debug( LDAP_DEBUG_ANY, "handle_one_request: " 231 "connid=%lu, operation_init failed\n", 232 c->c_connid ); 233 CONNECTION_DESTROY(c); 234 ber_free( ber, 1 ); 235 return -1; 236 } 237 if ( lload_client_max_pending && 238 c->c_n_ops_executing >= lload_client_max_pending ) { 239 over_limit = 1; 240 } 241 CONNECTION_UNLOCK(c); 242 243 switch ( op->o_tag ) { 244 case LDAP_REQ_UNBIND: 245 /* There is never a response for this operation */ 246 op->o_res = LLOAD_OP_COMPLETED; 247 operation_unlink( op ); 248 249 Debug( LDAP_DEBUG_STATS, "handle_one_request: " 250 "received unbind, closing client connid=%lu\n", 251 c->c_connid ); 252 CONNECTION_LOCK_DESTROY(c); 253 return -1; 254 case LDAP_REQ_BIND: 255 handler = request_bind; 256 break; 257 case LDAP_REQ_ABANDON: 258 /* We can't send a response to abandon requests even if a bind is 259 * currently in progress */ 260 return request_abandon( c, op ); 261 case LDAP_REQ_EXTENDED: 262 default: 263 if ( c->c_state == LLOAD_C_BINDING ) { 264 operation_send_reject( 265 op, LDAP_PROTOCOL_ERROR, "bind in progress", 0 ); 266 return LDAP_SUCCESS; 267 } 268 if ( over_limit ) { 269 operation_send_reject( op, LDAP_BUSY, 270 "pending operation limit reached on this connection", 271 0 ); 272 return LDAP_SUCCESS; 273 } 274 if ( c->c_io_state & LLOAD_C_READ_PAUSE ) { 275 operation_send_reject( op, LDAP_BUSY, 276 "writing side backlogged, please keep reading", 0 ); 277 return LDAP_SUCCESS; 278 } 279 if ( op->o_tag == LDAP_REQ_EXTENDED ) { 280 handler = request_extended; 281 } else { 282 handler = request_process; 283 } 284 break; 285 } 286 287 if ( c->c_state == LLOAD_C_CLOSING ) { 288 operation_send_reject( 289 op, LDAP_UNAVAILABLE, "connection is shutting down", 0 ); 290 return LDAP_SUCCESS; 291 } 292 293 return handler( c, op ); 294 } 295 296 #ifdef HAVE_TLS 297 /* 298 * The connection has a token assigned to it when the callback is set up. 299 */ 300 void 301 client_tls_handshake_cb( evutil_socket_t s, short what, void *arg ) 302 { 303 LloadConnection *c = arg; 304 epoch_t epoch; 305 int rc = 0; 306 307 if ( what & EV_TIMEOUT ) { 308 Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: " 309 "connid=%lu, timeout reached, destroying\n", 310 c->c_connid ); 311 goto fail; 312 } 313 314 /* 315 * In case of StartTLS, make sure we flush the response first. 316 * Also before we try to read anything from the connection, it isn't 317 * permitted to Abandon a StartTLS exop per RFC4511 anyway. 318 */ 319 checked_lock( &c->c_io_mutex ); 320 if ( c->c_pendingber ) { 321 checked_unlock( &c->c_io_mutex ); 322 connection_write_cb( s, what, arg ); 323 324 if ( !IS_ALIVE( c, c_live ) ) { 325 goto fail; 326 } 327 328 /* Do we still have data pending? If so, connection_write_cb would 329 * already have arranged the write callback to trigger again */ 330 checked_lock( &c->c_io_mutex ); 331 if ( c->c_pendingber ) { 332 checked_unlock( &c->c_io_mutex ); 333 return; 334 } 335 } 336 337 rc = ldap_pvt_tls_accept( c->c_sb, LLOAD_TLS_CTX ); 338 checked_unlock( &c->c_io_mutex ); 339 if ( rc < 0 ) { 340 goto fail; 341 } 342 343 if ( rc == 0 ) { 344 struct event_base *base = event_get_base( c->c_read_event ); 345 346 /* 347 * We're finished, replace the callbacks 348 * 349 * This is deadlock-safe, since both share the same base - the one 350 * that's just running us. 351 */ 352 CONNECTION_LOCK(c); 353 event_del( c->c_read_event ); 354 event_del( c->c_write_event ); 355 356 c->c_read_timeout = NULL; 357 event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST, 358 connection_read_cb, c ); 359 if ( IS_ALIVE( c, c_live ) ) { 360 event_add( c->c_read_event, c->c_read_timeout ); 361 } 362 363 event_assign( c->c_write_event, base, c->c_fd, EV_WRITE, 364 connection_write_cb, c ); 365 Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: " 366 "connid=%lu finished\n", 367 c->c_connid ); 368 369 c->c_is_tls = LLOAD_TLS_ESTABLISHED; 370 CONNECTION_UNLOCK(c); 371 return; 372 } else if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) { 373 if ( IS_ALIVE( c, c_live ) ) { 374 CONNECTION_LOCK(c); 375 event_add( c->c_write_event, lload_write_timeout ); 376 CONNECTION_UNLOCK(c); 377 } 378 Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: " 379 "connid=%lu need write rc=%d\n", 380 c->c_connid, rc ); 381 } 382 return; 383 384 fail: 385 Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: " 386 "connid=%lu failed rc=%d\n", 387 c->c_connid, rc ); 388 389 assert( c->c_ops == NULL ); 390 epoch = epoch_join(); 391 CONNECTION_LOCK_DESTROY(c); 392 epoch_leave( epoch ); 393 } 394 #endif /* HAVE_TLS */ 395 396 LloadConnection * 397 client_init( 398 ber_socket_t s, 399 const char *peername, 400 struct event_base *base, 401 int flags ) 402 { 403 LloadConnection *c; 404 struct event *event; 405 event_callback_fn read_cb = connection_read_cb, 406 write_cb = connection_write_cb; 407 408 if ( (c = lload_connection_init( s, peername, flags) ) == NULL ) { 409 return NULL; 410 } 411 412 { 413 ber_len_t max = sockbuf_max_incoming_client; 414 ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max ); 415 } 416 417 c->c_state = LLOAD_C_READY; 418 419 if ( flags & CONN_IS_TLS ) { 420 #ifdef HAVE_TLS 421 int rc; 422 423 c->c_is_tls = LLOAD_LDAPS; 424 425 rc = ldap_pvt_tls_accept( c->c_sb, LLOAD_TLS_CTX ); 426 if ( rc < 0 ) { 427 Debug( LDAP_DEBUG_CONNS, "client_init: " 428 "connid=%lu failed initial TLS accept rc=%d\n", 429 c->c_connid, rc ); 430 CONNECTION_LOCK(c); 431 goto fail; 432 } 433 434 if ( rc ) { 435 c->c_read_timeout = lload_timeout_net; 436 read_cb = write_cb = client_tls_handshake_cb; 437 } 438 #else /* ! HAVE_TLS */ 439 assert(0); 440 #endif /* ! HAVE_TLS */ 441 } 442 443 event = event_new( base, s, EV_READ|EV_PERSIST, read_cb, c ); 444 if ( !event ) { 445 Debug( LDAP_DEBUG_ANY, "client_init: " 446 "Read event could not be allocated\n" ); 447 CONNECTION_LOCK(c); 448 goto fail; 449 } 450 c->c_read_event = event; 451 452 event = event_new( base, s, EV_WRITE, write_cb, c ); 453 if ( !event ) { 454 Debug( LDAP_DEBUG_ANY, "client_init: " 455 "Write event could not be allocated\n" ); 456 CONNECTION_LOCK(c); 457 goto fail; 458 } 459 c->c_write_event = event; 460 461 c->c_destroy = client_destroy; 462 c->c_unlink = client_unlink; 463 c->c_pdu_cb = handle_one_request; 464 465 CONNECTION_LOCK(c); 466 /* We only register the write event when we have data pending */ 467 event_add( c->c_read_event, c->c_read_timeout ); 468 469 checked_lock( &clients_mutex ); 470 LDAP_CIRCLEQ_INSERT_TAIL( &clients, c, c_next ); 471 checked_unlock( &clients_mutex ); 472 CONNECTION_UNLOCK(c); 473 474 return c; 475 fail: 476 if ( c->c_write_event ) { 477 event_free( c->c_write_event ); 478 c->c_write_event = NULL; 479 } 480 if ( c->c_read_event ) { 481 event_free( c->c_read_event ); 482 c->c_read_event = NULL; 483 } 484 485 c->c_state = LLOAD_C_INVALID; 486 c->c_live--; 487 c->c_refcnt--; 488 connection_destroy( c ); 489 return NULL; 490 } 491 492 void 493 client_reset( LloadConnection *c ) 494 { 495 TAvlnode *root; 496 long freed = 0, executing; 497 498 CONNECTION_ASSERT_LOCKED(c); 499 root = c->c_ops; 500 c->c_ops = NULL; 501 executing = c->c_n_ops_executing; 502 c->c_n_ops_executing = 0; 503 504 if ( !BER_BVISNULL( &c->c_auth ) ) { 505 ch_free( c->c_auth.bv_val ); 506 BER_BVZERO( &c->c_auth ); 507 } 508 if ( !BER_BVISNULL( &c->c_sasl_bind_mech ) ) { 509 ch_free( c->c_sasl_bind_mech.bv_val ); 510 BER_BVZERO( &c->c_sasl_bind_mech ); 511 } 512 CONNECTION_UNLOCK(c); 513 514 if ( root ) { 515 freed = ldap_tavl_free( root, (AVL_FREE)operation_abandon ); 516 Debug( LDAP_DEBUG_TRACE, "client_reset: " 517 "dropped %ld operations\n", 518 freed ); 519 } 520 assert( freed == executing ); 521 522 CONNECTION_LOCK(c); 523 CONNECTION_ASSERT_LOCKED(c); 524 } 525 526 void 527 client_unlink( LloadConnection *c ) 528 { 529 enum sc_state state; 530 struct event *read_event, *write_event; 531 532 Debug( LDAP_DEBUG_CONNS, "client_unlink: " 533 "removing client connid=%lu\n", 534 c->c_connid ); 535 536 CONNECTION_ASSERT_LOCKED(c); 537 assert( c->c_state != LLOAD_C_INVALID ); 538 assert( c->c_state != LLOAD_C_DYING ); 539 540 state = c->c_state; 541 c->c_state = LLOAD_C_DYING; 542 543 read_event = c->c_read_event; 544 write_event = c->c_write_event; 545 CONNECTION_UNLOCK(c); 546 547 if ( read_event ) { 548 event_del( read_event ); 549 } 550 551 if ( write_event ) { 552 event_del( write_event ); 553 } 554 555 if ( state != LLOAD_C_DYING ) { 556 checked_lock( &clients_mutex ); 557 LDAP_CIRCLEQ_REMOVE( &clients, c, c_next ); 558 checked_unlock( &clients_mutex ); 559 } 560 561 CONNECTION_LOCK(c); 562 client_reset( c ); 563 CONNECTION_ASSERT_LOCKED(c); 564 } 565 566 void 567 client_destroy( LloadConnection *c ) 568 { 569 Debug( LDAP_DEBUG_CONNS, "client_destroy: " 570 "destroying client connid=%lu\n", 571 c->c_connid ); 572 573 CONNECTION_LOCK(c); 574 assert( c->c_state == LLOAD_C_DYING ); 575 c->c_state = LLOAD_C_INVALID; 576 577 assert( c->c_ops == NULL ); 578 579 if ( c->c_read_event ) { 580 event_free( c->c_read_event ); 581 c->c_read_event = NULL; 582 } 583 584 if ( c->c_write_event ) { 585 event_free( c->c_write_event ); 586 c->c_write_event = NULL; 587 } 588 589 assert( c->c_refcnt == 0 ); 590 connection_destroy( c ); 591 } 592 593 void 594 clients_destroy( int gentle ) 595 { 596 checked_lock( &clients_mutex ); 597 connections_walk( 598 &clients_mutex, &clients, lload_connection_close, &gentle ); 599 checked_unlock( &clients_mutex ); 600 } 601