1 /* $NetBSD: sssvlv.c,v 1.1.1.3 2014/05/28 09:58:52 tron Exp $ */ 2 3 /* sssvlv.c - server side sort / virtual list view */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2009-2014 The OpenLDAP Foundation. 8 * Portions copyright 2009 Symas Corporation. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19 /* ACKNOWLEDGEMENTS: 20 * This work was initially developed by Howard Chu for inclusion in 21 * OpenLDAP Software. Support for multiple sorts per connection added 22 * by Raphael Ouazana. 23 */ 24 25 #include "portable.h" 26 27 #ifdef SLAPD_OVER_SSSVLV 28 29 #include <stdio.h> 30 31 #include <ac/string.h> 32 #include <ac/ctype.h> 33 34 #include <avl.h> 35 36 #include "slap.h" 37 #include "lutil.h" 38 #include "config.h" 39 40 #include "../../../libraries/liblber/lber-int.h" /* ber_rewind */ 41 42 /* RFC2891: Server Side Sorting 43 * RFC2696: Paged Results 44 */ 45 #ifndef LDAP_MATCHRULE_IDENTIFIER 46 #define LDAP_MATCHRULE_IDENTIFIER 0x80L 47 #define LDAP_REVERSEORDER_IDENTIFIER 0x81L 48 #define LDAP_ATTRTYPES_IDENTIFIER 0x80L 49 #endif 50 51 /* draft-ietf-ldapext-ldapv3-vlv-09.txt: Virtual List Views 52 */ 53 #ifndef LDAP_VLVBYINDEX_IDENTIFIER 54 #define LDAP_VLVBYINDEX_IDENTIFIER 0xa0L 55 #define LDAP_VLVBYVALUE_IDENTIFIER 0x81L 56 #define LDAP_VLVCONTEXT_IDENTIFIER 0x04L 57 58 #define LDAP_VLV_SSS_MISSING 0x4C 59 #define LDAP_VLV_RANGE_ERROR 0x4D 60 #endif 61 62 #define SAFESTR(macro_str, macro_def) ((macro_str) ? (macro_str) : (macro_def)) 63 64 #define SSSVLV_DEFAULT_MAX_KEYS 5 65 #define SSSVLV_DEFAULT_MAX_REQUEST_PER_CONN 5 66 67 #define NO_PS_COOKIE (PagedResultsCookie) -1 68 #define NO_VC_CONTEXT (unsigned long) -1 69 70 typedef struct vlv_ctrl { 71 int vc_before; 72 int vc_after; 73 int vc_offset; 74 int vc_count; 75 struct berval vc_value; 76 unsigned long vc_context; 77 } vlv_ctrl; 78 79 typedef struct sort_key 80 { 81 AttributeDescription *sk_ad; 82 MatchingRule *sk_ordering; 83 int sk_direction; /* 1=normal, -1=reverse */ 84 } sort_key; 85 86 typedef struct sort_ctrl { 87 int sc_nkeys; 88 sort_key sc_keys[1]; 89 } sort_ctrl; 90 91 92 typedef struct sort_node 93 { 94 int sn_conn; 95 int sn_session; 96 struct berval sn_dn; 97 struct berval *sn_vals; 98 } sort_node; 99 100 typedef struct sssvlv_info 101 { 102 int svi_max; /* max concurrent sorts */ 103 int svi_num; /* current # sorts */ 104 int svi_max_keys; /* max sort keys per request */ 105 int svi_max_percon; /* max concurrent sorts per con */ 106 } sssvlv_info; 107 108 typedef struct sort_op 109 { 110 Avlnode *so_tree; 111 sort_ctrl *so_ctrl; 112 sssvlv_info *so_info; 113 int so_paged; 114 int so_page_size; 115 int so_nentries; 116 int so_vlv; 117 int so_vlv_rc; 118 int so_vlv_target; 119 int so_session; 120 unsigned long so_vcontext; 121 } sort_op; 122 123 /* There is only one conn table for all overlay instances */ 124 /* Each conn can handle one session by context */ 125 static sort_op ***sort_conns; 126 static ldap_pvt_thread_mutex_t sort_conns_mutex; 127 static int ov_count; 128 static const char *debug_header = "sssvlv"; 129 130 static int sss_cid; 131 static int vlv_cid; 132 133 /* RFC 2981 Section 2.2 134 * If a sort key is a multi-valued attribute, and an entry happens to 135 * have multiple values for that attribute and no other controls are 136 * present that affect the sorting order, then the server SHOULD use the 137 * least value (according to the ORDERING rule for that attribute). 138 */ 139 static struct berval* select_value( 140 Attribute *attr, 141 sort_key *key ) 142 { 143 struct berval* ber1, *ber2; 144 MatchingRule *mr = key->sk_ordering; 145 unsigned i; 146 int cmp; 147 148 ber1 = &(attr->a_nvals[0]); 149 ber2 = ber1+1; 150 for ( i = 1; i < attr->a_numvals; i++,ber2++ ) { 151 mr->smr_match( &cmp, 0, mr->smr_syntax, mr, ber1, ber2 ); 152 if ( cmp > 0 ) { 153 ber1 = ber2; 154 } 155 } 156 157 Debug(LDAP_DEBUG_TRACE, "%s: value selected for compare: %s\n", 158 debug_header, 159 SAFESTR(ber1->bv_val, "<Empty>"), 160 0); 161 162 return ber1; 163 } 164 165 static int node_cmp( const void* val1, const void* val2 ) 166 { 167 sort_node *sn1 = (sort_node *)val1; 168 sort_node *sn2 = (sort_node *)val2; 169 sort_ctrl *sc; 170 MatchingRule *mr; 171 int i, cmp = 0; 172 assert( sort_conns[sn1->sn_conn] 173 && sort_conns[sn1->sn_conn][sn1->sn_session] 174 && sort_conns[sn1->sn_conn][sn1->sn_session]->so_ctrl ); 175 sc = sort_conns[sn1->sn_conn][sn1->sn_session]->so_ctrl; 176 177 for ( i=0; cmp == 0 && i<sc->sc_nkeys; i++ ) { 178 if ( BER_BVISNULL( &sn1->sn_vals[i] )) { 179 if ( BER_BVISNULL( &sn2->sn_vals[i] )) 180 cmp = 0; 181 else 182 cmp = sc->sc_keys[i].sk_direction; 183 } else if ( BER_BVISNULL( &sn2->sn_vals[i] )) { 184 cmp = sc->sc_keys[i].sk_direction * -1; 185 } else { 186 mr = sc->sc_keys[i].sk_ordering; 187 mr->smr_match( &cmp, 0, mr->smr_syntax, mr, 188 &sn1->sn_vals[i], &sn2->sn_vals[i] ); 189 if ( cmp ) 190 cmp *= sc->sc_keys[i].sk_direction; 191 } 192 } 193 return cmp; 194 } 195 196 static int node_insert( const void *val1, const void *val2 ) 197 { 198 /* Never return equal so that new entries are always inserted */ 199 return node_cmp( val1, val2 ) < 0 ? -1 : 1; 200 } 201 202 static int pack_vlv_response_control( 203 Operation *op, 204 SlapReply *rs, 205 sort_op *so, 206 LDAPControl **ctrlsp ) 207 { 208 LDAPControl *ctrl; 209 BerElementBuffer berbuf; 210 BerElement *ber = (BerElement *)&berbuf; 211 struct berval cookie, bv; 212 int rc; 213 214 ber_init2( ber, NULL, LBER_USE_DER ); 215 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 216 217 rc = ber_printf( ber, "{iie", so->so_vlv_target, so->so_nentries, 218 so->so_vlv_rc ); 219 220 if ( rc != -1 && so->so_vcontext ) { 221 cookie.bv_val = (char *)&so->so_vcontext; 222 cookie.bv_len = sizeof(so->so_vcontext); 223 rc = ber_printf( ber, "tO", LDAP_VLVCONTEXT_IDENTIFIER, &cookie ); 224 } 225 226 if ( rc != -1 ) { 227 rc = ber_printf( ber, "}" ); 228 } 229 230 if ( rc != -1 ) { 231 rc = ber_flatten2( ber, &bv, 0 ); 232 } 233 234 if ( rc != -1 ) { 235 ctrl = (LDAPControl *)op->o_tmpalloc( sizeof(LDAPControl)+ 236 bv.bv_len, op->o_tmpmemctx ); 237 ctrl->ldctl_oid = LDAP_CONTROL_VLVRESPONSE; 238 ctrl->ldctl_iscritical = 0; 239 ctrl->ldctl_value.bv_val = (char *)(ctrl+1); 240 ctrl->ldctl_value.bv_len = bv.bv_len; 241 AC_MEMCPY( ctrl->ldctl_value.bv_val, bv.bv_val, bv.bv_len ); 242 ctrlsp[0] = ctrl; 243 } else { 244 ctrlsp[0] = NULL; 245 rs->sr_err = LDAP_OTHER; 246 } 247 248 ber_free_buf( ber ); 249 250 return rs->sr_err; 251 } 252 253 static int pack_pagedresult_response_control( 254 Operation *op, 255 SlapReply *rs, 256 sort_op *so, 257 LDAPControl **ctrlsp ) 258 { 259 LDAPControl *ctrl; 260 BerElementBuffer berbuf; 261 BerElement *ber = (BerElement *)&berbuf; 262 PagedResultsCookie resp_cookie; 263 struct berval cookie, bv; 264 int rc; 265 266 ber_init2( ber, NULL, LBER_USE_DER ); 267 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 268 269 if ( so->so_nentries > 0 ) { 270 resp_cookie = ( PagedResultsCookie )so->so_tree; 271 cookie.bv_len = sizeof( PagedResultsCookie ); 272 cookie.bv_val = (char *)&resp_cookie; 273 } else { 274 resp_cookie = ( PagedResultsCookie )0; 275 BER_BVZERO( &cookie ); 276 } 277 278 op->o_conn->c_pagedresults_state.ps_cookie = resp_cookie; 279 op->o_conn->c_pagedresults_state.ps_count 280 = ((PagedResultsState *)op->o_pagedresults_state)->ps_count 281 + rs->sr_nentries; 282 283 rc = ber_printf( ber, "{iO}", so->so_nentries, &cookie ); 284 if ( rc != -1 ) { 285 rc = ber_flatten2( ber, &bv, 0 ); 286 } 287 288 if ( rc != -1 ) { 289 ctrl = (LDAPControl *)op->o_tmpalloc( sizeof(LDAPControl)+ 290 bv.bv_len, op->o_tmpmemctx ); 291 ctrl->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; 292 ctrl->ldctl_iscritical = 0; 293 ctrl->ldctl_value.bv_val = (char *)(ctrl+1); 294 ctrl->ldctl_value.bv_len = bv.bv_len; 295 AC_MEMCPY( ctrl->ldctl_value.bv_val, bv.bv_val, bv.bv_len ); 296 ctrlsp[0] = ctrl; 297 } else { 298 ctrlsp[0] = NULL; 299 rs->sr_err = LDAP_OTHER; 300 } 301 302 ber_free_buf( ber ); 303 304 return rs->sr_err; 305 } 306 307 static int pack_sss_response_control( 308 Operation *op, 309 SlapReply *rs, 310 LDAPControl **ctrlsp ) 311 { 312 LDAPControl *ctrl; 313 BerElementBuffer berbuf; 314 BerElement *ber = (BerElement *)&berbuf; 315 struct berval bv; 316 int rc; 317 318 ber_init2( ber, NULL, LBER_USE_DER ); 319 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 320 321 /* Pack error code */ 322 rc = ber_printf(ber, "{e}", rs->sr_err); 323 324 if ( rc != -1) 325 rc = ber_flatten2( ber, &bv, 0 ); 326 327 if ( rc != -1 ) { 328 ctrl = (LDAPControl *)op->o_tmpalloc( sizeof(LDAPControl)+ 329 bv.bv_len, op->o_tmpmemctx ); 330 ctrl->ldctl_oid = LDAP_CONTROL_SORTRESPONSE; 331 ctrl->ldctl_iscritical = 0; 332 ctrl->ldctl_value.bv_val = (char *)(ctrl+1); 333 ctrl->ldctl_value.bv_len = bv.bv_len; 334 AC_MEMCPY( ctrl->ldctl_value.bv_val, bv.bv_val, bv.bv_len ); 335 ctrlsp[0] = ctrl; 336 } else { 337 ctrlsp[0] = NULL; 338 rs->sr_err = LDAP_OTHER; 339 } 340 341 ber_free_buf( ber ); 342 343 return rs->sr_err; 344 } 345 346 /* Return the session id or -1 if unknown */ 347 static int find_session_by_so( 348 int svi_max_percon, 349 int conn_id, 350 sort_op *so ) 351 { 352 int sess_id; 353 if (so == NULL) { 354 return -1; 355 } 356 for (sess_id = 0; sess_id < svi_max_percon; sess_id++) { 357 if ( sort_conns[conn_id] && sort_conns[conn_id][sess_id] == so ) 358 return sess_id; 359 } 360 return -1; 361 } 362 363 /* Return the session id or -1 if unknown */ 364 static int find_session_by_context( 365 int svi_max_percon, 366 int conn_id, 367 unsigned long vc_context, 368 PagedResultsCookie ps_cookie ) 369 { 370 int sess_id; 371 for(sess_id = 0; sess_id < svi_max_percon; sess_id++) { 372 if( sort_conns[conn_id] && sort_conns[conn_id][sess_id] && 373 ( sort_conns[conn_id][sess_id]->so_vcontext == vc_context || 374 (PagedResultsCookie) sort_conns[conn_id][sess_id]->so_tree == ps_cookie ) ) 375 return sess_id; 376 } 377 return -1; 378 } 379 380 static int find_next_session( 381 int svi_max_percon, 382 int conn_id ) 383 { 384 int sess_id; 385 assert(sort_conns[conn_id] != NULL); 386 for(sess_id = 0; sess_id < svi_max_percon; sess_id++) { 387 if(!sort_conns[conn_id][sess_id]) { 388 return sess_id; 389 } 390 } 391 if (sess_id >= svi_max_percon) { 392 return -1; 393 } else { 394 return sess_id; 395 } 396 } 397 398 static void free_sort_op( Connection *conn, sort_op *so ) 399 { 400 int sess_id; 401 if ( so->so_tree ) { 402 if ( so->so_paged > SLAP_CONTROL_IGNORED ) { 403 Avlnode *cur_node, *next_node; 404 cur_node = so->so_tree; 405 while ( cur_node ) { 406 next_node = tavl_next( cur_node, TAVL_DIR_RIGHT ); 407 ch_free( cur_node->avl_data ); 408 ber_memfree( cur_node ); 409 410 cur_node = next_node; 411 } 412 } else { 413 tavl_free( so->so_tree, ch_free ); 414 } 415 so->so_tree = NULL; 416 } 417 418 ldap_pvt_thread_mutex_lock( &sort_conns_mutex ); 419 sess_id = find_session_by_so( so->so_info->svi_max_percon, conn->c_conn_idx, so ); 420 sort_conns[conn->c_conn_idx][sess_id] = NULL; 421 so->so_info->svi_num--; 422 ldap_pvt_thread_mutex_unlock( &sort_conns_mutex ); 423 424 ch_free( so ); 425 } 426 427 static void free_sort_ops( Connection *conn, sort_op **sos, int svi_max_percon ) 428 { 429 int sess_id; 430 sort_op *so; 431 432 for( sess_id = 0; sess_id < svi_max_percon ; sess_id++ ) { 433 so = sort_conns[conn->c_conn_idx][sess_id]; 434 if ( so ) { 435 free_sort_op( conn, so ); 436 sort_conns[conn->c_conn_idx][sess_id] = NULL; 437 } 438 } 439 } 440 441 static void send_list( 442 Operation *op, 443 SlapReply *rs, 444 sort_op *so) 445 { 446 Avlnode *cur_node, *tmp_node; 447 vlv_ctrl *vc = op->o_controls[vlv_cid]; 448 int i, j, dir, rc; 449 BackendDB *be; 450 Entry *e; 451 LDAPControl *ctrls[2]; 452 453 rs->sr_attrs = op->ors_attrs; 454 455 /* FIXME: it may be better to just flatten the tree into 456 * an array before doing all of this... 457 */ 458 459 /* Are we just counting an offset? */ 460 if ( BER_BVISNULL( &vc->vc_value )) { 461 if ( vc->vc_offset == vc->vc_count ) { 462 /* wants the last entry in the list */ 463 cur_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT); 464 so->so_vlv_target = so->so_nentries; 465 } else if ( vc->vc_offset == 1 ) { 466 /* wants the first entry in the list */ 467 cur_node = tavl_end(so->so_tree, TAVL_DIR_LEFT); 468 so->so_vlv_target = 1; 469 } else { 470 int target; 471 /* Just iterate to the right spot */ 472 if ( vc->vc_count && vc->vc_count != so->so_nentries ) { 473 if ( vc->vc_offset > vc->vc_count ) 474 goto range_err; 475 target = so->so_nentries * vc->vc_offset / vc->vc_count; 476 } else { 477 if ( vc->vc_offset > so->so_nentries ) { 478 range_err: 479 so->so_vlv_rc = LDAP_VLV_RANGE_ERROR; 480 pack_vlv_response_control( op, rs, so, ctrls ); 481 ctrls[1] = NULL; 482 slap_add_ctrls( op, rs, ctrls ); 483 rs->sr_err = LDAP_VLV_ERROR; 484 return; 485 } 486 target = vc->vc_offset; 487 } 488 so->so_vlv_target = target; 489 /* Start at left and go right, or start at right and go left? */ 490 if ( target < so->so_nentries / 2 ) { 491 cur_node = tavl_end(so->so_tree, TAVL_DIR_LEFT); 492 dir = TAVL_DIR_RIGHT; 493 } else { 494 cur_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT); 495 dir = TAVL_DIR_LEFT; 496 target = so->so_nentries - target + 1; 497 } 498 for ( i=1; i<target; i++ ) 499 cur_node = tavl_next( cur_node, dir ); 500 } 501 } else { 502 /* we're looking for a specific value */ 503 sort_ctrl *sc = so->so_ctrl; 504 MatchingRule *mr = sc->sc_keys[0].sk_ordering; 505 sort_node *sn; 506 struct berval bv; 507 508 if ( mr->smr_normalize ) { 509 rc = mr->smr_normalize( SLAP_MR_VALUE_OF_SYNTAX, 510 mr->smr_syntax, mr, &vc->vc_value, &bv, op->o_tmpmemctx ); 511 if ( rc ) { 512 so->so_vlv_rc = LDAP_INAPPROPRIATE_MATCHING; 513 pack_vlv_response_control( op, rs, so, ctrls ); 514 ctrls[1] = NULL; 515 slap_add_ctrls( op, rs, ctrls ); 516 rs->sr_err = LDAP_VLV_ERROR; 517 return; 518 } 519 } else { 520 bv = vc->vc_value; 521 } 522 523 sn = op->o_tmpalloc( sizeof(sort_node) + 524 sc->sc_nkeys * sizeof(struct berval), op->o_tmpmemctx ); 525 sn->sn_vals = (struct berval *)(sn+1); 526 sn->sn_conn = op->o_conn->c_conn_idx; 527 sn->sn_session = find_session_by_so( so->so_info->svi_max_percon, op->o_conn->c_conn_idx, so ); 528 sn->sn_vals[0] = bv; 529 for (i=1; i<sc->sc_nkeys; i++) { 530 BER_BVZERO( &sn->sn_vals[i] ); 531 } 532 cur_node = tavl_find3( so->so_tree, sn, node_cmp, &j ); 533 /* didn't find >= match */ 534 if ( j > 0 ) { 535 if ( cur_node ) 536 cur_node = tavl_next( cur_node, TAVL_DIR_RIGHT ); 537 } 538 op->o_tmpfree( sn, op->o_tmpmemctx ); 539 540 if ( !cur_node ) { 541 so->so_vlv_target = so->so_nentries + 1; 542 } else { 543 sort_node *sn = so->so_tree->avl_data; 544 /* start from the left or the right side? */ 545 mr->smr_match( &i, 0, mr->smr_syntax, mr, &bv, &sn->sn_vals[0] ); 546 if ( i > 0 ) { 547 tmp_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT); 548 dir = TAVL_DIR_LEFT; 549 } else { 550 tmp_node = tavl_end(so->so_tree, TAVL_DIR_LEFT); 551 dir = TAVL_DIR_RIGHT; 552 } 553 for (i=0; tmp_node != cur_node; 554 tmp_node = tavl_next( tmp_node, dir ), i++); 555 so->so_vlv_target = (dir == TAVL_DIR_RIGHT) ? i+1 : so->so_nentries - i; 556 } 557 if ( bv.bv_val != vc->vc_value.bv_val ) 558 op->o_tmpfree( bv.bv_val, op->o_tmpmemctx ); 559 } 560 if ( !cur_node ) { 561 i = 1; 562 cur_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT); 563 } else { 564 i = 0; 565 } 566 for ( ; i<vc->vc_before; i++ ) { 567 tmp_node = tavl_next( cur_node, TAVL_DIR_LEFT ); 568 if ( !tmp_node ) break; 569 cur_node = tmp_node; 570 } 571 j = i + vc->vc_after + 1; 572 be = op->o_bd; 573 for ( i=0; i<j; i++ ) { 574 sort_node *sn = cur_node->avl_data; 575 576 if ( slapd_shutdown ) break; 577 578 op->o_bd = select_backend( &sn->sn_dn, 0 ); 579 e = NULL; 580 rc = be_entry_get_rw( op, &sn->sn_dn, NULL, NULL, 0, &e ); 581 582 if ( e && rc == LDAP_SUCCESS ) { 583 rs->sr_entry = e; 584 rs->sr_flags = REP_ENTRY_MUSTRELEASE; 585 rs->sr_err = send_search_entry( op, rs ); 586 if ( rs->sr_err == LDAP_UNAVAILABLE ) 587 break; 588 } 589 cur_node = tavl_next( cur_node, TAVL_DIR_RIGHT ); 590 if ( !cur_node ) break; 591 } 592 so->so_vlv_rc = LDAP_SUCCESS; 593 594 op->o_bd = be; 595 } 596 597 static void send_page( Operation *op, SlapReply *rs, sort_op *so ) 598 { 599 Avlnode *cur_node = so->so_tree; 600 Avlnode *next_node = NULL; 601 BackendDB *be = op->o_bd; 602 Entry *e; 603 int rc; 604 605 rs->sr_attrs = op->ors_attrs; 606 607 while ( cur_node && rs->sr_nentries < so->so_page_size ) { 608 sort_node *sn = cur_node->avl_data; 609 610 if ( slapd_shutdown ) break; 611 612 next_node = tavl_next( cur_node, TAVL_DIR_RIGHT ); 613 614 op->o_bd = select_backend( &sn->sn_dn, 0 ); 615 e = NULL; 616 rc = be_entry_get_rw( op, &sn->sn_dn, NULL, NULL, 0, &e ); 617 618 ch_free( cur_node->avl_data ); 619 ber_memfree( cur_node ); 620 621 cur_node = next_node; 622 so->so_nentries--; 623 624 if ( e && rc == LDAP_SUCCESS ) { 625 rs->sr_entry = e; 626 rs->sr_flags = REP_ENTRY_MUSTRELEASE; 627 rs->sr_err = send_search_entry( op, rs ); 628 if ( rs->sr_err == LDAP_UNAVAILABLE ) 629 break; 630 } 631 } 632 633 /* Set the first entry to send for the next page */ 634 so->so_tree = next_node; 635 if ( next_node ) 636 next_node->avl_left = NULL; 637 638 op->o_bd = be; 639 } 640 641 static void send_entry( 642 Operation *op, 643 SlapReply *rs, 644 sort_op *so) 645 { 646 Debug(LDAP_DEBUG_TRACE, 647 "%s: response control: status=%d, text=%s\n", 648 debug_header, rs->sr_err, SAFESTR(rs->sr_text, "<None>")); 649 650 if ( !so->so_tree ) 651 return; 652 653 /* RFC 2891: If critical then send the entries iff they were 654 * succesfully sorted. If non-critical send all entries 655 * whether they were sorted or not. 656 */ 657 if ( (op->o_ctrlflag[sss_cid] != SLAP_CONTROL_CRITICAL) || 658 (rs->sr_err == LDAP_SUCCESS) ) 659 { 660 if ( so->so_vlv > SLAP_CONTROL_IGNORED ) { 661 send_list( op, rs, so ); 662 } else { 663 /* Get the first node to send */ 664 Avlnode *start_node = tavl_end(so->so_tree, TAVL_DIR_LEFT); 665 so->so_tree = start_node; 666 667 if ( so->so_paged <= SLAP_CONTROL_IGNORED ) { 668 /* Not paged result search. Send all entries. 669 * Set the page size to the number of entries 670 * so that send_page() will send all entries. 671 */ 672 so->so_page_size = so->so_nentries; 673 } 674 675 send_page( op, rs, so ); 676 } 677 } 678 } 679 680 static void send_result( 681 Operation *op, 682 SlapReply *rs, 683 sort_op *so) 684 { 685 LDAPControl *ctrls[3]; 686 int rc, i = 0; 687 688 rc = pack_sss_response_control( op, rs, ctrls ); 689 if ( rc == LDAP_SUCCESS ) { 690 i++; 691 rc = -1; 692 if ( so->so_paged > SLAP_CONTROL_IGNORED ) { 693 rc = pack_pagedresult_response_control( op, rs, so, ctrls+1 ); 694 } else if ( so->so_vlv > SLAP_CONTROL_IGNORED ) { 695 rc = pack_vlv_response_control( op, rs, so, ctrls+1 ); 696 } 697 if ( rc == LDAP_SUCCESS ) 698 i++; 699 } 700 ctrls[i] = NULL; 701 702 if ( ctrls[0] != NULL ) 703 slap_add_ctrls( op, rs, ctrls ); 704 send_ldap_result( op, rs ); 705 706 if ( so->so_tree == NULL ) { 707 /* Search finished, so clean up */ 708 free_sort_op( op->o_conn, so ); 709 } 710 } 711 712 static int sssvlv_op_response( 713 Operation *op, 714 SlapReply *rs ) 715 { 716 sort_ctrl *sc = op->o_controls[sss_cid]; 717 sort_op *so = op->o_callback->sc_private; 718 719 if ( rs->sr_type == REP_SEARCH ) { 720 int i; 721 size_t len; 722 sort_node *sn, *sn2; 723 struct berval *bv; 724 char *ptr; 725 726 len = sizeof(sort_node) + sc->sc_nkeys * sizeof(struct berval) + 727 rs->sr_entry->e_nname.bv_len + 1; 728 sn = op->o_tmpalloc( len, op->o_tmpmemctx ); 729 sn->sn_vals = (struct berval *)(sn+1); 730 731 /* Build tmp list of key values */ 732 for ( i=0; i<sc->sc_nkeys; i++ ) { 733 Attribute *a = attr_find( rs->sr_entry->e_attrs, 734 sc->sc_keys[i].sk_ad ); 735 if ( a ) { 736 if ( a->a_numvals > 1 ) { 737 bv = select_value( a, &sc->sc_keys[i] ); 738 } else { 739 bv = a->a_nvals; 740 } 741 sn->sn_vals[i] = *bv; 742 len += bv->bv_len + 1; 743 } else { 744 BER_BVZERO( &sn->sn_vals[i] ); 745 } 746 } 747 748 /* Now dup into regular memory */ 749 sn2 = ch_malloc( len ); 750 sn2->sn_vals = (struct berval *)(sn2+1); 751 AC_MEMCPY( sn2->sn_vals, sn->sn_vals, 752 sc->sc_nkeys * sizeof(struct berval)); 753 754 ptr = (char *)(sn2->sn_vals + sc->sc_nkeys); 755 sn2->sn_dn.bv_val = ptr; 756 sn2->sn_dn.bv_len = rs->sr_entry->e_nname.bv_len; 757 AC_MEMCPY( ptr, rs->sr_entry->e_nname.bv_val, 758 rs->sr_entry->e_nname.bv_len ); 759 ptr += rs->sr_entry->e_nname.bv_len; 760 *ptr++ = '\0'; 761 for ( i=0; i<sc->sc_nkeys; i++ ) { 762 if ( !BER_BVISNULL( &sn2->sn_vals[i] )) { 763 AC_MEMCPY(ptr, sn2->sn_vals[i].bv_val, sn2->sn_vals[i].bv_len); 764 sn2->sn_vals[i].bv_val = ptr; 765 ptr += sn2->sn_vals[i].bv_len; 766 *ptr++ = '\0'; 767 } 768 } 769 op->o_tmpfree( sn, op->o_tmpmemctx ); 770 sn = sn2; 771 sn->sn_conn = op->o_conn->c_conn_idx; 772 sn->sn_session = find_session_by_so( so->so_info->svi_max_percon, op->o_conn->c_conn_idx, so ); 773 774 /* Insert into the AVL tree */ 775 tavl_insert(&(so->so_tree), sn, node_insert, avl_dup_error); 776 777 so->so_nentries++; 778 779 /* Collected the keys so that they can be sorted. Thus, stop 780 * the entry from propagating. 781 */ 782 rs->sr_err = LDAP_SUCCESS; 783 } 784 else if ( rs->sr_type == REP_RESULT ) { 785 /* Remove serversort response callback. 786 * We don't want the entries that we are about to send to be 787 * processed by serversort response again. 788 */ 789 if ( op->o_callback->sc_response == sssvlv_op_response ) { 790 op->o_callback = op->o_callback->sc_next; 791 } 792 793 send_entry( op, rs, so ); 794 send_result( op, rs, so ); 795 } 796 797 return rs->sr_err; 798 } 799 800 static int sssvlv_op_search( 801 Operation *op, 802 SlapReply *rs) 803 { 804 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 805 sssvlv_info *si = on->on_bi.bi_private; 806 int rc = SLAP_CB_CONTINUE; 807 int ok; 808 sort_op *so = NULL, so2; 809 sort_ctrl *sc; 810 PagedResultsState *ps; 811 vlv_ctrl *vc; 812 int sess_id; 813 814 if ( op->o_ctrlflag[sss_cid] <= SLAP_CONTROL_IGNORED ) { 815 if ( op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ) { 816 LDAPControl *ctrls[2]; 817 so2.so_vcontext = 0; 818 so2.so_vlv_target = 0; 819 so2.so_nentries = 0; 820 so2.so_vlv_rc = LDAP_VLV_SSS_MISSING; 821 so2.so_vlv = op->o_ctrlflag[vlv_cid]; 822 rc = pack_vlv_response_control( op, rs, &so2, ctrls ); 823 if ( rc == LDAP_SUCCESS ) { 824 ctrls[1] = NULL; 825 slap_add_ctrls( op, rs, ctrls ); 826 } 827 rs->sr_err = LDAP_VLV_ERROR; 828 rs->sr_text = "Sort control is required with VLV"; 829 goto leave; 830 } 831 /* Not server side sort so just continue */ 832 return SLAP_CB_CONTINUE; 833 } 834 835 Debug(LDAP_DEBUG_TRACE, 836 "==> sssvlv_search: <%s> %s, control flag: %d\n", 837 op->o_req_dn.bv_val, op->ors_filterstr.bv_val, 838 op->o_ctrlflag[sss_cid]); 839 840 sc = op->o_controls[sss_cid]; 841 if ( sc->sc_nkeys > si->svi_max_keys ) { 842 rs->sr_text = "Too many sort keys"; 843 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 844 goto leave; 845 } 846 847 ps = ( op->o_pagedresults > SLAP_CONTROL_IGNORED ) ? 848 (PagedResultsState*)(op->o_pagedresults_state) : NULL; 849 vc = op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ? 850 op->o_controls[vlv_cid] : NULL; 851 852 if ( ps && vc ) { 853 rs->sr_text = "VLV incompatible with PagedResults"; 854 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 855 goto leave; 856 } 857 858 ok = 1; 859 ldap_pvt_thread_mutex_lock( &sort_conns_mutex ); 860 /* Is there already a sort running on this conn? */ 861 sess_id = find_session_by_context( si->svi_max_percon, op->o_conn->c_conn_idx, vc ? vc->vc_context : NO_VC_CONTEXT, ps ? ps->ps_cookie : NO_PS_COOKIE ); 862 if ( sess_id >= 0 ) { 863 so = sort_conns[op->o_conn->c_conn_idx][sess_id]; 864 /* Is it a continuation of a VLV search? */ 865 if ( !vc || so->so_vlv <= SLAP_CONTROL_IGNORED || 866 vc->vc_context != so->so_vcontext ) { 867 /* Is it a continuation of a paged search? */ 868 if ( !ps || so->so_paged <= SLAP_CONTROL_IGNORED || 869 op->o_conn->c_pagedresults_state.ps_cookie != ps->ps_cookie ) { 870 ok = 0; 871 } else if ( !ps->ps_size ) { 872 /* Abandoning current request */ 873 ok = 0; 874 so->so_nentries = 0; 875 rs->sr_err = LDAP_SUCCESS; 876 } 877 } 878 if (( vc && so->so_paged > SLAP_CONTROL_IGNORED ) || 879 ( ps && so->so_vlv > SLAP_CONTROL_IGNORED )) { 880 /* changed from paged to vlv or vice versa, abandon */ 881 ok = 0; 882 so->so_nentries = 0; 883 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 884 } 885 /* Are there too many running overall? */ 886 } else if ( si->svi_num >= si->svi_max ) { 887 ok = 0; 888 } else if ( ( sess_id = find_next_session(si->svi_max_percon, op->o_conn->c_conn_idx ) ) < 0 ) { 889 ok = 0; 890 } else { 891 /* OK, this connection now has a sort running */ 892 si->svi_num++; 893 sort_conns[op->o_conn->c_conn_idx][sess_id] = &so2; 894 sort_conns[op->o_conn->c_conn_idx][sess_id]->so_session = sess_id; 895 } 896 ldap_pvt_thread_mutex_unlock( &sort_conns_mutex ); 897 if ( ok ) { 898 /* If we're a global overlay, this check got bypassed */ 899 if ( !op->ors_limit && limits_check( op, rs )) 900 return rs->sr_err; 901 /* are we continuing a VLV search? */ 902 if ( so && vc && vc->vc_context ) { 903 so->so_ctrl = sc; 904 send_list( op, rs, so ); 905 send_result( op, rs, so ); 906 rc = LDAP_SUCCESS; 907 /* are we continuing a paged search? */ 908 } else if ( so && ps && ps->ps_cookie ) { 909 so->so_ctrl = sc; 910 send_page( op, rs, so ); 911 send_result( op, rs, so ); 912 rc = LDAP_SUCCESS; 913 } else { 914 slap_callback *cb = op->o_tmpalloc( sizeof(slap_callback), 915 op->o_tmpmemctx ); 916 /* Install serversort response callback to handle a new search */ 917 if ( ps || vc ) { 918 so = ch_calloc( 1, sizeof(sort_op)); 919 } else { 920 so = op->o_tmpcalloc( 1, sizeof(sort_op), op->o_tmpmemctx ); 921 } 922 sort_conns[op->o_conn->c_conn_idx][sess_id] = so; 923 924 cb->sc_cleanup = NULL; 925 cb->sc_response = sssvlv_op_response; 926 cb->sc_next = op->o_callback; 927 cb->sc_private = so; 928 929 so->so_tree = NULL; 930 so->so_ctrl = sc; 931 so->so_info = si; 932 if ( ps ) { 933 so->so_paged = op->o_pagedresults; 934 so->so_page_size = ps->ps_size; 935 op->o_pagedresults = SLAP_CONTROL_IGNORED; 936 } else { 937 so->so_paged = 0; 938 so->so_page_size = 0; 939 if ( vc ) { 940 so->so_vlv = op->o_ctrlflag[vlv_cid]; 941 so->so_vlv_target = 0; 942 so->so_vlv_rc = 0; 943 } else { 944 so->so_vlv = SLAP_CONTROL_NONE; 945 } 946 } 947 so->so_session = sess_id; 948 so->so_vlv = op->o_ctrlflag[vlv_cid]; 949 so->so_vcontext = (unsigned long)so; 950 so->so_nentries = 0; 951 952 op->o_callback = cb; 953 } 954 } else { 955 if ( so && !so->so_nentries ) { 956 free_sort_op( op->o_conn, so ); 957 } else { 958 rs->sr_text = "Other sort requests already in progress"; 959 rs->sr_err = LDAP_BUSY; 960 } 961 leave: 962 rc = rs->sr_err; 963 send_ldap_result( op, rs ); 964 } 965 966 return rc; 967 } 968 969 static int get_ordering_rule( 970 AttributeDescription *ad, 971 struct berval *matchrule, 972 SlapReply *rs, 973 MatchingRule **ordering ) 974 { 975 MatchingRule* mr; 976 977 if ( matchrule && matchrule->bv_val ) { 978 mr = mr_find( matchrule->bv_val ); 979 if ( mr == NULL ) { 980 rs->sr_err = LDAP_INAPPROPRIATE_MATCHING; 981 rs->sr_text = "serverSort control: No ordering rule"; 982 Debug(LDAP_DEBUG_TRACE, "%s: no ordering rule function for %s\n", 983 debug_header, matchrule->bv_val, 0); 984 } 985 } 986 else { 987 mr = ad->ad_type->sat_ordering; 988 if ( mr == NULL ) { 989 rs->sr_err = LDAP_INAPPROPRIATE_MATCHING; 990 rs->sr_text = "serverSort control: No ordering rule"; 991 Debug(LDAP_DEBUG_TRACE, 992 "%s: no ordering rule specified and no default ordering rule for attribute %s\n", 993 debug_header, ad->ad_cname.bv_val, 0); 994 } 995 } 996 997 *ordering = mr; 998 return rs->sr_err; 999 } 1000 1001 static int count_key(BerElement *ber) 1002 { 1003 char *end; 1004 ber_len_t len; 1005 ber_tag_t tag; 1006 int count = 0; 1007 1008 /* Server Side Sort Control is a SEQUENCE of SEQUENCE */ 1009 for ( tag = ber_first_element( ber, &len, &end ); 1010 tag == LBER_SEQUENCE; 1011 tag = ber_next_element( ber, &len, end )) 1012 { 1013 tag = ber_skip_tag( ber, &len ); 1014 ber_skip_data( ber, len ); 1015 ++count; 1016 } 1017 ber_rewind( ber ); 1018 1019 return count; 1020 } 1021 1022 static int build_key( 1023 BerElement *ber, 1024 SlapReply *rs, 1025 sort_key *key ) 1026 { 1027 struct berval attr; 1028 struct berval matchrule = BER_BVNULL; 1029 ber_int_t reverse = 0; 1030 ber_tag_t tag; 1031 ber_len_t len; 1032 MatchingRule *ordering = NULL; 1033 AttributeDescription *ad = NULL; 1034 const char *text; 1035 1036 if (( tag = ber_scanf( ber, "{" )) == LBER_ERROR ) { 1037 rs->sr_text = "serverSort control: decoding error"; 1038 rs->sr_err = LDAP_PROTOCOL_ERROR; 1039 return rs->sr_err; 1040 } 1041 1042 if (( tag = ber_scanf( ber, "m", &attr )) == LBER_ERROR ) { 1043 rs->sr_text = "serverSort control: attribute decoding error"; 1044 rs->sr_err = LDAP_PROTOCOL_ERROR; 1045 return rs->sr_err; 1046 } 1047 1048 tag = ber_peek_tag( ber, &len ); 1049 if ( tag == LDAP_MATCHRULE_IDENTIFIER ) { 1050 if (( tag = ber_scanf( ber, "m", &matchrule )) == LBER_ERROR ) { 1051 rs->sr_text = "serverSort control: matchrule decoding error"; 1052 rs->sr_err = LDAP_PROTOCOL_ERROR; 1053 return rs->sr_err; 1054 } 1055 tag = ber_peek_tag( ber, &len ); 1056 } 1057 1058 if ( tag == LDAP_REVERSEORDER_IDENTIFIER ) { 1059 if (( tag = ber_scanf( ber, "b", &reverse )) == LBER_ERROR ) { 1060 rs->sr_text = "serverSort control: reverse decoding error"; 1061 rs->sr_err = LDAP_PROTOCOL_ERROR; 1062 return rs->sr_err; 1063 } 1064 } 1065 1066 if (( tag = ber_scanf( ber, "}" )) == LBER_ERROR ) { 1067 rs->sr_text = "serverSort control: decoding error"; 1068 rs->sr_err = LDAP_PROTOCOL_ERROR; 1069 return rs->sr_err; 1070 } 1071 1072 if ( slap_bv2ad( &attr, &ad, &text ) != LDAP_SUCCESS ) { 1073 rs->sr_text = 1074 "serverSort control: Unrecognized attribute type in sort key"; 1075 Debug(LDAP_DEBUG_TRACE, 1076 "%s: Unrecognized attribute type in sort key: %s\n", 1077 debug_header, SAFESTR(attr.bv_val, "<None>"), 0); 1078 rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; 1079 return rs->sr_err; 1080 } 1081 1082 /* get_ordering_rule will set sr_err and sr_text */ 1083 get_ordering_rule( ad, &matchrule, rs, &ordering ); 1084 if ( rs->sr_err != LDAP_SUCCESS ) { 1085 return rs->sr_err; 1086 } 1087 1088 key->sk_ad = ad; 1089 key->sk_ordering = ordering; 1090 key->sk_direction = reverse ? -1 : 1; 1091 1092 return rs->sr_err; 1093 } 1094 1095 /* Conforms to RFC4510 re: Criticality, original RFC2891 spec is broken 1096 * Also see ITS#7253 for discussion 1097 */ 1098 static int sss_parseCtrl( 1099 Operation *op, 1100 SlapReply *rs, 1101 LDAPControl *ctrl ) 1102 { 1103 BerElementBuffer berbuf; 1104 BerElement *ber; 1105 ber_tag_t tag; 1106 ber_len_t len; 1107 int i; 1108 sort_ctrl *sc; 1109 1110 rs->sr_err = LDAP_PROTOCOL_ERROR; 1111 1112 if ( op->o_ctrlflag[sss_cid] > SLAP_CONTROL_IGNORED ) { 1113 rs->sr_text = "sorted results control specified multiple times"; 1114 } else if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { 1115 rs->sr_text = "sorted results control value is absent"; 1116 } else if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { 1117 rs->sr_text = "sorted results control value is empty"; 1118 } else { 1119 rs->sr_err = LDAP_SUCCESS; 1120 } 1121 if ( rs->sr_err != LDAP_SUCCESS ) 1122 return rs->sr_err; 1123 1124 op->o_ctrlflag[sss_cid] = ctrl->ldctl_iscritical ? 1125 SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL; 1126 1127 ber = (BerElement *)&berbuf; 1128 ber_init2( ber, &ctrl->ldctl_value, 0 ); 1129 i = count_key( ber ); 1130 1131 sc = op->o_tmpalloc( sizeof(sort_ctrl) + 1132 (i-1) * sizeof(sort_key), op->o_tmpmemctx ); 1133 sc->sc_nkeys = i; 1134 op->o_controls[sss_cid] = sc; 1135 1136 /* peel off initial sequence */ 1137 ber_scanf( ber, "{" ); 1138 1139 i = 0; 1140 do { 1141 if ( build_key( ber, rs, &sc->sc_keys[i] ) != LDAP_SUCCESS ) 1142 break; 1143 i++; 1144 tag = ber_peek_tag( ber, &len ); 1145 } while ( tag != LBER_DEFAULT ); 1146 1147 return rs->sr_err; 1148 } 1149 1150 static int vlv_parseCtrl( 1151 Operation *op, 1152 SlapReply *rs, 1153 LDAPControl *ctrl ) 1154 { 1155 BerElementBuffer berbuf; 1156 BerElement *ber; 1157 ber_tag_t tag; 1158 ber_len_t len; 1159 vlv_ctrl *vc, vc2; 1160 1161 rs->sr_err = LDAP_PROTOCOL_ERROR; 1162 rs->sr_text = NULL; 1163 1164 if ( op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ) { 1165 rs->sr_text = "vlv control specified multiple times"; 1166 } else if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { 1167 rs->sr_text = "vlv control value is absent"; 1168 } else if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { 1169 rs->sr_text = "vlv control value is empty"; 1170 } 1171 if ( rs->sr_text != NULL ) 1172 return rs->sr_err; 1173 1174 op->o_ctrlflag[vlv_cid] = ctrl->ldctl_iscritical ? 1175 SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL; 1176 1177 ber = (BerElement *)&berbuf; 1178 ber_init2( ber, &ctrl->ldctl_value, 0 ); 1179 1180 rs->sr_err = LDAP_PROTOCOL_ERROR; 1181 1182 tag = ber_scanf( ber, "{ii", &vc2.vc_before, &vc2.vc_after ); 1183 if ( tag == LBER_ERROR ) { 1184 return rs->sr_err; 1185 } 1186 1187 tag = ber_peek_tag( ber, &len ); 1188 if ( tag == LDAP_VLVBYINDEX_IDENTIFIER ) { 1189 tag = ber_scanf( ber, "{ii}", &vc2.vc_offset, &vc2.vc_count ); 1190 if ( tag == LBER_ERROR ) 1191 return rs->sr_err; 1192 BER_BVZERO( &vc2.vc_value ); 1193 } else if ( tag == LDAP_VLVBYVALUE_IDENTIFIER ) { 1194 tag = ber_scanf( ber, "m", &vc2.vc_value ); 1195 if ( tag == LBER_ERROR || BER_BVISNULL( &vc2.vc_value )) 1196 return rs->sr_err; 1197 } else { 1198 return rs->sr_err; 1199 } 1200 tag = ber_peek_tag( ber, &len ); 1201 if ( tag == LDAP_VLVCONTEXT_IDENTIFIER ) { 1202 struct berval bv; 1203 tag = ber_scanf( ber, "m", &bv ); 1204 if ( tag == LBER_ERROR || bv.bv_len != sizeof(vc2.vc_context)) 1205 return rs->sr_err; 1206 AC_MEMCPY( &vc2.vc_context, bv.bv_val, bv.bv_len ); 1207 } else { 1208 vc2.vc_context = 0; 1209 } 1210 1211 vc = op->o_tmpalloc( sizeof(vlv_ctrl), op->o_tmpmemctx ); 1212 *vc = vc2; 1213 op->o_controls[vlv_cid] = vc; 1214 rs->sr_err = LDAP_SUCCESS; 1215 1216 return rs->sr_err; 1217 } 1218 1219 static int sssvlv_connection_destroy( BackendDB *be, Connection *conn ) 1220 { 1221 slap_overinst *on = (slap_overinst *)be->bd_info; 1222 sssvlv_info *si = on->on_bi.bi_private; 1223 1224 if ( sort_conns[conn->c_conn_idx] ) { 1225 free_sort_ops( conn, sort_conns[conn->c_conn_idx], si->svi_max_percon ); 1226 } 1227 1228 return LDAP_SUCCESS; 1229 } 1230 1231 static int sssvlv_db_open( 1232 BackendDB *be, 1233 ConfigReply *cr ) 1234 { 1235 slap_overinst *on = (slap_overinst *)be->bd_info; 1236 sssvlv_info *si = on->on_bi.bi_private; 1237 int rc; 1238 int conn_index; 1239 1240 /* If not set, default to 1/2 of available threads */ 1241 if ( !si->svi_max ) 1242 si->svi_max = connection_pool_max / 2; 1243 1244 if ( dtblsize && !sort_conns ) { 1245 ldap_pvt_thread_mutex_init( &sort_conns_mutex ); 1246 /* accommodate for c_conn_idx == -1 */ 1247 sort_conns = ch_calloc( dtblsize + 1, sizeof(sort_op **) ); 1248 for ( conn_index = 0 ; conn_index < dtblsize + 1 ; conn_index++ ) { 1249 sort_conns[conn_index] = ch_calloc( si->svi_max_percon, sizeof(sort_op *) ); 1250 } 1251 sort_conns++; 1252 } 1253 1254 rc = overlay_register_control( be, LDAP_CONTROL_SORTREQUEST ); 1255 if ( rc == LDAP_SUCCESS ) 1256 rc = overlay_register_control( be, LDAP_CONTROL_VLVREQUEST ); 1257 return rc; 1258 } 1259 1260 static ConfigTable sssvlv_cfg[] = { 1261 { "sssvlv-max", "num", 1262 2, 2, 0, ARG_INT|ARG_OFFSET, 1263 (void *)offsetof(sssvlv_info, svi_max), 1264 "( OLcfgOvAt:21.1 NAME 'olcSssVlvMax' " 1265 "DESC 'Maximum number of concurrent Sort requests' " 1266 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, 1267 { "sssvlv-maxkeys", "num", 1268 2, 2, 0, ARG_INT|ARG_OFFSET, 1269 (void *)offsetof(sssvlv_info, svi_max_keys), 1270 "( OLcfgOvAt:21.2 NAME 'olcSssVlvMaxKeys' " 1271 "DESC 'Maximum number of Keys in a Sort request' " 1272 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, 1273 { "sssvlv-maxperconn", "num", 1274 2, 2, 0, ARG_INT|ARG_OFFSET, 1275 (void *)offsetof(sssvlv_info, svi_max_percon), 1276 "( OLcfgOvAt:21.3 NAME 'olcSssVlvMaxPerConn' " 1277 "DESC 'Maximum number of concurrent paged search requests per connection' " 1278 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, 1279 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 1280 }; 1281 1282 static ConfigOCs sssvlv_ocs[] = { 1283 { "( OLcfgOvOc:21.1 " 1284 "NAME 'olcSssVlvConfig' " 1285 "DESC 'SSS VLV configuration' " 1286 "SUP olcOverlayConfig " 1287 "MAY ( olcSssVlvMax $ olcSssVlvMaxKeys ) )", 1288 Cft_Overlay, sssvlv_cfg, NULL, NULL }, 1289 { NULL, 0, NULL } 1290 }; 1291 1292 static int sssvlv_db_init( 1293 BackendDB *be, 1294 ConfigReply *cr) 1295 { 1296 slap_overinst *on = (slap_overinst *)be->bd_info; 1297 sssvlv_info *si; 1298 1299 if ( ov_count == 0 ) { 1300 int rc; 1301 1302 rc = register_supported_control2( LDAP_CONTROL_SORTREQUEST, 1303 SLAP_CTRL_SEARCH, 1304 NULL, 1305 sss_parseCtrl, 1306 1 /* replace */, 1307 &sss_cid ); 1308 if ( rc != LDAP_SUCCESS ) { 1309 Debug( LDAP_DEBUG_ANY, "Failed to register Sort Request control '%s' (%d)\n", 1310 LDAP_CONTROL_SORTREQUEST, rc, 0 ); 1311 return rc; 1312 } 1313 1314 rc = register_supported_control2( LDAP_CONTROL_VLVREQUEST, 1315 SLAP_CTRL_SEARCH, 1316 NULL, 1317 vlv_parseCtrl, 1318 1 /* replace */, 1319 &vlv_cid ); 1320 if ( rc != LDAP_SUCCESS ) { 1321 Debug( LDAP_DEBUG_ANY, "Failed to register VLV Request control '%s' (%d)\n", 1322 LDAP_CONTROL_VLVREQUEST, rc, 0 ); 1323 #ifdef SLAP_CONFIG_DELETE 1324 overlay_unregister_control( be, LDAP_CONTROL_SORTREQUEST ); 1325 unregister_supported_control( LDAP_CONTROL_SORTREQUEST ); 1326 #endif /* SLAP_CONFIG_DELETE */ 1327 return rc; 1328 } 1329 } 1330 1331 si = (sssvlv_info *)ch_malloc(sizeof(sssvlv_info)); 1332 on->on_bi.bi_private = si; 1333 1334 si->svi_max = 0; 1335 si->svi_num = 0; 1336 si->svi_max_keys = SSSVLV_DEFAULT_MAX_KEYS; 1337 si->svi_max_percon = SSSVLV_DEFAULT_MAX_REQUEST_PER_CONN; 1338 1339 ov_count++; 1340 1341 return LDAP_SUCCESS; 1342 } 1343 1344 static int sssvlv_db_destroy( 1345 BackendDB *be, 1346 ConfigReply *cr ) 1347 { 1348 slap_overinst *on = (slap_overinst *)be->bd_info; 1349 sssvlv_info *si = (sssvlv_info *)on->on_bi.bi_private; 1350 int conn_index; 1351 1352 ov_count--; 1353 if ( !ov_count && sort_conns) { 1354 sort_conns--; 1355 for ( conn_index = 0 ; conn_index < dtblsize + 1 ; conn_index++ ) { 1356 ch_free(sort_conns[conn_index]); 1357 } 1358 ch_free(sort_conns); 1359 ldap_pvt_thread_mutex_destroy( &sort_conns_mutex ); 1360 } 1361 1362 #ifdef SLAP_CONFIG_DELETE 1363 overlay_unregister_control( be, LDAP_CONTROL_SORTREQUEST ); 1364 overlay_unregister_control( be, LDAP_CONTROL_VLVREQUEST ); 1365 if ( ov_count == 0 ) { 1366 unregister_supported_control( LDAP_CONTROL_SORTREQUEST ); 1367 unregister_supported_control( LDAP_CONTROL_VLVREQUEST ); 1368 } 1369 #endif /* SLAP_CONFIG_DELETE */ 1370 1371 if ( si ) { 1372 ch_free( si ); 1373 on->on_bi.bi_private = NULL; 1374 } 1375 return LDAP_SUCCESS; 1376 } 1377 1378 static slap_overinst sssvlv; 1379 1380 int sssvlv_initialize() 1381 { 1382 int rc; 1383 1384 sssvlv.on_bi.bi_type = "sssvlv"; 1385 sssvlv.on_bi.bi_db_init = sssvlv_db_init; 1386 sssvlv.on_bi.bi_db_destroy = sssvlv_db_destroy; 1387 sssvlv.on_bi.bi_db_open = sssvlv_db_open; 1388 sssvlv.on_bi.bi_connection_destroy = sssvlv_connection_destroy; 1389 sssvlv.on_bi.bi_op_search = sssvlv_op_search; 1390 1391 sssvlv.on_bi.bi_cf_ocs = sssvlv_ocs; 1392 1393 rc = config_register_schema( sssvlv_cfg, sssvlv_ocs ); 1394 if ( rc ) 1395 return rc; 1396 1397 rc = overlay_register( &sssvlv ); 1398 if ( rc != LDAP_SUCCESS ) { 1399 Debug( LDAP_DEBUG_ANY, "Failed to register server side sort overlay\n", 0, 0, 0 ); 1400 } 1401 1402 return rc; 1403 } 1404 1405 #if SLAPD_OVER_SSSVLV == SLAPD_MOD_DYNAMIC 1406 int init_module( int argc, char *argv[]) 1407 { 1408 return sssvlv_initialize(); 1409 } 1410 #endif 1411 1412 #endif /* SLAPD_OVER_SSSVLV */ 1413