1 /* $NetBSD: search.c,v 1.3 2021/08/14 16:15:01 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2021 The OpenLDAP Foundation. 7 * Portions Copyright 1999 Dmitry Kovalev. 8 * Portions Copyright 2002 Pierangelo Masarati. 9 * Portions Copyright 2004 Mark Adamson. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted only as authorized by the OpenLDAP 14 * Public License. 15 * 16 * A copy of this license is available in the file LICENSE in the 17 * top-level directory of the distribution or, alternatively, at 18 * <http://www.OpenLDAP.org/license.html>. 19 */ 20 /* ACKNOWLEDGEMENTS: 21 * This work was initially developed by Dmitry Kovalev for inclusion 22 * by OpenLDAP Software. Additional significant contributors include 23 * Pierangelo Masarati and Mark Adamson. 24 */ 25 26 #include <sys/cdefs.h> 27 __RCSID("$NetBSD: search.c,v 1.3 2021/08/14 16:15:01 christos Exp $"); 28 29 #include "portable.h" 30 31 #include <stdio.h> 32 #include <sys/types.h> 33 #include "ac/string.h" 34 #include "ac/ctype.h" 35 36 #include "lutil.h" 37 #include "slap.h" 38 #include "proto-sql.h" 39 40 static int backsql_process_filter( backsql_srch_info *bsi, Filter *f ); 41 static int backsql_process_filter_eq( backsql_srch_info *bsi, 42 backsql_at_map_rec *at, 43 int casefold, struct berval *filter_value ); 44 static int backsql_process_filter_like( backsql_srch_info *bsi, 45 backsql_at_map_rec *at, 46 int casefold, struct berval *filter_value ); 47 static int backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, 48 backsql_at_map_rec *at ); 49 50 /* For LDAP_CONTROL_PAGEDRESULTS, a 32 bit cookie is available to keep track of 51 the state of paged results. The ldap_entries.id and oc_map_id values of the 52 last entry returned are used as the cookie, so 6 bits are used for the OC id 53 and the other 26 for ldap_entries ID number. If your max(oc_map_id) is more 54 than 63, you will need to steal more bits from ldap_entries ID number and 55 put them into the OC ID part of the cookie. */ 56 57 /* NOTE: not supported when BACKSQL_ARBITRARY_KEY is defined */ 58 #ifndef BACKSQL_ARBITRARY_KEY 59 #define SQL_TO_PAGECOOKIE(id, oc) (((id) << 6 ) | ((oc) & 0x3F)) 60 #define PAGECOOKIE_TO_SQL_ID(pc) ((pc) >> 6) 61 #define PAGECOOKIE_TO_SQL_OC(pc) ((pc) & 0x3F) 62 63 static int parse_paged_cookie( Operation *op, SlapReply *rs ); 64 65 static void send_paged_response( 66 Operation *op, 67 SlapReply *rs, 68 ID *lastid ); 69 #endif /* ! BACKSQL_ARBITRARY_KEY */ 70 71 static int 72 backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad ) 73 { 74 int n_attrs = 0; 75 AttributeName *an = NULL; 76 77 if ( bsi->bsi_attrs == NULL ) { 78 return 1; 79 } 80 81 /* 82 * clear the list (retrieve all attrs) 83 */ 84 if ( ad == NULL ) { 85 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx ); 86 bsi->bsi_attrs = NULL; 87 bsi->bsi_flags |= BSQL_SF_ALL_ATTRS; 88 return 1; 89 } 90 91 /* strip ';binary' */ 92 if ( slap_ad_is_binary( ad ) ) { 93 ad = ad->ad_type->sat_ad; 94 } 95 96 for ( ; !BER_BVISNULL( &bsi->bsi_attrs[ n_attrs ].an_name ); n_attrs++ ) { 97 an = &bsi->bsi_attrs[ n_attrs ]; 98 99 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): " 100 "attribute \"%s\" is in list\n", 101 an->an_name.bv_val ); 102 /* 103 * We can live with strcmp because the attribute 104 * list has been normalized before calling be_search 105 */ 106 if ( !BACKSQL_NCMP( &an->an_name, &ad->ad_cname ) ) { 107 return 1; 108 } 109 } 110 111 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): " 112 "adding \"%s\" to list\n", ad->ad_cname.bv_val ); 113 114 an = (AttributeName *)bsi->bsi_op->o_tmprealloc( bsi->bsi_attrs, 115 sizeof( AttributeName ) * ( n_attrs + 2 ), 116 bsi->bsi_op->o_tmpmemctx ); 117 if ( an == NULL ) { 118 return -1; 119 } 120 121 an[ n_attrs ].an_name = ad->ad_cname; 122 an[ n_attrs ].an_desc = ad; 123 BER_BVZERO( &an[ n_attrs + 1 ].an_name ); 124 125 bsi->bsi_attrs = an; 126 127 return 1; 128 } 129 130 /* 131 * Initializes the search structure. 132 * 133 * If get_base_id != 0, the field bsi_base_id is filled 134 * with the entryID of bsi_base_ndn; it must be freed 135 * by backsql_free_entryID() when no longer required. 136 * 137 * NOTE: base must be normalized 138 */ 139 int 140 backsql_init_search( 141 backsql_srch_info *bsi, 142 struct berval *nbase, 143 int scope, 144 time_t stoptime, 145 Filter *filter, 146 SQLHDBC dbh, 147 Operation *op, 148 SlapReply *rs, 149 AttributeName *attrs, 150 unsigned flags ) 151 { 152 backsql_info *bi = (backsql_info *)op->o_bd->be_private; 153 int rc = LDAP_SUCCESS; 154 155 bsi->bsi_base_ndn = nbase; 156 bsi->bsi_use_subtree_shortcut = 0; 157 BER_BVZERO( &bsi->bsi_base_id.eid_dn ); 158 BER_BVZERO( &bsi->bsi_base_id.eid_ndn ); 159 bsi->bsi_scope = scope; 160 bsi->bsi_filter = filter; 161 bsi->bsi_dbh = dbh; 162 bsi->bsi_op = op; 163 bsi->bsi_rs = rs; 164 bsi->bsi_flags = BSQL_SF_NONE; 165 166 bsi->bsi_attrs = NULL; 167 168 if ( BACKSQL_FETCH_ALL_ATTRS( bi ) ) { 169 /* 170 * if requested, simply try to fetch all attributes 171 */ 172 bsi->bsi_flags |= BSQL_SF_ALL_ATTRS; 173 174 } else { 175 if ( BACKSQL_FETCH_ALL_USERATTRS( bi ) ) { 176 bsi->bsi_flags |= BSQL_SF_ALL_USER; 177 178 } else if ( BACKSQL_FETCH_ALL_OPATTRS( bi ) ) { 179 bsi->bsi_flags |= BSQL_SF_ALL_OPER; 180 } 181 182 if ( attrs == NULL ) { 183 /* NULL means all user attributes */ 184 bsi->bsi_flags |= BSQL_SF_ALL_USER; 185 186 } else { 187 AttributeName *p; 188 int got_oc = 0; 189 190 bsi->bsi_attrs = (AttributeName *)bsi->bsi_op->o_tmpalloc( 191 sizeof( AttributeName ), 192 bsi->bsi_op->o_tmpmemctx ); 193 BER_BVZERO( &bsi->bsi_attrs[ 0 ].an_name ); 194 195 for ( p = attrs; !BER_BVISNULL( &p->an_name ); p++ ) { 196 if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_user_attrs ) == 0 ) { 197 /* handle "*" */ 198 bsi->bsi_flags |= BSQL_SF_ALL_USER; 199 200 /* if all attrs are requested, there's 201 * no need to continue */ 202 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) { 203 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, 204 bsi->bsi_op->o_tmpmemctx ); 205 bsi->bsi_attrs = NULL; 206 break; 207 } 208 continue; 209 210 } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_operational_attrs ) == 0 ) { 211 /* handle "+" */ 212 bsi->bsi_flags |= BSQL_SF_ALL_OPER; 213 214 /* if all attrs are requested, there's 215 * no need to continue */ 216 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) { 217 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, 218 bsi->bsi_op->o_tmpmemctx ); 219 bsi->bsi_attrs = NULL; 220 break; 221 } 222 continue; 223 224 } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_no_attrs ) == 0 ) { 225 /* ignore "1.1" */ 226 continue; 227 228 } else if ( p->an_desc == slap_schema.si_ad_objectClass ) { 229 got_oc = 1; 230 } 231 232 backsql_attrlist_add( bsi, p->an_desc ); 233 } 234 235 if ( got_oc == 0 && !( bsi->bsi_flags & BSQL_SF_ALL_USER ) ) { 236 /* add objectClass if not present, 237 * because it is required to understand 238 * if an entry is a referral, an alias 239 * or so... */ 240 backsql_attrlist_add( bsi, slap_schema.si_ad_objectClass ); 241 } 242 } 243 244 if ( !BSQL_ISF_ALL_ATTRS( bsi ) && bi->sql_anlist ) { 245 AttributeName *p; 246 247 /* use hints if available */ 248 for ( p = bi->sql_anlist; !BER_BVISNULL( &p->an_name ); p++ ) { 249 if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_user_attrs ) == 0 ) { 250 /* handle "*" */ 251 bsi->bsi_flags |= BSQL_SF_ALL_USER; 252 253 /* if all attrs are requested, there's 254 * no need to continue */ 255 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) { 256 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, 257 bsi->bsi_op->o_tmpmemctx ); 258 bsi->bsi_attrs = NULL; 259 break; 260 } 261 continue; 262 263 } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_operational_attrs ) == 0 ) { 264 /* handle "+" */ 265 bsi->bsi_flags |= BSQL_SF_ALL_OPER; 266 267 /* if all attrs are requested, there's 268 * no need to continue */ 269 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) { 270 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, 271 bsi->bsi_op->o_tmpmemctx ); 272 bsi->bsi_attrs = NULL; 273 break; 274 } 275 continue; 276 } 277 278 backsql_attrlist_add( bsi, p->an_desc ); 279 } 280 281 } 282 } 283 284 bsi->bsi_id_list = NULL; 285 bsi->bsi_id_listtail = &bsi->bsi_id_list; 286 bsi->bsi_n_candidates = 0; 287 bsi->bsi_stoptime = stoptime; 288 BER_BVZERO( &bsi->bsi_sel.bb_val ); 289 bsi->bsi_sel.bb_len = 0; 290 BER_BVZERO( &bsi->bsi_from.bb_val ); 291 bsi->bsi_from.bb_len = 0; 292 BER_BVZERO( &bsi->bsi_join_where.bb_val ); 293 bsi->bsi_join_where.bb_len = 0; 294 BER_BVZERO( &bsi->bsi_flt_where.bb_val ); 295 bsi->bsi_flt_where.bb_len = 0; 296 bsi->bsi_filter_oc = NULL; 297 298 if ( BACKSQL_IS_GET_ID( flags ) ) { 299 int matched = BACKSQL_IS_MATCHED( flags ); 300 int getentry = BACKSQL_IS_GET_ENTRY( flags ); 301 int gotit = 0; 302 303 assert( op->o_bd->be_private != NULL ); 304 305 rc = backsql_dn2id( op, rs, dbh, nbase, &bsi->bsi_base_id, 306 matched, 1 ); 307 308 /* the entry is collected either if requested for by getentry 309 * or if get noSuchObject and requested to climb the tree, 310 * so that a matchedDN or a referral can be returned */ 311 if ( ( rc == LDAP_NO_SUCH_OBJECT && matched ) || getentry ) { 312 if ( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ) { 313 assert( bsi->bsi_e != NULL ); 314 315 if ( dn_match( nbase, &bsi->bsi_base_id.eid_ndn ) ) 316 { 317 gotit = 1; 318 } 319 320 /* 321 * let's see if it is a referral and, in case, get it 322 */ 323 backsql_attrlist_add( bsi, slap_schema.si_ad_ref ); 324 rc = backsql_id2entry( bsi, &bsi->bsi_base_id ); 325 if ( rc == LDAP_SUCCESS ) { 326 if ( is_entry_referral( bsi->bsi_e ) ) 327 { 328 BerVarray erefs = get_entry_referrals( op, bsi->bsi_e ); 329 if ( erefs ) { 330 rc = rs->sr_err = LDAP_REFERRAL; 331 rs->sr_ref = referral_rewrite( erefs, 332 &bsi->bsi_e->e_nname, 333 &op->o_req_dn, 334 scope ); 335 ber_bvarray_free( erefs ); 336 337 } else { 338 rc = rs->sr_err = LDAP_OTHER; 339 rs->sr_text = "bad referral object"; 340 } 341 342 } else if ( !gotit ) { 343 rc = rs->sr_err = LDAP_NO_SUCH_OBJECT; 344 } 345 } 346 347 } else { 348 rs->sr_err = rc; 349 } 350 } 351 352 if ( gotit && BACKSQL_IS_GET_OC( flags ) ) { 353 bsi->bsi_base_id.eid_oc = backsql_id2oc( bi, 354 bsi->bsi_base_id.eid_oc_id ); 355 if ( bsi->bsi_base_id.eid_oc == NULL ) { 356 /* error? */ 357 backsql_free_entryID( &bsi->bsi_base_id, 1, 358 op->o_tmpmemctx ); 359 rc = rs->sr_err = LDAP_OTHER; 360 } 361 } 362 } 363 364 bsi->bsi_status = rc; 365 366 switch ( rc ) { 367 case LDAP_SUCCESS: 368 case LDAP_REFERRAL: 369 break; 370 371 default: 372 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, 373 bsi->bsi_op->o_tmpmemctx ); 374 break; 375 } 376 377 return rc; 378 } 379 380 static int 381 backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op ) 382 { 383 int res; 384 385 if ( !f ) { 386 return 0; 387 } 388 389 backsql_strfcat_x( &bsi->bsi_flt_where, 390 bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ ); 391 392 while ( 1 ) { 393 res = backsql_process_filter( bsi, f ); 394 if ( res < 0 ) { 395 /* 396 * TimesTen : If the query has no answers, 397 * don't bother to run the query. 398 */ 399 return -1; 400 } 401 402 f = f->f_next; 403 if ( f == NULL ) { 404 break; 405 } 406 407 switch ( op ) { 408 case LDAP_FILTER_AND: 409 backsql_strfcat_x( &bsi->bsi_flt_where, 410 bsi->bsi_op->o_tmpmemctx, "l", 411 (ber_len_t)STRLENOF( " AND " ), 412 " AND " ); 413 break; 414 415 case LDAP_FILTER_OR: 416 backsql_strfcat_x( &bsi->bsi_flt_where, 417 bsi->bsi_op->o_tmpmemctx, "l", 418 (ber_len_t)STRLENOF( " OR " ), 419 " OR " ); 420 break; 421 } 422 } 423 424 backsql_strfcat_x( &bsi->bsi_flt_where, 425 bsi->bsi_op->o_tmpmemctx, "c", /* ( */ ')' ); 426 427 return 1; 428 } 429 430 static int 431 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, 432 backsql_at_map_rec *at ) 433 { 434 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; 435 int i; 436 int casefold = 0; 437 438 if ( !f ) { 439 return 0; 440 } 441 442 /* always uppercase strings by now */ 443 #ifdef BACKSQL_UPPERCASE_FILTER 444 if ( f->f_sub_desc->ad_type->sat_substr && 445 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr, 446 bi->sql_caseIgnoreMatch ) ) 447 #endif /* BACKSQL_UPPERCASE_FILTER */ 448 { 449 casefold = 1; 450 } 451 452 if ( f->f_sub_desc->ad_type->sat_substr && 453 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr, 454 bi->sql_telephoneNumberMatch ) ) 455 { 456 457 struct berval bv; 458 ber_len_t i, s, a; 459 460 /* 461 * to check for matching telephone numbers 462 * with intermixed chars, e.g. val='1234' 463 * use 464 * 465 * val LIKE '%1%2%3%4%' 466 */ 467 468 BER_BVZERO( &bv ); 469 if ( f->f_sub_initial.bv_val ) { 470 bv.bv_len += f->f_sub_initial.bv_len; 471 } 472 if ( f->f_sub_any != NULL ) { 473 for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) { 474 bv.bv_len += f->f_sub_any[ a ].bv_len; 475 } 476 } 477 if ( f->f_sub_final.bv_val ) { 478 bv.bv_len += f->f_sub_final.bv_len; 479 } 480 bv.bv_len = 2 * bv.bv_len - 1; 481 bv.bv_val = ch_malloc( bv.bv_len + 1 ); 482 483 s = 0; 484 if ( !BER_BVISNULL( &f->f_sub_initial ) ) { 485 bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ]; 486 for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) { 487 bv.bv_val[ s + 2 * i - 1 ] = '%'; 488 bv.bv_val[ s + 2 * i ] = f->f_sub_initial.bv_val[ i ]; 489 } 490 bv.bv_val[ s + 2 * i - 1 ] = '%'; 491 s += 2 * i; 492 } 493 494 if ( f->f_sub_any != NULL ) { 495 for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) { 496 bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ]; 497 for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) { 498 bv.bv_val[ s + 2 * i - 1 ] = '%'; 499 bv.bv_val[ s + 2 * i ] = f->f_sub_any[ a ].bv_val[ i ]; 500 } 501 bv.bv_val[ s + 2 * i - 1 ] = '%'; 502 s += 2 * i; 503 } 504 } 505 506 if ( !BER_BVISNULL( &f->f_sub_final ) ) { 507 bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ]; 508 for ( i = 1; i < f->f_sub_final.bv_len; i++ ) { 509 bv.bv_val[ s + 2 * i - 1 ] = '%'; 510 bv.bv_val[ s + 2 * i ] = f->f_sub_final.bv_val[ i ]; 511 } 512 bv.bv_val[ s + 2 * i - 1 ] = '%'; 513 s += 2 * i; 514 } 515 516 bv.bv_val[ s - 1 ] = '\0'; 517 518 (void)backsql_process_filter_like( bsi, at, casefold, &bv ); 519 ch_free( bv.bv_val ); 520 521 return 1; 522 } 523 524 /* 525 * When dealing with case-sensitive strings 526 * we may omit normalization; however, normalized 527 * SQL filters are more liberal. 528 */ 529 530 backsql_strfcat_x( &bsi->bsi_flt_where, 531 bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ ); 532 533 /* TimesTen */ 534 Debug( LDAP_DEBUG_TRACE, "backsql_process_sub_filter(%s):\n", 535 at->bam_ad->ad_cname.bv_val ); 536 Debug(LDAP_DEBUG_TRACE, " expr: '%s%s%s'\n", at->bam_sel_expr.bv_val, 537 at->bam_sel_expr_u.bv_val ? "' '" : "", 538 at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" ); 539 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { 540 /* 541 * If a pre-upper-cased version of the column 542 * or a precompiled upper function exists, use it 543 */ 544 backsql_strfcat_x( &bsi->bsi_flt_where, 545 bsi->bsi_op->o_tmpmemctx, 546 "bl", 547 &at->bam_sel_expr_u, 548 (ber_len_t)STRLENOF( " LIKE '" ), 549 " LIKE '" ); 550 551 } else { 552 backsql_strfcat_x( &bsi->bsi_flt_where, 553 bsi->bsi_op->o_tmpmemctx, 554 "bl", 555 &at->bam_sel_expr, 556 (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" ); 557 } 558 559 if ( !BER_BVISNULL( &f->f_sub_initial ) ) { 560 ber_len_t start; 561 562 #ifdef BACKSQL_TRACE 563 Debug( LDAP_DEBUG_TRACE, 564 "==>backsql_process_sub_filter(%s): " 565 "sub_initial=\"%s\"\n", at->bam_ad->ad_cname.bv_val, 566 f->f_sub_initial.bv_val ); 567 #endif /* BACKSQL_TRACE */ 568 569 start = bsi->bsi_flt_where.bb_val.bv_len; 570 backsql_strfcat_x( &bsi->bsi_flt_where, 571 bsi->bsi_op->o_tmpmemctx, 572 "b", 573 &f->f_sub_initial ); 574 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { 575 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); 576 } 577 } 578 579 backsql_strfcat_x( &bsi->bsi_flt_where, 580 bsi->bsi_op->o_tmpmemctx, 581 "c", '%' ); 582 583 if ( f->f_sub_any != NULL ) { 584 for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) { 585 ber_len_t start; 586 587 #ifdef BACKSQL_TRACE 588 Debug( LDAP_DEBUG_TRACE, 589 "==>backsql_process_sub_filter(%s): " 590 "sub_any[%d]=\"%s\"\n", at->bam_ad->ad_cname.bv_val, 591 i, f->f_sub_any[ i ].bv_val ); 592 #endif /* BACKSQL_TRACE */ 593 594 start = bsi->bsi_flt_where.bb_val.bv_len; 595 backsql_strfcat_x( &bsi->bsi_flt_where, 596 bsi->bsi_op->o_tmpmemctx, 597 "bc", 598 &f->f_sub_any[ i ], 599 '%' ); 600 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { 601 /* 602 * Note: toupper('%') = '%' 603 */ 604 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); 605 } 606 } 607 } 608 609 if ( !BER_BVISNULL( &f->f_sub_final ) ) { 610 ber_len_t start; 611 612 #ifdef BACKSQL_TRACE 613 Debug( LDAP_DEBUG_TRACE, 614 "==>backsql_process_sub_filter(%s): " 615 "sub_final=\"%s\"\n", at->bam_ad->ad_cname.bv_val, 616 f->f_sub_final.bv_val ); 617 #endif /* BACKSQL_TRACE */ 618 619 start = bsi->bsi_flt_where.bb_val.bv_len; 620 backsql_strfcat_x( &bsi->bsi_flt_where, 621 bsi->bsi_op->o_tmpmemctx, 622 "b", 623 &f->f_sub_final ); 624 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { 625 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); 626 } 627 } 628 629 backsql_strfcat_x( &bsi->bsi_flt_where, 630 bsi->bsi_op->o_tmpmemctx, 631 "l", 632 (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" ); 633 634 return 1; 635 } 636 637 static int 638 backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls ) 639 { 640 if ( BER_BVISNULL( from_tbls ) ) { 641 return LDAP_SUCCESS; 642 } 643 644 if ( !BER_BVISNULL( &bsi->bsi_from.bb_val ) ) { 645 char *start, *end; 646 struct berval tmp; 647 648 ber_dupbv_x( &tmp, from_tbls, bsi->bsi_op->o_tmpmemctx ); 649 650 for ( start = tmp.bv_val, end = strchr( start, ',' ); start; ) { 651 if ( end ) { 652 end[0] = '\0'; 653 } 654 655 if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL ) 656 { 657 backsql_strfcat_x( &bsi->bsi_from, 658 bsi->bsi_op->o_tmpmemctx, 659 "cs", ',', start ); 660 } 661 662 if ( end ) { 663 /* in case there are spaces after the comma... */ 664 for ( start = &end[1]; isspace( start[0] ); start++ ); 665 if ( start[0] ) { 666 end = strchr( start, ',' ); 667 } else { 668 start = NULL; 669 } 670 } else { 671 start = NULL; 672 } 673 } 674 675 bsi->bsi_op->o_tmpfree( tmp.bv_val, bsi->bsi_op->o_tmpmemctx ); 676 677 } else { 678 backsql_strfcat_x( &bsi->bsi_from, 679 bsi->bsi_op->o_tmpmemctx, 680 "b", from_tbls ); 681 } 682 683 return LDAP_SUCCESS; 684 } 685 686 static int 687 backsql_process_filter( backsql_srch_info *bsi, Filter *f ) 688 { 689 backsql_at_map_rec **vat = NULL; 690 AttributeDescription *ad = NULL; 691 unsigned i; 692 int done = 0; 693 int rc = 0; 694 695 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n" ); 696 if ( f->f_choice == SLAPD_FILTER_COMPUTED ) { 697 struct berval flt; 698 char *msg = NULL; 699 700 switch ( f->f_result ) { 701 case LDAP_COMPARE_TRUE: 702 BER_BVSTR( &flt, "10=10" ); 703 msg = "TRUE"; 704 break; 705 706 case LDAP_COMPARE_FALSE: 707 BER_BVSTR( &flt, "11=0" ); 708 msg = "FALSE"; 709 break; 710 711 case SLAPD_COMPARE_UNDEFINED: 712 BER_BVSTR( &flt, "12=0" ); 713 msg = "UNDEFINED"; 714 break; 715 716 default: 717 rc = -1; 718 goto done; 719 } 720 721 Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): " 722 "filter computed (%s)\n", msg ); 723 backsql_strfcat_x( &bsi->bsi_flt_where, 724 bsi->bsi_op->o_tmpmemctx, "b", &flt ); 725 rc = 1; 726 goto done; 727 } 728 729 if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) { 730 backsql_strfcat_x( &bsi->bsi_flt_where, 731 bsi->bsi_op->o_tmpmemctx, 732 "l", 733 (ber_len_t)STRLENOF( "1=0" ), "1=0" ); 734 done = 1; 735 rc = 1; 736 goto done; 737 } 738 739 switch( f->f_choice ) { 740 case LDAP_FILTER_OR: 741 rc = backsql_process_filter_list( bsi, f->f_or, 742 LDAP_FILTER_OR ); 743 done = 1; 744 break; 745 746 case LDAP_FILTER_AND: 747 rc = backsql_process_filter_list( bsi, f->f_and, 748 LDAP_FILTER_AND ); 749 done = 1; 750 break; 751 752 case LDAP_FILTER_NOT: 753 backsql_strfcat_x( &bsi->bsi_flt_where, 754 bsi->bsi_op->o_tmpmemctx, 755 "l", 756 (ber_len_t)STRLENOF( "NOT (" /* ) */ ), 757 "NOT (" /* ) */ ); 758 rc = backsql_process_filter( bsi, f->f_not ); 759 backsql_strfcat_x( &bsi->bsi_flt_where, 760 bsi->bsi_op->o_tmpmemctx, 761 "c", /* ( */ ')' ); 762 done = 1; 763 break; 764 765 case LDAP_FILTER_PRESENT: 766 ad = f->f_desc; 767 break; 768 769 case LDAP_FILTER_EXT: 770 ad = f->f_mra->ma_desc; 771 if ( f->f_mr_dnattrs ) { 772 /* 773 * if dn attrs filtering is requested, better return 774 * success and let test_filter() deal with candidate 775 * selection; otherwise we'd need to set conditions 776 * on the contents of the DN, e.g. "SELECT ... FROM 777 * ldap_entries AS attributeName WHERE attributeName.dn 778 * like '%attributeName=value%'" 779 */ 780 backsql_strfcat_x( &bsi->bsi_flt_where, 781 bsi->bsi_op->o_tmpmemctx, 782 "l", 783 (ber_len_t)STRLENOF( "1=1" ), "1=1" ); 784 bsi->bsi_status = LDAP_SUCCESS; 785 rc = 1; 786 goto done; 787 } 788 break; 789 790 default: 791 ad = f->f_av_desc; 792 break; 793 } 794 795 if ( rc == -1 ) { 796 goto done; 797 } 798 799 if ( done ) { 800 rc = 1; 801 goto done; 802 } 803 804 /* 805 * Turn structuralObjectClass into objectClass 806 */ 807 if ( ad == slap_schema.si_ad_objectClass 808 || ad == slap_schema.si_ad_structuralObjectClass ) 809 { 810 /* 811 * If the filter is LDAP_FILTER_PRESENT, then it's done; 812 * otherwise, let's see if we are lucky: filtering 813 * for "structural" objectclass or ancestor... 814 */ 815 switch ( f->f_choice ) { 816 case LDAP_FILTER_EQUALITY: 817 { 818 ObjectClass *oc = oc_bvfind( &f->f_av_value ); 819 820 if ( oc == NULL ) { 821 Debug( LDAP_DEBUG_TRACE, 822 "backsql_process_filter(): " 823 "unknown objectClass \"%s\" " 824 "in filter\n", 825 f->f_av_value.bv_val ); 826 bsi->bsi_status = LDAP_OTHER; 827 rc = -1; 828 goto done; 829 } 830 831 /* 832 * "structural" objectClass inheritance: 833 * - a search for "person" will also return 834 * "inetOrgPerson" 835 * - a search for "top" will return everything 836 */ 837 if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) { 838 static struct berval ldap_entry_objclasses = BER_BVC( "ldap_entry_objclasses" ); 839 840 backsql_merge_from_tbls( bsi, &ldap_entry_objclasses ); 841 842 backsql_strfcat_x( &bsi->bsi_flt_where, 843 bsi->bsi_op->o_tmpmemctx, 844 "lbl", 845 (ber_len_t)STRLENOF( "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */ ), 846 "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */, 847 &bsi->bsi_oc->bom_oc->soc_cname, 848 (ber_len_t)STRLENOF( /* ((' */ "'))" ), 849 /* ((' */ "'))" ); 850 bsi->bsi_status = LDAP_SUCCESS; 851 rc = 1; 852 goto done; 853 } 854 855 break; 856 } 857 858 case LDAP_FILTER_PRESENT: 859 backsql_strfcat_x( &bsi->bsi_flt_where, 860 bsi->bsi_op->o_tmpmemctx, 861 "l", 862 (ber_len_t)STRLENOF( "3=3" ), "3=3" ); 863 bsi->bsi_status = LDAP_SUCCESS; 864 rc = 1; 865 goto done; 866 867 /* FIXME: LDAP_FILTER_EXT? */ 868 869 default: 870 Debug( LDAP_DEBUG_TRACE, 871 "backsql_process_filter(): " 872 "illegal/unhandled filter " 873 "on objectClass attribute" ); 874 bsi->bsi_status = LDAP_OTHER; 875 rc = -1; 876 goto done; 877 } 878 879 } else if ( ad == slap_schema.si_ad_entryUUID ) { 880 unsigned long oc_id; 881 #ifdef BACKSQL_ARBITRARY_KEY 882 struct berval keyval; 883 #else /* ! BACKSQL_ARBITRARY_KEY */ 884 unsigned long keyval; 885 char keyvalbuf[LDAP_PVT_INTTYPE_CHARS(unsigned long)]; 886 #endif /* ! BACKSQL_ARBITRARY_KEY */ 887 888 switch ( f->f_choice ) { 889 case LDAP_FILTER_EQUALITY: 890 backsql_entryUUID_decode( &f->f_av_value, &oc_id, &keyval ); 891 892 if ( oc_id != bsi->bsi_oc->bom_id ) { 893 bsi->bsi_status = LDAP_SUCCESS; 894 rc = -1; 895 goto done; 896 } 897 898 #ifdef BACKSQL_ARBITRARY_KEY 899 backsql_strfcat_x( &bsi->bsi_flt_where, 900 bsi->bsi_op->o_tmpmemctx, 901 "bcblbc", 902 &bsi->bsi_oc->bom_keytbl, '.', 903 &bsi->bsi_oc->bom_keycol, 904 STRLENOF( " LIKE '" ), " LIKE '", 905 &keyval, '\'' ); 906 #else /* ! BACKSQL_ARBITRARY_KEY */ 907 snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval ); 908 backsql_strfcat_x( &bsi->bsi_flt_where, 909 bsi->bsi_op->o_tmpmemctx, 910 "bcbcs", 911 &bsi->bsi_oc->bom_keytbl, '.', 912 &bsi->bsi_oc->bom_keycol, '=', keyvalbuf ); 913 #endif /* ! BACKSQL_ARBITRARY_KEY */ 914 break; 915 916 case LDAP_FILTER_PRESENT: 917 backsql_strfcat_x( &bsi->bsi_flt_where, 918 bsi->bsi_op->o_tmpmemctx, 919 "l", 920 (ber_len_t)STRLENOF( "4=4" ), "4=4" ); 921 break; 922 923 default: 924 rc = -1; 925 goto done; 926 } 927 928 bsi->bsi_flags |= BSQL_SF_FILTER_ENTRYUUID; 929 rc = 1; 930 goto done; 931 932 #ifdef BACKSQL_SYNCPROV 933 } else if ( ad == slap_schema.si_ad_entryCSN ) { 934 /* 935 * support for syncrepl as provider... 936 */ 937 #if 0 938 if ( !bsi->bsi_op->o_sync ) { 939 /* unsupported at present... */ 940 bsi->bsi_status = LDAP_OTHER; 941 rc = -1; 942 goto done; 943 } 944 #endif 945 946 bsi->bsi_flags |= ( BSQL_SF_FILTER_ENTRYCSN | BSQL_SF_RETURN_ENTRYUUID); 947 948 /* if doing a syncrepl, try to return as much as possible, 949 * and always match the filter */ 950 backsql_strfcat_x( &bsi->bsi_flt_where, 951 bsi->bsi_op->o_tmpmemctx, 952 "l", 953 (ber_len_t)STRLENOF( "5=5" ), "5=5" ); 954 955 /* save for later use in operational attributes */ 956 /* FIXME: saves only the first occurrence, because 957 * the filter during updates is written as 958 * "(&(entryCSN<={contextCSN})(entryCSN>={oldContextCSN})({filter}))" 959 * so we want our fake entryCSN to match the greatest 960 * value 961 */ 962 if ( bsi->bsi_op->o_private == NULL ) { 963 bsi->bsi_op->o_private = &f->f_av_value; 964 } 965 bsi->bsi_status = LDAP_SUCCESS; 966 967 rc = 1; 968 goto done; 969 #endif /* BACKSQL_SYNCPROV */ 970 971 } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) { 972 /* 973 * FIXME: this is not robust; e.g. a filter 974 * '(!(hasSubordinates=TRUE))' fails because 975 * in SQL it would read 'NOT (1=1)' instead 976 * of no condition. 977 * Note however that hasSubordinates is boolean, 978 * so a more appropriate filter would be 979 * '(hasSubordinates=FALSE)' 980 * 981 * A more robust search for hasSubordinates 982 * would * require joining the ldap_entries table 983 * selecting if there are descendants of the 984 * candidate. 985 */ 986 backsql_strfcat_x( &bsi->bsi_flt_where, 987 bsi->bsi_op->o_tmpmemctx, 988 "l", 989 (ber_len_t)STRLENOF( "6=6" ), "6=6" ); 990 if ( ad == slap_schema.si_ad_hasSubordinates ) { 991 /* 992 * instruct candidate selection algorithm 993 * and attribute list to try to detect 994 * if an entry has subordinates 995 */ 996 bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE; 997 998 } else { 999 /* 1000 * clear attributes to fetch, to require ALL 1001 * and try extended match on all attributes 1002 */ 1003 backsql_attrlist_add( bsi, NULL ); 1004 } 1005 rc = 1; 1006 goto done; 1007 } 1008 1009 /* 1010 * attribute inheritance: 1011 */ 1012 if ( backsql_supad2at( bsi->bsi_oc, ad, &vat ) ) { 1013 bsi->bsi_status = LDAP_OTHER; 1014 rc = -1; 1015 goto done; 1016 } 1017 1018 if ( vat == NULL ) { 1019 /* search anyway; other parts of the filter 1020 * may succeed */ 1021 backsql_strfcat_x( &bsi->bsi_flt_where, 1022 bsi->bsi_op->o_tmpmemctx, 1023 "l", 1024 (ber_len_t)STRLENOF( "7=7" ), "7=7" ); 1025 bsi->bsi_status = LDAP_SUCCESS; 1026 rc = 1; 1027 goto done; 1028 } 1029 1030 /* if required, open extra level of parens */ 1031 done = 0; 1032 if ( vat[0]->bam_next || vat[1] ) { 1033 backsql_strfcat_x( &bsi->bsi_flt_where, 1034 bsi->bsi_op->o_tmpmemctx, 1035 "c", '(' ); 1036 done = 1; 1037 } 1038 1039 i = 0; 1040 next:; 1041 /* apply attr */ 1042 if ( backsql_process_filter_attr( bsi, f, vat[i] ) == -1 ) { 1043 return -1; 1044 } 1045 1046 /* if more definitions of the same attr, apply */ 1047 if ( vat[i]->bam_next ) { 1048 backsql_strfcat_x( &bsi->bsi_flt_where, 1049 bsi->bsi_op->o_tmpmemctx, 1050 "l", 1051 STRLENOF( " OR " ), " OR " ); 1052 vat[i] = vat[i]->bam_next; 1053 goto next; 1054 } 1055 1056 /* if more descendants of the same attr, apply */ 1057 i++; 1058 if ( vat[i] ) { 1059 backsql_strfcat_x( &bsi->bsi_flt_where, 1060 bsi->bsi_op->o_tmpmemctx, 1061 "l", 1062 STRLENOF( " OR " ), " OR " ); 1063 goto next; 1064 } 1065 1066 /* if needed, close extra level of parens */ 1067 if ( done ) { 1068 backsql_strfcat_x( &bsi->bsi_flt_where, 1069 bsi->bsi_op->o_tmpmemctx, 1070 "c", ')' ); 1071 } 1072 1073 rc = 1; 1074 1075 done:; 1076 if ( vat ) { 1077 ch_free( vat ); 1078 } 1079 1080 Debug( LDAP_DEBUG_TRACE, 1081 "<==backsql_process_filter() %s\n", 1082 rc == 1 ? "succeeded" : "failed" ); 1083 1084 return rc; 1085 } 1086 1087 static int 1088 backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at, 1089 int casefold, struct berval *filter_value ) 1090 { 1091 /* 1092 * maybe we should check type of at->sel_expr here somehow, 1093 * to know whether upper_func is applicable, but for now 1094 * upper_func stuff is made for Oracle, where UPPER is 1095 * safely applicable to NUMBER etc. 1096 */ 1097 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { 1098 ber_len_t start; 1099 1100 backsql_strfcat_x( &bsi->bsi_flt_where, 1101 bsi->bsi_op->o_tmpmemctx, 1102 "cbl", 1103 '(', /* ) */ 1104 &at->bam_sel_expr_u, 1105 (ber_len_t)STRLENOF( "='" ), 1106 "='" ); 1107 1108 start = bsi->bsi_flt_where.bb_val.bv_len; 1109 1110 backsql_strfcat_x( &bsi->bsi_flt_where, 1111 bsi->bsi_op->o_tmpmemctx, 1112 "bl", 1113 filter_value, 1114 (ber_len_t)STRLENOF( /* (' */ "')" ), 1115 /* (' */ "')" ); 1116 1117 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); 1118 1119 } else { 1120 backsql_strfcat_x( &bsi->bsi_flt_where, 1121 bsi->bsi_op->o_tmpmemctx, 1122 "cblbl", 1123 '(', /* ) */ 1124 &at->bam_sel_expr, 1125 (ber_len_t)STRLENOF( "='" ), "='", 1126 filter_value, 1127 (ber_len_t)STRLENOF( /* (' */ "')" ), 1128 /* (' */ "')" ); 1129 } 1130 1131 return 1; 1132 } 1133 1134 static int 1135 backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at, 1136 int casefold, struct berval *filter_value ) 1137 { 1138 /* 1139 * maybe we should check type of at->sel_expr here somehow, 1140 * to know whether upper_func is applicable, but for now 1141 * upper_func stuff is made for Oracle, where UPPER is 1142 * safely applicable to NUMBER etc. 1143 */ 1144 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { 1145 ber_len_t start; 1146 1147 backsql_strfcat_x( &bsi->bsi_flt_where, 1148 bsi->bsi_op->o_tmpmemctx, 1149 "cbl", 1150 '(', /* ) */ 1151 &at->bam_sel_expr_u, 1152 (ber_len_t)STRLENOF( " LIKE '%" ), 1153 " LIKE '%" ); 1154 1155 start = bsi->bsi_flt_where.bb_val.bv_len; 1156 1157 backsql_strfcat_x( &bsi->bsi_flt_where, 1158 bsi->bsi_op->o_tmpmemctx, 1159 "bl", 1160 filter_value, 1161 (ber_len_t)STRLENOF( /* (' */ "%')" ), 1162 /* (' */ "%')" ); 1163 1164 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); 1165 1166 } else { 1167 backsql_strfcat_x( &bsi->bsi_flt_where, 1168 bsi->bsi_op->o_tmpmemctx, 1169 "cblbl", 1170 '(', /* ) */ 1171 &at->bam_sel_expr, 1172 (ber_len_t)STRLENOF( " LIKE '%" ), 1173 " LIKE '%", 1174 filter_value, 1175 (ber_len_t)STRLENOF( /* (' */ "%')" ), 1176 /* (' */ "%')" ); 1177 } 1178 1179 return 1; 1180 } 1181 1182 static int 1183 backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at ) 1184 { 1185 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; 1186 int casefold = 0; 1187 struct berval *filter_value = NULL; 1188 MatchingRule *matching_rule = NULL; 1189 struct berval ordering = BER_BVC("<="); 1190 1191 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n", 1192 at->bam_ad->ad_cname.bv_val ); 1193 1194 /* 1195 * need to add this attribute to list of attrs to load, 1196 * so that we can do test_filter() later 1197 */ 1198 backsql_attrlist_add( bsi, at->bam_ad ); 1199 1200 backsql_merge_from_tbls( bsi, &at->bam_from_tbls ); 1201 1202 if ( !BER_BVISNULL( &at->bam_join_where ) 1203 && strstr( bsi->bsi_join_where.bb_val.bv_val, 1204 at->bam_join_where.bv_val ) == NULL ) 1205 { 1206 backsql_strfcat_x( &bsi->bsi_join_where, 1207 bsi->bsi_op->o_tmpmemctx, 1208 "lb", 1209 (ber_len_t)STRLENOF( " AND " ), " AND ", 1210 &at->bam_join_where ); 1211 } 1212 1213 if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) { 1214 backsql_strfcat_x( &bsi->bsi_flt_where, 1215 bsi->bsi_op->o_tmpmemctx, 1216 "l", 1217 (ber_len_t)STRLENOF( "1=0" ), "1=0" ); 1218 return 1; 1219 } 1220 1221 switch ( f->f_choice ) { 1222 case LDAP_FILTER_EQUALITY: 1223 filter_value = &f->f_av_value; 1224 matching_rule = at->bam_ad->ad_type->sat_equality; 1225 1226 goto equality_match; 1227 1228 /* fail over into next case */ 1229 1230 case LDAP_FILTER_EXT: 1231 filter_value = &f->f_mra->ma_value; 1232 matching_rule = f->f_mr_rule; 1233 1234 equality_match:; 1235 /* always uppercase strings by now */ 1236 #ifdef BACKSQL_UPPERCASE_FILTER 1237 if ( SLAP_MR_ASSOCIATED( matching_rule, 1238 bi->sql_caseIgnoreMatch ) ) 1239 #endif /* BACKSQL_UPPERCASE_FILTER */ 1240 { 1241 casefold = 1; 1242 } 1243 1244 /* FIXME: directoryString filtering should use a similar 1245 * approach to deal with non-prettified values like 1246 * " A non prettified value ", by using a LIKE 1247 * filter with all whitespaces collapsed to a single '%' */ 1248 if ( SLAP_MR_ASSOCIATED( matching_rule, 1249 bi->sql_telephoneNumberMatch ) ) 1250 { 1251 struct berval bv; 1252 ber_len_t i; 1253 1254 /* 1255 * to check for matching telephone numbers 1256 * with intermized chars, e.g. val='1234' 1257 * use 1258 * 1259 * val LIKE '%1%2%3%4%' 1260 */ 1261 1262 bv.bv_len = 2 * filter_value->bv_len - 1; 1263 bv.bv_val = ch_malloc( bv.bv_len + 1 ); 1264 1265 bv.bv_val[ 0 ] = filter_value->bv_val[ 0 ]; 1266 for ( i = 1; i < filter_value->bv_len; i++ ) { 1267 bv.bv_val[ 2 * i - 1 ] = '%'; 1268 bv.bv_val[ 2 * i ] = filter_value->bv_val[ i ]; 1269 } 1270 bv.bv_val[ 2 * i - 1 ] = '\0'; 1271 1272 (void)backsql_process_filter_like( bsi, at, casefold, &bv ); 1273 ch_free( bv.bv_val ); 1274 1275 break; 1276 } 1277 1278 /* NOTE: this is required by objectClass inheritance 1279 * and auxiliary objectClass use in filters for slightly 1280 * more efficient candidate selection. */ 1281 /* FIXME: a bit too many specializations to deal with 1282 * very specific cases... */ 1283 if ( at->bam_ad == slap_schema.si_ad_objectClass 1284 || at->bam_ad == slap_schema.si_ad_structuralObjectClass ) 1285 { 1286 backsql_strfcat_x( &bsi->bsi_flt_where, 1287 bsi->bsi_op->o_tmpmemctx, 1288 "lbl", 1289 (ber_len_t)STRLENOF( "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ), 1290 "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */, 1291 filter_value, 1292 (ber_len_t)STRLENOF( /* (' */ "')" ), 1293 /* (' */ "')" ); 1294 break; 1295 } 1296 1297 /* 1298 * maybe we should check type of at->sel_expr here somehow, 1299 * to know whether upper_func is applicable, but for now 1300 * upper_func stuff is made for Oracle, where UPPER is 1301 * safely applicable to NUMBER etc. 1302 */ 1303 (void)backsql_process_filter_eq( bsi, at, casefold, filter_value ); 1304 break; 1305 1306 case LDAP_FILTER_GE: 1307 ordering.bv_val = ">="; 1308 1309 /* fall thru to next case */ 1310 1311 case LDAP_FILTER_LE: 1312 filter_value = &f->f_av_value; 1313 1314 /* always uppercase strings by now */ 1315 #ifdef BACKSQL_UPPERCASE_FILTER 1316 if ( at->bam_ad->ad_type->sat_ordering && 1317 SLAP_MR_ASSOCIATED( at->bam_ad->ad_type->sat_ordering, 1318 bi->sql_caseIgnoreMatch ) ) 1319 #endif /* BACKSQL_UPPERCASE_FILTER */ 1320 { 1321 casefold = 1; 1322 } 1323 1324 /* 1325 * FIXME: should we uppercase the operands? 1326 */ 1327 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { 1328 ber_len_t start; 1329 1330 backsql_strfcat_x( &bsi->bsi_flt_where, 1331 bsi->bsi_op->o_tmpmemctx, 1332 "cbbc", 1333 '(', /* ) */ 1334 &at->bam_sel_expr_u, 1335 &ordering, 1336 '\'' ); 1337 1338 start = bsi->bsi_flt_where.bb_val.bv_len; 1339 1340 backsql_strfcat_x( &bsi->bsi_flt_where, 1341 bsi->bsi_op->o_tmpmemctx, 1342 "bl", 1343 filter_value, 1344 (ber_len_t)STRLENOF( /* (' */ "')" ), 1345 /* (' */ "')" ); 1346 1347 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); 1348 1349 } else { 1350 backsql_strfcat_x( &bsi->bsi_flt_where, 1351 bsi->bsi_op->o_tmpmemctx, 1352 "cbbcbl", 1353 '(' /* ) */ , 1354 &at->bam_sel_expr, 1355 &ordering, 1356 '\'', 1357 &f->f_av_value, 1358 (ber_len_t)STRLENOF( /* (' */ "')" ), 1359 /* ( */ "')" ); 1360 } 1361 break; 1362 1363 case LDAP_FILTER_PRESENT: 1364 backsql_strfcat_x( &bsi->bsi_flt_where, 1365 bsi->bsi_op->o_tmpmemctx, 1366 "lbl", 1367 (ber_len_t)STRLENOF( "NOT (" /* ) */), 1368 "NOT (", /* ) */ 1369 &at->bam_sel_expr, 1370 (ber_len_t)STRLENOF( /* ( */ " IS NULL)" ), 1371 /* ( */ " IS NULL)" ); 1372 break; 1373 1374 case LDAP_FILTER_SUBSTRINGS: 1375 backsql_process_sub_filter( bsi, f, at ); 1376 break; 1377 1378 case LDAP_FILTER_APPROX: 1379 /* we do our best */ 1380 1381 /* 1382 * maybe we should check type of at->sel_expr here somehow, 1383 * to know whether upper_func is applicable, but for now 1384 * upper_func stuff is made for Oracle, where UPPER is 1385 * safely applicable to NUMBER etc. 1386 */ 1387 (void)backsql_process_filter_like( bsi, at, 1, &f->f_av_value ); 1388 break; 1389 1390 default: 1391 /* unhandled filter type; should not happen */ 1392 assert( 0 ); 1393 backsql_strfcat_x( &bsi->bsi_flt_where, 1394 bsi->bsi_op->o_tmpmemctx, 1395 "l", 1396 (ber_len_t)STRLENOF( "8=8" ), "8=8" ); 1397 break; 1398 1399 } 1400 1401 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter_attr(%s)\n", 1402 at->bam_ad->ad_cname.bv_val ); 1403 1404 return 1; 1405 } 1406 1407 static int 1408 backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) 1409 { 1410 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; 1411 int rc; 1412 1413 assert( query != NULL ); 1414 BER_BVZERO( query ); 1415 1416 bsi->bsi_use_subtree_shortcut = 0; 1417 1418 Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n" ); 1419 BER_BVZERO( &bsi->bsi_sel.bb_val ); 1420 BER_BVZERO( &bsi->bsi_sel.bb_val ); 1421 bsi->bsi_sel.bb_len = 0; 1422 BER_BVZERO( &bsi->bsi_from.bb_val ); 1423 bsi->bsi_from.bb_len = 0; 1424 BER_BVZERO( &bsi->bsi_join_where.bb_val ); 1425 bsi->bsi_join_where.bb_len = 0; 1426 BER_BVZERO( &bsi->bsi_flt_where.bb_val ); 1427 bsi->bsi_flt_where.bb_len = 0; 1428 1429 backsql_strfcat_x( &bsi->bsi_sel, 1430 bsi->bsi_op->o_tmpmemctx, 1431 "lbcbc", 1432 (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ), 1433 "SELECT DISTINCT ldap_entries.id,", 1434 &bsi->bsi_oc->bom_keytbl, 1435 '.', 1436 &bsi->bsi_oc->bom_keycol, 1437 ',' ); 1438 1439 if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) { 1440 backsql_strfcat_x( &bsi->bsi_sel, 1441 bsi->bsi_op->o_tmpmemctx, 1442 "blbl", 1443 &bi->sql_strcast_func, 1444 (ber_len_t)STRLENOF( "('" /* ') */ ), 1445 "('" /* ') */ , 1446 &bsi->bsi_oc->bom_oc->soc_cname, 1447 (ber_len_t)STRLENOF( /* (' */ "')" ), 1448 /* (' */ "')" ); 1449 } else { 1450 backsql_strfcat_x( &bsi->bsi_sel, 1451 bsi->bsi_op->o_tmpmemctx, 1452 "cbc", 1453 '\'', 1454 &bsi->bsi_oc->bom_oc->soc_cname, 1455 '\'' ); 1456 } 1457 1458 backsql_strfcat_x( &bsi->bsi_sel, 1459 bsi->bsi_op->o_tmpmemctx, 1460 "b", 1461 &bi->sql_dn_oc_aliasing ); 1462 backsql_strfcat_x( &bsi->bsi_from, 1463 bsi->bsi_op->o_tmpmemctx, 1464 "lb", 1465 (ber_len_t)STRLENOF( " FROM ldap_entries," ), 1466 " FROM ldap_entries,", 1467 &bsi->bsi_oc->bom_keytbl ); 1468 1469 backsql_strfcat_x( &bsi->bsi_join_where, 1470 bsi->bsi_op->o_tmpmemctx, 1471 "lbcbl", 1472 (ber_len_t)STRLENOF( " WHERE " ), " WHERE ", 1473 &bsi->bsi_oc->bom_keytbl, 1474 '.', 1475 &bsi->bsi_oc->bom_keycol, 1476 (ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ), 1477 "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ); 1478 1479 switch ( bsi->bsi_scope ) { 1480 case LDAP_SCOPE_BASE: 1481 if ( BACKSQL_CANUPPERCASE( bi ) ) { 1482 backsql_strfcat_x( &bsi->bsi_join_where, 1483 bsi->bsi_op->o_tmpmemctx, 1484 "bl", 1485 &bi->sql_upper_func, 1486 (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ), 1487 "(ldap_entries.dn)=?" ); 1488 } else { 1489 backsql_strfcat_x( &bsi->bsi_join_where, 1490 bsi->bsi_op->o_tmpmemctx, 1491 "l", 1492 (ber_len_t)STRLENOF( "ldap_entries.dn=?" ), 1493 "ldap_entries.dn=?" ); 1494 } 1495 break; 1496 1497 case BACKSQL_SCOPE_BASE_LIKE: 1498 if ( BACKSQL_CANUPPERCASE( bi ) ) { 1499 backsql_strfcat_x( &bsi->bsi_join_where, 1500 bsi->bsi_op->o_tmpmemctx, 1501 "bl", 1502 &bi->sql_upper_func, 1503 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ), 1504 "(ldap_entries.dn) LIKE ?" ); 1505 } else { 1506 backsql_strfcat_x( &bsi->bsi_join_where, 1507 bsi->bsi_op->o_tmpmemctx, 1508 "l", 1509 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ), 1510 "ldap_entries.dn LIKE ?" ); 1511 } 1512 break; 1513 1514 case LDAP_SCOPE_ONELEVEL: 1515 backsql_strfcat_x( &bsi->bsi_join_where, 1516 bsi->bsi_op->o_tmpmemctx, 1517 "l", 1518 (ber_len_t)STRLENOF( "ldap_entries.parent=?" ), 1519 "ldap_entries.parent=?" ); 1520 break; 1521 1522 case LDAP_SCOPE_SUBORDINATE: 1523 case LDAP_SCOPE_SUBTREE: 1524 if ( BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ) { 1525 int i; 1526 BackendDB *bd = bsi->bsi_op->o_bd; 1527 1528 assert( bd->be_nsuffix != NULL ); 1529 1530 for ( i = 0; !BER_BVISNULL( &bd->be_nsuffix[ i ] ); i++ ) 1531 { 1532 if ( dn_match( &bd->be_nsuffix[ i ], 1533 bsi->bsi_base_ndn ) ) 1534 { 1535 /* pass this to the candidate selection 1536 * routine so that the DN is not bound 1537 * to the select statement */ 1538 bsi->bsi_use_subtree_shortcut = 1; 1539 break; 1540 } 1541 } 1542 } 1543 1544 if ( bsi->bsi_use_subtree_shortcut ) { 1545 /* Skip the base DN filter, as every entry will match it */ 1546 backsql_strfcat_x( &bsi->bsi_join_where, 1547 bsi->bsi_op->o_tmpmemctx, 1548 "l", 1549 (ber_len_t)STRLENOF( "9=9"), "9=9"); 1550 1551 } else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) { 1552 /* This should always be true... */ 1553 backsql_strfcat_x( &bsi->bsi_join_where, 1554 bsi->bsi_op->o_tmpmemctx, 1555 "b", 1556 &bi->sql_subtree_cond ); 1557 1558 } else if ( BACKSQL_CANUPPERCASE( bi ) ) { 1559 backsql_strfcat_x( &bsi->bsi_join_where, 1560 bsi->bsi_op->o_tmpmemctx, 1561 "bl", 1562 &bi->sql_upper_func, 1563 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ), 1564 "(ldap_entries.dn) LIKE ?" ); 1565 1566 } else { 1567 backsql_strfcat_x( &bsi->bsi_join_where, 1568 bsi->bsi_op->o_tmpmemctx, 1569 "l", 1570 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ), 1571 "ldap_entries.dn LIKE ?" ); 1572 } 1573 1574 break; 1575 1576 default: 1577 assert( 0 ); 1578 } 1579 1580 #ifndef BACKSQL_ARBITRARY_KEY 1581 /* If paged results are in effect, ignore low ldap_entries.id numbers */ 1582 if ( get_pagedresults(bsi->bsi_op) > SLAP_CONTROL_IGNORED ) { 1583 unsigned long lowid = 0; 1584 1585 /* Pick up the previous ldap_entries.id if the previous page ended in this objectClass */ 1586 if ( bsi->bsi_oc->bom_id == PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ) ) 1587 { 1588 lowid = PAGECOOKIE_TO_SQL_ID( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ); 1589 } 1590 1591 if ( lowid ) { 1592 char lowidstring[48]; 1593 int lowidlen; 1594 1595 lowidlen = snprintf( lowidstring, sizeof( lowidstring ), 1596 " AND ldap_entries.id>%lu", lowid ); 1597 backsql_strfcat_x( &bsi->bsi_join_where, 1598 bsi->bsi_op->o_tmpmemctx, 1599 "l", 1600 (ber_len_t)lowidlen, 1601 lowidstring ); 1602 } 1603 } 1604 #endif /* ! BACKSQL_ARBITRARY_KEY */ 1605 1606 rc = backsql_process_filter( bsi, bsi->bsi_filter ); 1607 if ( rc > 0 ) { 1608 struct berbuf bb = BB_NULL; 1609 1610 backsql_strfcat_x( &bb, 1611 bsi->bsi_op->o_tmpmemctx, 1612 "bbblb", 1613 &bsi->bsi_sel.bb_val, 1614 &bsi->bsi_from.bb_val, 1615 &bsi->bsi_join_where.bb_val, 1616 (ber_len_t)STRLENOF( " AND " ), " AND ", 1617 &bsi->bsi_flt_where.bb_val ); 1618 1619 *query = bb.bb_val; 1620 1621 } else if ( rc < 0 ) { 1622 /* 1623 * Indicates that there's no possible way the filter matches 1624 * anything. No need to issue the query 1625 */ 1626 free( query->bv_val ); 1627 BER_BVZERO( query ); 1628 } 1629 1630 bsi->bsi_op->o_tmpfree( bsi->bsi_sel.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); 1631 BER_BVZERO( &bsi->bsi_sel.bb_val ); 1632 bsi->bsi_sel.bb_len = 0; 1633 bsi->bsi_op->o_tmpfree( bsi->bsi_from.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); 1634 BER_BVZERO( &bsi->bsi_from.bb_val ); 1635 bsi->bsi_from.bb_len = 0; 1636 bsi->bsi_op->o_tmpfree( bsi->bsi_join_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); 1637 BER_BVZERO( &bsi->bsi_join_where.bb_val ); 1638 bsi->bsi_join_where.bb_len = 0; 1639 bsi->bsi_op->o_tmpfree( bsi->bsi_flt_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); 1640 BER_BVZERO( &bsi->bsi_flt_where.bb_val ); 1641 bsi->bsi_flt_where.bb_len = 0; 1642 1643 Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n", 1644 query->bv_val ? query->bv_val : "NULL" ); 1645 1646 return ( rc <= 0 ? 1 : 0 ); 1647 } 1648 1649 static int 1650 backsql_oc_get_candidates( void *v_oc, void *v_bsi ) 1651 { 1652 backsql_oc_map_rec *oc = v_oc; 1653 backsql_srch_info *bsi = v_bsi; 1654 Operation *op = bsi->bsi_op; 1655 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; 1656 struct berval query; 1657 SQLHSTMT sth = SQL_NULL_HSTMT; 1658 RETCODE rc; 1659 int res; 1660 BACKSQL_ROW_NTS row; 1661 int i; 1662 int j; 1663 int n_candidates = bsi->bsi_n_candidates; 1664 1665 /* 1666 * + 1 because we need room for '%'; 1667 * + 1 because we need room for ',' for LDAP_SCOPE_SUBORDINATE; 1668 * this makes a subtree 1669 * search for a DN BACKSQL_MAX_DN_LEN long legal 1670 * if it returns that DN only 1671 */ 1672 char tmp_base_ndn[ BACKSQL_MAX_DN_LEN + 1 + 1 ]; 1673 1674 bsi->bsi_status = LDAP_SUCCESS; 1675 1676 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc=\"%s\"\n", 1677 BACKSQL_OC_NAME( oc ) ); 1678 1679 /* check for abandon */ 1680 if ( op->o_abandon ) { 1681 bsi->bsi_status = SLAPD_ABANDON; 1682 return BACKSQL_AVL_STOP; 1683 } 1684 1685 #ifndef BACKSQL_ARBITRARY_KEY 1686 /* If paged results have already completed this objectClass, skip it */ 1687 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { 1688 if ( oc->bom_id < PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)op->o_pagedresults_state)->ps_cookie ) ) 1689 { 1690 return BACKSQL_AVL_CONTINUE; 1691 } 1692 } 1693 #endif /* ! BACKSQL_ARBITRARY_KEY */ 1694 1695 if ( bsi->bsi_n_candidates == -1 ) { 1696 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1697 "unchecked limit has been overcome\n" ); 1698 /* should never get here */ 1699 assert( 0 ); 1700 bsi->bsi_status = LDAP_ADMINLIMIT_EXCEEDED; 1701 return BACKSQL_AVL_STOP; 1702 } 1703 1704 bsi->bsi_oc = oc; 1705 res = backsql_srch_query( bsi, &query ); 1706 if ( res ) { 1707 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1708 "error while constructing query for objectclass \"%s\"\n", 1709 oc->bom_oc->soc_cname.bv_val ); 1710 /* 1711 * FIXME: need to separate errors from legally 1712 * impossible filters 1713 */ 1714 switch ( bsi->bsi_status ) { 1715 case LDAP_SUCCESS: 1716 case LDAP_UNDEFINED_TYPE: 1717 case LDAP_NO_SUCH_OBJECT: 1718 /* we are conservative... */ 1719 default: 1720 bsi->bsi_status = LDAP_SUCCESS; 1721 /* try next */ 1722 return BACKSQL_AVL_CONTINUE; 1723 1724 case LDAP_ADMINLIMIT_EXCEEDED: 1725 case LDAP_OTHER: 1726 /* don't try any more */ 1727 return BACKSQL_AVL_STOP; 1728 } 1729 } 1730 1731 if ( BER_BVISNULL( &query ) ) { 1732 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1733 "could not construct query for objectclass \"%s\"\n", 1734 oc->bom_oc->soc_cname.bv_val ); 1735 bsi->bsi_status = LDAP_SUCCESS; 1736 return BACKSQL_AVL_CONTINUE; 1737 } 1738 1739 Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n", 1740 query.bv_val ); 1741 1742 rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 ); 1743 bsi->bsi_op->o_tmpfree( query.bv_val, bsi->bsi_op->o_tmpmemctx ); 1744 BER_BVZERO( &query ); 1745 if ( rc != SQL_SUCCESS ) { 1746 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1747 "error preparing query\n" ); 1748 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); 1749 bsi->bsi_status = LDAP_OTHER; 1750 return BACKSQL_AVL_CONTINUE; 1751 } 1752 1753 Debug( LDAP_DEBUG_TRACE, "id: '" BACKSQL_IDNUMFMT "'\n", 1754 bsi->bsi_oc->bom_id ); 1755 1756 rc = backsql_BindParamNumID( sth, 1, SQL_PARAM_INPUT, 1757 &bsi->bsi_oc->bom_id ); 1758 if ( rc != SQL_SUCCESS ) { 1759 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1760 "error binding objectclass id parameter\n" ); 1761 bsi->bsi_status = LDAP_OTHER; 1762 return BACKSQL_AVL_CONTINUE; 1763 } 1764 1765 switch ( bsi->bsi_scope ) { 1766 case LDAP_SCOPE_BASE: 1767 case BACKSQL_SCOPE_BASE_LIKE: 1768 /* 1769 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN; 1770 * however this should be handled earlier 1771 */ 1772 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) { 1773 bsi->bsi_status = LDAP_OTHER; 1774 return BACKSQL_AVL_CONTINUE; 1775 } 1776 1777 AC_MEMCPY( tmp_base_ndn, bsi->bsi_base_ndn->bv_val, 1778 bsi->bsi_base_ndn->bv_len + 1 ); 1779 1780 /* uppercase DN only if the stored DN can be uppercased 1781 * for comparison */ 1782 if ( BACKSQL_CANUPPERCASE( bi ) ) { 1783 ldap_pvt_str2upper( tmp_base_ndn ); 1784 } 1785 1786 Debug( LDAP_DEBUG_TRACE, "(base)dn: \"%s\"\n", 1787 tmp_base_ndn ); 1788 1789 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT, 1790 tmp_base_ndn, BACKSQL_MAX_DN_LEN ); 1791 if ( rc != SQL_SUCCESS ) { 1792 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1793 "error binding base_ndn parameter\n" ); 1794 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, 1795 sth, rc ); 1796 bsi->bsi_status = LDAP_OTHER; 1797 return BACKSQL_AVL_CONTINUE; 1798 } 1799 break; 1800 1801 case LDAP_SCOPE_SUBORDINATE: 1802 case LDAP_SCOPE_SUBTREE: 1803 { 1804 /* if short-cutting the search base, 1805 * don't bind any parameter */ 1806 if ( bsi->bsi_use_subtree_shortcut ) { 1807 break; 1808 } 1809 1810 /* 1811 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN; 1812 * however this should be handled earlier 1813 */ 1814 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) { 1815 bsi->bsi_status = LDAP_OTHER; 1816 return BACKSQL_AVL_CONTINUE; 1817 } 1818 1819 /* 1820 * Sets the parameters for the SQL built earlier 1821 * NOTE that all the databases could actually use 1822 * the TimesTen version, which would be cleaner 1823 * and would also eliminate the need for the 1824 * subtree_cond line in the configuration file. 1825 * For now, I'm leaving it the way it is, 1826 * so non-TimesTen databases use the original code. 1827 * But at some point this should get cleaned up. 1828 * 1829 * If "dn" is being used, do a suffix search. 1830 * If "dn_ru" is being used, do a prefix search. 1831 */ 1832 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) { 1833 tmp_base_ndn[ 0 ] = '\0'; 1834 1835 for ( i = 0, j = bsi->bsi_base_ndn->bv_len - 1; 1836 j >= 0; i++, j--) { 1837 tmp_base_ndn[ i ] = bsi->bsi_base_ndn->bv_val[ j ]; 1838 } 1839 1840 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) { 1841 tmp_base_ndn[ i++ ] = ','; 1842 } 1843 1844 tmp_base_ndn[ i ] = '%'; 1845 tmp_base_ndn[ i + 1 ] = '\0'; 1846 1847 } else { 1848 i = 0; 1849 1850 tmp_base_ndn[ i++ ] = '%'; 1851 1852 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) { 1853 tmp_base_ndn[ i++ ] = ','; 1854 } 1855 1856 AC_MEMCPY( &tmp_base_ndn[ i ], bsi->bsi_base_ndn->bv_val, 1857 bsi->bsi_base_ndn->bv_len + 1 ); 1858 } 1859 1860 /* uppercase DN only if the stored DN can be uppercased 1861 * for comparison */ 1862 if ( BACKSQL_CANUPPERCASE( bi ) ) { 1863 ldap_pvt_str2upper( tmp_base_ndn ); 1864 } 1865 1866 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) { 1867 Debug( LDAP_DEBUG_TRACE, "(children)dn: \"%s\"\n", 1868 tmp_base_ndn ); 1869 } else { 1870 Debug( LDAP_DEBUG_TRACE, "(sub)dn: \"%s\"\n", 1871 tmp_base_ndn ); 1872 } 1873 1874 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT, 1875 tmp_base_ndn, BACKSQL_MAX_DN_LEN ); 1876 if ( rc != SQL_SUCCESS ) { 1877 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1878 "error binding base_ndn parameter (2)\n" ); 1879 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, 1880 sth, rc ); 1881 bsi->bsi_status = LDAP_OTHER; 1882 return BACKSQL_AVL_CONTINUE; 1883 } 1884 break; 1885 } 1886 1887 case LDAP_SCOPE_ONELEVEL: 1888 assert( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ); 1889 1890 Debug( LDAP_DEBUG_TRACE, "(one)id=" BACKSQL_IDFMT "\n", 1891 BACKSQL_IDARG(bsi->bsi_base_id.eid_id) ); 1892 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT, 1893 &bsi->bsi_base_id.eid_id ); 1894 if ( rc != SQL_SUCCESS ) { 1895 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1896 "error binding base id parameter\n" ); 1897 bsi->bsi_status = LDAP_OTHER; 1898 return BACKSQL_AVL_CONTINUE; 1899 } 1900 break; 1901 } 1902 1903 rc = SQLExecute( sth ); 1904 if ( !BACKSQL_SUCCESS( rc ) ) { 1905 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1906 "error executing query\n" ); 1907 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); 1908 SQLFreeStmt( sth, SQL_DROP ); 1909 bsi->bsi_status = LDAP_OTHER; 1910 return BACKSQL_AVL_CONTINUE; 1911 } 1912 1913 backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx ); 1914 rc = SQLFetch( sth ); 1915 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) { 1916 struct berval dn, pdn, ndn; 1917 backsql_entryID *c_id = NULL; 1918 int ret; 1919 1920 ber_str2bv( row.cols[ 3 ], 0, 0, &dn ); 1921 1922 if ( backsql_api_odbc2dn( bsi->bsi_op, bsi->bsi_rs, &dn ) ) { 1923 continue; 1924 } 1925 1926 ret = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx ); 1927 if ( dn.bv_val != row.cols[ 3 ] ) { 1928 free( dn.bv_val ); 1929 } 1930 1931 if ( ret != LDAP_SUCCESS ) { 1932 continue; 1933 } 1934 1935 if ( bi->sql_baseObject && dn_match( &ndn, &bi->sql_baseObject->e_nname ) ) { 1936 goto cleanup; 1937 } 1938 1939 c_id = (backsql_entryID *)op->o_tmpcalloc( 1, 1940 sizeof( backsql_entryID ), op->o_tmpmemctx ); 1941 #ifdef BACKSQL_ARBITRARY_KEY 1942 ber_str2bv_x( row.cols[ 0 ], 0, 1, &c_id->eid_id, 1943 op->o_tmpmemctx ); 1944 ber_str2bv_x( row.cols[ 1 ], 0, 1, &c_id->eid_keyval, 1945 op->o_tmpmemctx ); 1946 #else /* ! BACKSQL_ARBITRARY_KEY */ 1947 if ( BACKSQL_STR2ID( &c_id->eid_id, row.cols[ 0 ], 0 ) != 0 ) { 1948 goto cleanup; 1949 } 1950 if ( BACKSQL_STR2ID( &c_id->eid_keyval, row.cols[ 1 ], 0 ) != 0 ) { 1951 goto cleanup; 1952 } 1953 #endif /* ! BACKSQL_ARBITRARY_KEY */ 1954 c_id->eid_oc = bsi->bsi_oc; 1955 c_id->eid_oc_id = bsi->bsi_oc->bom_id; 1956 1957 c_id->eid_dn = pdn; 1958 c_id->eid_ndn = ndn; 1959 1960 /* append at end of list ... */ 1961 c_id->eid_next = NULL; 1962 *bsi->bsi_id_listtail = c_id; 1963 bsi->bsi_id_listtail = &c_id->eid_next; 1964 1965 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1966 "added entry id=" BACKSQL_IDFMT " keyval=" BACKSQL_IDFMT " dn=\"%s\"\n", 1967 BACKSQL_IDARG(c_id->eid_id), 1968 BACKSQL_IDARG(c_id->eid_keyval), 1969 row.cols[ 3 ] ); 1970 1971 /* count candidates, for unchecked limit */ 1972 bsi->bsi_n_candidates--; 1973 if ( bsi->bsi_n_candidates == -1 ) { 1974 break; 1975 } 1976 continue; 1977 1978 cleanup:; 1979 if ( !BER_BVISNULL( &pdn ) ) { 1980 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx ); 1981 } 1982 if ( !BER_BVISNULL( &ndn ) ) { 1983 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); 1984 } 1985 if ( c_id != NULL ) { 1986 ch_free( c_id ); 1987 } 1988 } 1989 backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx ); 1990 SQLFreeStmt( sth, SQL_DROP ); 1991 1992 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates(): %d\n", 1993 n_candidates - bsi->bsi_n_candidates ); 1994 1995 return ( bsi->bsi_n_candidates == -1 ? BACKSQL_AVL_STOP : BACKSQL_AVL_CONTINUE ); 1996 } 1997 1998 int 1999 backsql_search( Operation *op, SlapReply *rs ) 2000 { 2001 backsql_info *bi = (backsql_info *)op->o_bd->be_private; 2002 SQLHDBC dbh = SQL_NULL_HDBC; 2003 int sres; 2004 Entry user_entry = { 0 }, 2005 base_entry = { 0 }; 2006 int manageDSAit = get_manageDSAit( op ); 2007 time_t stoptime = 0; 2008 backsql_srch_info bsi = { 0 }; 2009 backsql_entryID *eid = NULL; 2010 struct berval nbase = BER_BVNULL; 2011 #ifndef BACKSQL_ARBITRARY_KEY 2012 ID lastid = 0; 2013 #endif /* ! BACKSQL_ARBITRARY_KEY */ 2014 2015 Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): " 2016 "base=\"%s\", filter=\"%s\", scope=%d,", 2017 op->o_req_ndn.bv_val, 2018 op->ors_filterstr.bv_val, 2019 op->ors_scope ); 2020 Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, " 2021 "attributes to load: %s\n", 2022 op->ors_deref, 2023 op->ors_attrsonly, 2024 op->ors_attrs == NULL ? "all" : "custom list" ); 2025 2026 if ( op->o_req_ndn.bv_len > BACKSQL_MAX_DN_LEN ) { 2027 Debug( LDAP_DEBUG_TRACE, "backsql_search(): " 2028 "search base length (%ld) exceeds max length (%d)\n", 2029 op->o_req_ndn.bv_len, BACKSQL_MAX_DN_LEN ); 2030 /* 2031 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate 2032 * since it is impossible that such a long DN exists 2033 * in the backend 2034 */ 2035 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 2036 send_ldap_result( op, rs ); 2037 return 1; 2038 } 2039 2040 sres = backsql_get_db_conn( op, &dbh ); 2041 if ( sres != LDAP_SUCCESS ) { 2042 Debug( LDAP_DEBUG_TRACE, "backsql_search(): " 2043 "could not get connection handle - exiting\n" ); 2044 rs->sr_err = sres; 2045 rs->sr_text = sres == LDAP_OTHER ? "SQL-backend error" : NULL; 2046 send_ldap_result( op, rs ); 2047 return 1; 2048 } 2049 2050 /* compute it anyway; root does not use it */ 2051 stoptime = op->o_time + op->ors_tlimit; 2052 2053 /* init search */ 2054 bsi.bsi_e = &base_entry; 2055 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, 2056 op->ors_scope, 2057 stoptime, op->ors_filter, 2058 dbh, op, rs, op->ors_attrs, 2059 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); 2060 switch ( rs->sr_err ) { 2061 case LDAP_SUCCESS: 2062 break; 2063 2064 case LDAP_REFERRAL: 2065 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && 2066 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) ) 2067 { 2068 rs->sr_err = LDAP_SUCCESS; 2069 rs->sr_text = NULL; 2070 rs->sr_matched = NULL; 2071 if ( rs->sr_ref ) { 2072 ber_bvarray_free( rs->sr_ref ); 2073 rs->sr_ref = NULL; 2074 } 2075 break; 2076 } 2077 2078 /* an entry was created; free it */ 2079 entry_clean( bsi.bsi_e ); 2080 2081 /* fall thru */ 2082 2083 default: 2084 if ( !BER_BVISNULL( &base_entry.e_nname ) 2085 && !access_allowed( op, &base_entry, 2086 slap_schema.si_ad_entry, NULL, 2087 ACL_DISCLOSE, NULL ) ) 2088 { 2089 rs->sr_err = LDAP_NO_SUCH_OBJECT; 2090 if ( rs->sr_ref ) { 2091 ber_bvarray_free( rs->sr_ref ); 2092 rs->sr_ref = NULL; 2093 } 2094 rs->sr_matched = NULL; 2095 rs->sr_text = NULL; 2096 } 2097 2098 send_ldap_result( op, rs ); 2099 2100 if ( rs->sr_ref ) { 2101 ber_bvarray_free( rs->sr_ref ); 2102 rs->sr_ref = NULL; 2103 } 2104 2105 if ( !BER_BVISNULL( &base_entry.e_nname ) ) { 2106 entry_clean( &base_entry ); 2107 } 2108 2109 goto done; 2110 } 2111 /* NOTE: __NEW__ "search" access is required 2112 * on searchBase object */ 2113 { 2114 slap_mask_t mask; 2115 2116 if ( get_assert( op ) && 2117 ( test_filter( op, &base_entry, get_assertion( op ) ) 2118 != LDAP_COMPARE_TRUE ) ) 2119 { 2120 rs->sr_err = LDAP_ASSERTION_FAILED; 2121 2122 } 2123 if ( ! access_allowed_mask( op, &base_entry, 2124 slap_schema.si_ad_entry, 2125 NULL, ACL_SEARCH, NULL, &mask ) ) 2126 { 2127 if ( rs->sr_err == LDAP_SUCCESS ) { 2128 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 2129 } 2130 } 2131 2132 if ( rs->sr_err != LDAP_SUCCESS ) { 2133 if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) { 2134 rs->sr_err = LDAP_NO_SUCH_OBJECT; 2135 rs->sr_text = NULL; 2136 } 2137 send_ldap_result( op, rs ); 2138 goto done; 2139 } 2140 } 2141 2142 bsi.bsi_e = NULL; 2143 2144 bsi.bsi_n_candidates = 2145 ( op->ors_limit == NULL /* isroot == TRUE */ ? -2 : 2146 ( op->ors_limit->lms_s_unchecked == -1 ? -2 : 2147 ( op->ors_limit->lms_s_unchecked ) ) ); 2148 2149 #ifndef BACKSQL_ARBITRARY_KEY 2150 /* If paged results are in effect, check the paging cookie */ 2151 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { 2152 rs->sr_err = parse_paged_cookie( op, rs ); 2153 if ( rs->sr_err != LDAP_SUCCESS ) { 2154 send_ldap_result( op, rs ); 2155 goto done; 2156 } 2157 } 2158 #endif /* ! BACKSQL_ARBITRARY_KEY */ 2159 2160 switch ( bsi.bsi_scope ) { 2161 case LDAP_SCOPE_BASE: 2162 case BACKSQL_SCOPE_BASE_LIKE: 2163 /* 2164 * probably already found... 2165 */ 2166 bsi.bsi_id_list = &bsi.bsi_base_id; 2167 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next; 2168 break; 2169 2170 case LDAP_SCOPE_SUBTREE: 2171 /* 2172 * if baseObject is defined, and if it is the root 2173 * of the search, add it to the candidate list 2174 */ 2175 if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &bsi.bsi_base_id.eid_id ) ) 2176 { 2177 bsi.bsi_id_list = &bsi.bsi_base_id; 2178 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next; 2179 } 2180 2181 /* FALLTHRU */ 2182 default: 2183 2184 /* 2185 * for each objectclass we try to construct query which gets IDs 2186 * of entries matching LDAP query filter and scope (or at least 2187 * candidates), and get the IDs. Do this in ID order for paging. 2188 */ 2189 ldap_avl_apply( bi->sql_oc_by_id, backsql_oc_get_candidates, 2190 &bsi, BACKSQL_AVL_STOP, AVL_INORDER ); 2191 2192 /* check for abandon */ 2193 if ( op->o_abandon ) { 2194 eid = bsi.bsi_id_list; 2195 rs->sr_err = SLAPD_ABANDON; 2196 goto send_results; 2197 } 2198 } 2199 2200 if ( op->ors_limit != NULL /* isroot == FALSE */ 2201 && op->ors_limit->lms_s_unchecked != -1 2202 && bsi.bsi_n_candidates == -1 ) 2203 { 2204 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 2205 send_ldap_result( op, rs ); 2206 goto done; 2207 } 2208 2209 /* 2210 * now we load candidate entries (only those attributes 2211 * mentioned in attrs and filter), test it against full filter 2212 * and then send to client; don't free entry_id if baseObject... 2213 */ 2214 for ( eid = bsi.bsi_id_list; 2215 eid != NULL; 2216 eid = backsql_free_entryID( 2217 eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) ) 2218 { 2219 int rc; 2220 Attribute *a_hasSubordinate = NULL, 2221 *a_entryUUID = NULL, 2222 *a_entryCSN = NULL, 2223 **ap = NULL; 2224 Entry *e = NULL; 2225 2226 /* check for abandon */ 2227 if ( op->o_abandon ) { 2228 rs->sr_err = SLAPD_ABANDON; 2229 goto send_results; 2230 } 2231 2232 /* check time limit */ 2233 if ( op->ors_tlimit != SLAP_NO_LIMIT 2234 && slap_get_time() > stoptime ) 2235 { 2236 rs->sr_err = LDAP_TIMELIMIT_EXCEEDED; 2237 rs->sr_ctrls = NULL; 2238 rs->sr_ref = rs->sr_v2ref; 2239 goto send_results; 2240 } 2241 2242 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data " 2243 "for entry id=" BACKSQL_IDFMT " oc_id=" BACKSQL_IDNUMFMT ", keyval=" BACKSQL_IDFMT "\n", 2244 BACKSQL_IDARG(eid->eid_id), 2245 eid->eid_oc_id, 2246 BACKSQL_IDARG(eid->eid_keyval) ); 2247 2248 /* check scope */ 2249 switch ( op->ors_scope ) { 2250 case LDAP_SCOPE_BASE: 2251 case BACKSQL_SCOPE_BASE_LIKE: 2252 if ( !dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) { 2253 goto next_entry2; 2254 } 2255 break; 2256 2257 case LDAP_SCOPE_ONE: 2258 { 2259 struct berval rdn = eid->eid_ndn; 2260 2261 rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," ); 2262 if ( !dnIsOneLevelRDN( &rdn ) ) { 2263 goto next_entry2; 2264 } 2265 /* fall thru */ 2266 } 2267 2268 case LDAP_SCOPE_SUBORDINATE: 2269 /* discard the baseObject entry */ 2270 if ( dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) { 2271 goto next_entry2; 2272 } 2273 /* FALLTHRU */ 2274 case LDAP_SCOPE_SUBTREE: 2275 /* FIXME: this should never fail... */ 2276 if ( !dnIsSuffix( &eid->eid_ndn, &op->o_req_ndn ) ) { 2277 goto next_entry2; 2278 } 2279 break; 2280 } 2281 2282 if ( BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) { 2283 /* don't recollect baseObject... */ 2284 e = bi->sql_baseObject; 2285 2286 } else if ( eid == &bsi.bsi_base_id ) { 2287 /* don't recollect searchBase object... */ 2288 e = &base_entry; 2289 2290 } else { 2291 bsi.bsi_e = &user_entry; 2292 rc = backsql_id2entry( &bsi, eid ); 2293 if ( rc != LDAP_SUCCESS ) { 2294 Debug( LDAP_DEBUG_TRACE, "backsql_search(): " 2295 "error %d in backsql_id2entry() " 2296 "- skipping\n", rc ); 2297 continue; 2298 } 2299 e = &user_entry; 2300 } 2301 2302 if ( !manageDSAit && 2303 op->ors_scope != LDAP_SCOPE_BASE && 2304 op->ors_scope != BACKSQL_SCOPE_BASE_LIKE && 2305 is_entry_referral( e ) ) 2306 { 2307 BerVarray refs; 2308 2309 refs = get_entry_referrals( op, e ); 2310 if ( !refs ) { 2311 backsql_srch_info bsi2 = { 0 }; 2312 Entry user_entry2 = { 0 }; 2313 2314 /* retry with the full entry... */ 2315 bsi2.bsi_e = &user_entry2; 2316 rc = backsql_init_search( &bsi2, 2317 &e->e_nname, 2318 LDAP_SCOPE_BASE, 2319 (time_t)(-1), NULL, 2320 dbh, op, rs, NULL, 2321 BACKSQL_ISF_GET_ENTRY ); 2322 if ( rc == LDAP_SUCCESS ) { 2323 if ( is_entry_referral( &user_entry2 ) ) 2324 { 2325 refs = get_entry_referrals( op, 2326 &user_entry2 ); 2327 } else { 2328 rs->sr_err = LDAP_OTHER; 2329 } 2330 backsql_entry_clean( op, &user_entry2 ); 2331 } 2332 if ( bsi2.bsi_attrs != NULL ) { 2333 op->o_tmpfree( bsi2.bsi_attrs, 2334 op->o_tmpmemctx ); 2335 } 2336 } 2337 2338 if ( refs ) { 2339 rs->sr_ref = referral_rewrite( refs, 2340 &e->e_name, 2341 &op->o_req_dn, 2342 op->ors_scope ); 2343 ber_bvarray_free( refs ); 2344 } 2345 2346 if ( rs->sr_ref ) { 2347 rs->sr_err = LDAP_REFERRAL; 2348 2349 } else { 2350 rs->sr_text = "bad referral object"; 2351 } 2352 2353 rs->sr_entry = e; 2354 rs->sr_matched = user_entry.e_name.bv_val; 2355 send_search_reference( op, rs ); 2356 2357 ber_bvarray_free( rs->sr_ref ); 2358 rs->sr_ref = NULL; 2359 rs->sr_matched = NULL; 2360 rs->sr_entry = NULL; 2361 if ( rs->sr_err == LDAP_REFERRAL ) { 2362 rs->sr_err = LDAP_SUCCESS; 2363 } 2364 2365 goto next_entry; 2366 } 2367 2368 /* 2369 * We use this flag since we need to parse the filter 2370 * anyway; we should have used the frontend API function 2371 * filter_has_subordinates() 2372 */ 2373 if ( bsi.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) { 2374 rc = backsql_has_children( op, dbh, &e->e_nname ); 2375 2376 switch ( rc ) { 2377 case LDAP_COMPARE_TRUE: 2378 case LDAP_COMPARE_FALSE: 2379 a_hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE ); 2380 if ( a_hasSubordinate != NULL ) { 2381 for ( ap = &user_entry.e_attrs; 2382 *ap; 2383 ap = &(*ap)->a_next ); 2384 2385 *ap = a_hasSubordinate; 2386 } 2387 rc = 0; 2388 break; 2389 2390 default: 2391 Debug(LDAP_DEBUG_TRACE, 2392 "backsql_search(): " 2393 "has_children failed( %d)\n", 2394 rc ); 2395 rc = 1; 2396 goto next_entry; 2397 } 2398 } 2399 2400 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYUUID ) { 2401 a_entryUUID = backsql_operational_entryUUID( bi, eid ); 2402 if ( a_entryUUID != NULL ) { 2403 if ( ap == NULL ) { 2404 ap = &user_entry.e_attrs; 2405 } 2406 2407 for ( ; *ap; ap = &(*ap)->a_next ); 2408 2409 *ap = a_entryUUID; 2410 } 2411 } 2412 2413 #ifdef BACKSQL_SYNCPROV 2414 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYCSN ) { 2415 a_entryCSN = backsql_operational_entryCSN( op ); 2416 if ( a_entryCSN != NULL ) { 2417 if ( ap == NULL ) { 2418 ap = &user_entry.e_attrs; 2419 } 2420 2421 for ( ; *ap; ap = &(*ap)->a_next ); 2422 2423 *ap = a_entryCSN; 2424 } 2425 } 2426 #endif /* BACKSQL_SYNCPROV */ 2427 2428 if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) 2429 { 2430 #ifndef BACKSQL_ARBITRARY_KEY 2431 /* If paged results are in effect, see if the page limit was exceeded */ 2432 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { 2433 if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) 2434 { 2435 e = NULL; 2436 send_paged_response( op, rs, &lastid ); 2437 goto done; 2438 } 2439 lastid = SQL_TO_PAGECOOKIE( eid->eid_id, eid->eid_oc_id ); 2440 } 2441 #endif /* ! BACKSQL_ARBITRARY_KEY */ 2442 rs->sr_attrs = op->ors_attrs; 2443 rs->sr_operational_attrs = NULL; 2444 rs->sr_entry = e; 2445 e->e_private = (void *)eid; 2446 rs->sr_flags = ( e == &user_entry ) ? REP_ENTRY_MODIFIABLE : 0; 2447 /* FIXME: need the whole entry (ITS#3480) */ 2448 rs->sr_err = send_search_entry( op, rs ); 2449 e->e_private = NULL; 2450 rs->sr_entry = NULL; 2451 rs->sr_attrs = NULL; 2452 rs->sr_operational_attrs = NULL; 2453 2454 switch ( rs->sr_err ) { 2455 case LDAP_UNAVAILABLE: 2456 /* 2457 * FIXME: send_search_entry failed; 2458 * better stop 2459 */ 2460 Debug( LDAP_DEBUG_TRACE, "backsql_search(): " 2461 "connection lost\n" ); 2462 goto end_of_search; 2463 2464 case LDAP_SIZELIMIT_EXCEEDED: 2465 case LDAP_BUSY: 2466 goto send_results; 2467 } 2468 } 2469 2470 next_entry:; 2471 if ( e == &user_entry ) { 2472 backsql_entry_clean( op, &user_entry ); 2473 } 2474 2475 next_entry2:; 2476 } 2477 2478 end_of_search:; 2479 if ( rs->sr_nentries > 0 ) { 2480 rs->sr_ref = rs->sr_v2ref; 2481 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS 2482 : LDAP_REFERRAL; 2483 2484 } else { 2485 rs->sr_err = bsi.bsi_status; 2486 } 2487 2488 send_results:; 2489 if ( rs->sr_err != SLAPD_ABANDON ) { 2490 #ifndef BACKSQL_ARBITRARY_KEY 2491 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { 2492 send_paged_response( op, rs, NULL ); 2493 } else 2494 #endif /* ! BACKSQL_ARBITRARY_KEY */ 2495 { 2496 send_ldap_result( op, rs ); 2497 } 2498 } 2499 2500 /* cleanup in case of abandon */ 2501 for ( ; eid != NULL; 2502 eid = backsql_free_entryID( 2503 eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) ) 2504 ; 2505 2506 backsql_entry_clean( op, &base_entry ); 2507 2508 /* in case we got here accidentally */ 2509 backsql_entry_clean( op, &user_entry ); 2510 2511 if ( rs->sr_v2ref ) { 2512 ber_bvarray_free( rs->sr_v2ref ); 2513 rs->sr_v2ref = NULL; 2514 } 2515 2516 #ifdef BACKSQL_SYNCPROV 2517 if ( op->o_sync ) { 2518 Operation op2 = *op; 2519 SlapReply rs2 = { REP_RESULT }; 2520 Entry *e = entry_alloc(); 2521 slap_callback cb = { 0 }; 2522 2523 op2.o_tag = LDAP_REQ_ADD; 2524 op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0 ); 2525 op2.ora_e = e; 2526 op2.o_callback = &cb; 2527 2528 ber_dupbv( &e->e_name, op->o_bd->be_suffix ); 2529 ber_dupbv( &e->e_nname, op->o_bd->be_nsuffix ); 2530 2531 cb.sc_response = slap_null_cb; 2532 2533 op2.o_bd->be_add( &op2, &rs2 ); 2534 2535 if ( op2.ora_e == e ) 2536 entry_free( e ); 2537 } 2538 #endif /* BACKSQL_SYNCPROV */ 2539 2540 done:; 2541 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); 2542 2543 if ( bsi.bsi_attrs != NULL ) { 2544 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx ); 2545 } 2546 2547 if ( !BER_BVISNULL( &nbase ) 2548 && nbase.bv_val != op->o_req_ndn.bv_val ) 2549 { 2550 ch_free( nbase.bv_val ); 2551 } 2552 2553 /* restore scope ... FIXME: this should be done before ANY 2554 * frontend call that uses op */ 2555 if ( op->ors_scope == BACKSQL_SCOPE_BASE_LIKE ) { 2556 op->ors_scope = LDAP_SCOPE_BASE; 2557 } 2558 2559 Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n" ); 2560 2561 return rs->sr_err; 2562 } 2563 2564 /* return LDAP_SUCCESS IFF we can retrieve the specified entry. 2565 */ 2566 int 2567 backsql_entry_get( 2568 Operation *op, 2569 struct berval *ndn, 2570 ObjectClass *oc, 2571 AttributeDescription *at, 2572 int rw, 2573 Entry **ent ) 2574 { 2575 backsql_srch_info bsi = { 0 }; 2576 SQLHDBC dbh = SQL_NULL_HDBC; 2577 int rc; 2578 SlapReply rs = { 0 }; 2579 AttributeName anlist[ 2 ]; 2580 2581 *ent = NULL; 2582 2583 rc = backsql_get_db_conn( op, &dbh ); 2584 if ( rc != LDAP_SUCCESS ) { 2585 return rc; 2586 } 2587 2588 if ( at ) { 2589 anlist[ 0 ].an_name = at->ad_cname; 2590 anlist[ 0 ].an_desc = at; 2591 BER_BVZERO( &anlist[ 1 ].an_name ); 2592 } 2593 2594 bsi.bsi_e = entry_alloc(); 2595 rc = backsql_init_search( &bsi, 2596 ndn, 2597 LDAP_SCOPE_BASE, 2598 (time_t)(-1), NULL, 2599 dbh, op, &rs, at ? anlist : NULL, 2600 BACKSQL_ISF_GET_ENTRY ); 2601 2602 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { 2603 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); 2604 } 2605 2606 if ( rc == LDAP_SUCCESS ) { 2607 2608 #if 0 /* not supported at present */ 2609 /* find attribute values */ 2610 if ( is_entry_alias( bsi.bsi_e ) ) { 2611 Debug( LDAP_DEBUG_ACL, 2612 "<= backsql_entry_get: entry is an alias\n" ); 2613 rc = LDAP_ALIAS_PROBLEM; 2614 goto return_results; 2615 } 2616 #endif 2617 2618 if ( is_entry_referral( bsi.bsi_e ) ) { 2619 Debug( LDAP_DEBUG_ACL, 2620 "<= backsql_entry_get: entry is a referral\n" ); 2621 rc = LDAP_REFERRAL; 2622 goto return_results; 2623 } 2624 2625 if ( oc && !is_entry_objectclass( bsi.bsi_e, oc, 0 ) ) { 2626 Debug( LDAP_DEBUG_ACL, 2627 "<= backsql_entry_get: " 2628 "failed to find objectClass\n" ); 2629 rc = LDAP_NO_SUCH_ATTRIBUTE; 2630 goto return_results; 2631 } 2632 2633 *ent = bsi.bsi_e; 2634 } 2635 2636 return_results:; 2637 if ( bsi.bsi_attrs != NULL ) { 2638 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx ); 2639 } 2640 2641 if ( rc != LDAP_SUCCESS ) { 2642 if ( bsi.bsi_e ) { 2643 entry_free( bsi.bsi_e ); 2644 } 2645 } 2646 2647 return rc; 2648 } 2649 2650 void 2651 backsql_entry_clean( 2652 Operation *op, 2653 Entry *e ) 2654 { 2655 void *ctx; 2656 2657 ctx = ldap_pvt_thread_pool_context(); 2658 2659 if ( ctx == NULL || ctx != op->o_tmpmemctx ) { 2660 if ( !BER_BVISNULL( &e->e_name ) ) { 2661 op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx ); 2662 BER_BVZERO( &e->e_name ); 2663 } 2664 2665 if ( !BER_BVISNULL( &e->e_nname ) ) { 2666 op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx ); 2667 BER_BVZERO( &e->e_nname ); 2668 } 2669 } 2670 2671 entry_clean( e ); 2672 } 2673 2674 int 2675 backsql_entry_release( 2676 Operation *op, 2677 Entry *e, 2678 int rw ) 2679 { 2680 backsql_entry_clean( op, e ); 2681 2682 entry_free( e ); 2683 2684 return 0; 2685 } 2686 2687 #ifndef BACKSQL_ARBITRARY_KEY 2688 /* This function is copied verbatim from back-bdb/search.c */ 2689 static int 2690 parse_paged_cookie( Operation *op, SlapReply *rs ) 2691 { 2692 int rc = LDAP_SUCCESS; 2693 PagedResultsState *ps = op->o_pagedresults_state; 2694 2695 /* this function must be invoked only if the pagedResults 2696 * control has been detected, parsed and partially checked 2697 * by the frontend */ 2698 assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ); 2699 2700 /* cookie decoding/checks deferred to backend... */ 2701 if ( ps->ps_cookieval.bv_len ) { 2702 PagedResultsCookie reqcookie; 2703 if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) { 2704 /* bad cookie */ 2705 rs->sr_text = "paged results cookie is invalid"; 2706 rc = LDAP_PROTOCOL_ERROR; 2707 goto done; 2708 } 2709 2710 AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie )); 2711 2712 if ( reqcookie > ps->ps_cookie ) { 2713 /* bad cookie */ 2714 rs->sr_text = "paged results cookie is invalid"; 2715 rc = LDAP_PROTOCOL_ERROR; 2716 goto done; 2717 2718 } else if ( reqcookie < ps->ps_cookie ) { 2719 rs->sr_text = "paged results cookie is invalid or old"; 2720 rc = LDAP_UNWILLING_TO_PERFORM; 2721 goto done; 2722 } 2723 2724 } else { 2725 /* Initial request. Initialize state. */ 2726 ps->ps_cookie = 0; 2727 ps->ps_count = 0; 2728 } 2729 2730 done:; 2731 2732 return rc; 2733 } 2734 2735 /* This function is copied nearly verbatim from back-bdb/search.c */ 2736 static void 2737 send_paged_response( 2738 Operation *op, 2739 SlapReply *rs, 2740 ID *lastid ) 2741 { 2742 LDAPControl ctrl, *ctrls[2]; 2743 BerElementBuffer berbuf; 2744 BerElement *ber = (BerElement *)&berbuf; 2745 PagedResultsCookie respcookie; 2746 struct berval cookie; 2747 2748 Debug(LDAP_DEBUG_ARGS, 2749 "send_paged_response: lastid=0x%08lx nentries=%d\n", 2750 lastid ? *lastid : 0, rs->sr_nentries ); 2751 2752 BER_BVZERO( &ctrl.ldctl_value ); 2753 ctrls[0] = &ctrl; 2754 ctrls[1] = NULL; 2755 2756 ber_init2( ber, NULL, LBER_USE_DER ); 2757 2758 if ( lastid ) { 2759 respcookie = ( PagedResultsCookie )(*lastid); 2760 cookie.bv_len = sizeof( respcookie ); 2761 cookie.bv_val = (char *)&respcookie; 2762 2763 } else { 2764 respcookie = ( PagedResultsCookie )0; 2765 BER_BVSTR( &cookie, "" ); 2766 } 2767 2768 op->o_conn->c_pagedresults_state.ps_cookie = respcookie; 2769 op->o_conn->c_pagedresults_state.ps_count = 2770 ((PagedResultsState *)op->o_pagedresults_state)->ps_count + 2771 rs->sr_nentries; 2772 2773 /* return size of 0 -- no estimate */ 2774 ber_printf( ber, "{iO}", 0, &cookie ); 2775 2776 if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) { 2777 goto done; 2778 } 2779 2780 ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; 2781 ctrls[0]->ldctl_iscritical = 0; 2782 2783 rs->sr_ctrls = ctrls; 2784 rs->sr_err = LDAP_SUCCESS; 2785 send_ldap_result( op, rs ); 2786 rs->sr_ctrls = NULL; 2787 2788 done: 2789 (void) ber_free_buf( ber ); 2790 } 2791 #endif /* ! BACKSQL_ARBITRARY_KEY */ 2792