1 /* $NetBSD: search.c,v 1.1.1.6 2018/02/06 01:53:18 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2017 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.1.1.6 2018/02/06 01:53:18 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, 0, 0 ); 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, 0, 0 ); 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, 0, 0 ); 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, 0 ); 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, 0 ); 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", 0, 0, 0 ); 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, 0, 0 ); 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, 0, 0 ); 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 0, 0, 0 ); 875 bsi->bsi_status = LDAP_OTHER; 876 rc = -1; 877 goto done; 878 } 879 880 } else if ( ad == slap_schema.si_ad_entryUUID ) { 881 unsigned long oc_id; 882 #ifdef BACKSQL_ARBITRARY_KEY 883 struct berval keyval; 884 #else /* ! BACKSQL_ARBITRARY_KEY */ 885 unsigned long keyval; 886 char keyvalbuf[LDAP_PVT_INTTYPE_CHARS(unsigned long)]; 887 #endif /* ! BACKSQL_ARBITRARY_KEY */ 888 889 switch ( f->f_choice ) { 890 case LDAP_FILTER_EQUALITY: 891 backsql_entryUUID_decode( &f->f_av_value, &oc_id, &keyval ); 892 893 if ( oc_id != bsi->bsi_oc->bom_id ) { 894 bsi->bsi_status = LDAP_SUCCESS; 895 rc = -1; 896 goto done; 897 } 898 899 #ifdef BACKSQL_ARBITRARY_KEY 900 backsql_strfcat_x( &bsi->bsi_flt_where, 901 bsi->bsi_op->o_tmpmemctx, 902 "bcblbc", 903 &bsi->bsi_oc->bom_keytbl, '.', 904 &bsi->bsi_oc->bom_keycol, 905 STRLENOF( " LIKE '" ), " LIKE '", 906 &keyval, '\'' ); 907 #else /* ! BACKSQL_ARBITRARY_KEY */ 908 snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval ); 909 backsql_strfcat_x( &bsi->bsi_flt_where, 910 bsi->bsi_op->o_tmpmemctx, 911 "bcbcs", 912 &bsi->bsi_oc->bom_keytbl, '.', 913 &bsi->bsi_oc->bom_keycol, '=', keyvalbuf ); 914 #endif /* ! BACKSQL_ARBITRARY_KEY */ 915 break; 916 917 case LDAP_FILTER_PRESENT: 918 backsql_strfcat_x( &bsi->bsi_flt_where, 919 bsi->bsi_op->o_tmpmemctx, 920 "l", 921 (ber_len_t)STRLENOF( "4=4" ), "4=4" ); 922 break; 923 924 default: 925 rc = -1; 926 goto done; 927 } 928 929 bsi->bsi_flags |= BSQL_SF_FILTER_ENTRYUUID; 930 rc = 1; 931 goto done; 932 933 #ifdef BACKSQL_SYNCPROV 934 } else if ( ad == slap_schema.si_ad_entryCSN ) { 935 /* 936 * support for syncrepl as provider... 937 */ 938 #if 0 939 if ( !bsi->bsi_op->o_sync ) { 940 /* unsupported at present... */ 941 bsi->bsi_status = LDAP_OTHER; 942 rc = -1; 943 goto done; 944 } 945 #endif 946 947 bsi->bsi_flags |= ( BSQL_SF_FILTER_ENTRYCSN | BSQL_SF_RETURN_ENTRYUUID); 948 949 /* if doing a syncrepl, try to return as much as possible, 950 * and always match the filter */ 951 backsql_strfcat_x( &bsi->bsi_flt_where, 952 bsi->bsi_op->o_tmpmemctx, 953 "l", 954 (ber_len_t)STRLENOF( "5=5" ), "5=5" ); 955 956 /* save for later use in operational attributes */ 957 /* FIXME: saves only the first occurrence, because 958 * the filter during updates is written as 959 * "(&(entryCSN<={contextCSN})(entryCSN>={oldContextCSN})({filter}))" 960 * so we want our fake entryCSN to match the greatest 961 * value 962 */ 963 if ( bsi->bsi_op->o_private == NULL ) { 964 bsi->bsi_op->o_private = &f->f_av_value; 965 } 966 bsi->bsi_status = LDAP_SUCCESS; 967 968 rc = 1; 969 goto done; 970 #endif /* BACKSQL_SYNCPROV */ 971 972 } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) { 973 /* 974 * FIXME: this is not robust; e.g. a filter 975 * '(!(hasSubordinates=TRUE))' fails because 976 * in SQL it would read 'NOT (1=1)' instead 977 * of no condition. 978 * Note however that hasSubordinates is boolean, 979 * so a more appropriate filter would be 980 * '(hasSubordinates=FALSE)' 981 * 982 * A more robust search for hasSubordinates 983 * would * require joining the ldap_entries table 984 * selecting if there are descendants of the 985 * candidate. 986 */ 987 backsql_strfcat_x( &bsi->bsi_flt_where, 988 bsi->bsi_op->o_tmpmemctx, 989 "l", 990 (ber_len_t)STRLENOF( "6=6" ), "6=6" ); 991 if ( ad == slap_schema.si_ad_hasSubordinates ) { 992 /* 993 * instruct candidate selection algorithm 994 * and attribute list to try to detect 995 * if an entry has subordinates 996 */ 997 bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE; 998 999 } else { 1000 /* 1001 * clear attributes to fetch, to require ALL 1002 * and try extended match on all attributes 1003 */ 1004 backsql_attrlist_add( bsi, NULL ); 1005 } 1006 rc = 1; 1007 goto done; 1008 } 1009 1010 /* 1011 * attribute inheritance: 1012 */ 1013 if ( backsql_supad2at( bsi->bsi_oc, ad, &vat ) ) { 1014 bsi->bsi_status = LDAP_OTHER; 1015 rc = -1; 1016 goto done; 1017 } 1018 1019 if ( vat == NULL ) { 1020 /* search anyway; other parts of the filter 1021 * may succeeed */ 1022 backsql_strfcat_x( &bsi->bsi_flt_where, 1023 bsi->bsi_op->o_tmpmemctx, 1024 "l", 1025 (ber_len_t)STRLENOF( "7=7" ), "7=7" ); 1026 bsi->bsi_status = LDAP_SUCCESS; 1027 rc = 1; 1028 goto done; 1029 } 1030 1031 /* if required, open extra level of parens */ 1032 done = 0; 1033 if ( vat[0]->bam_next || vat[1] ) { 1034 backsql_strfcat_x( &bsi->bsi_flt_where, 1035 bsi->bsi_op->o_tmpmemctx, 1036 "c", '(' ); 1037 done = 1; 1038 } 1039 1040 i = 0; 1041 next:; 1042 /* apply attr */ 1043 if ( backsql_process_filter_attr( bsi, f, vat[i] ) == -1 ) { 1044 return -1; 1045 } 1046 1047 /* if more definitions of the same attr, apply */ 1048 if ( vat[i]->bam_next ) { 1049 backsql_strfcat_x( &bsi->bsi_flt_where, 1050 bsi->bsi_op->o_tmpmemctx, 1051 "l", 1052 STRLENOF( " OR " ), " OR " ); 1053 vat[i] = vat[i]->bam_next; 1054 goto next; 1055 } 1056 1057 /* if more descendants of the same attr, apply */ 1058 i++; 1059 if ( vat[i] ) { 1060 backsql_strfcat_x( &bsi->bsi_flt_where, 1061 bsi->bsi_op->o_tmpmemctx, 1062 "l", 1063 STRLENOF( " OR " ), " OR " ); 1064 goto next; 1065 } 1066 1067 /* if needed, close extra level of parens */ 1068 if ( done ) { 1069 backsql_strfcat_x( &bsi->bsi_flt_where, 1070 bsi->bsi_op->o_tmpmemctx, 1071 "c", ')' ); 1072 } 1073 1074 rc = 1; 1075 1076 done:; 1077 if ( vat ) { 1078 ch_free( vat ); 1079 } 1080 1081 Debug( LDAP_DEBUG_TRACE, 1082 "<==backsql_process_filter() %s\n", 1083 rc == 1 ? "succeeded" : "failed", 0, 0); 1084 1085 return rc; 1086 } 1087 1088 static int 1089 backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at, 1090 int casefold, struct berval *filter_value ) 1091 { 1092 /* 1093 * maybe we should check type of at->sel_expr here somehow, 1094 * to know whether upper_func is applicable, but for now 1095 * upper_func stuff is made for Oracle, where UPPER is 1096 * safely applicable to NUMBER etc. 1097 */ 1098 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { 1099 ber_len_t start; 1100 1101 backsql_strfcat_x( &bsi->bsi_flt_where, 1102 bsi->bsi_op->o_tmpmemctx, 1103 "cbl", 1104 '(', /* ) */ 1105 &at->bam_sel_expr_u, 1106 (ber_len_t)STRLENOF( "='" ), 1107 "='" ); 1108 1109 start = bsi->bsi_flt_where.bb_val.bv_len; 1110 1111 backsql_strfcat_x( &bsi->bsi_flt_where, 1112 bsi->bsi_op->o_tmpmemctx, 1113 "bl", 1114 filter_value, 1115 (ber_len_t)STRLENOF( /* (' */ "')" ), 1116 /* (' */ "')" ); 1117 1118 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); 1119 1120 } else { 1121 backsql_strfcat_x( &bsi->bsi_flt_where, 1122 bsi->bsi_op->o_tmpmemctx, 1123 "cblbl", 1124 '(', /* ) */ 1125 &at->bam_sel_expr, 1126 (ber_len_t)STRLENOF( "='" ), "='", 1127 filter_value, 1128 (ber_len_t)STRLENOF( /* (' */ "')" ), 1129 /* (' */ "')" ); 1130 } 1131 1132 return 1; 1133 } 1134 1135 static int 1136 backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at, 1137 int casefold, struct berval *filter_value ) 1138 { 1139 /* 1140 * maybe we should check type of at->sel_expr here somehow, 1141 * to know whether upper_func is applicable, but for now 1142 * upper_func stuff is made for Oracle, where UPPER is 1143 * safely applicable to NUMBER etc. 1144 */ 1145 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { 1146 ber_len_t start; 1147 1148 backsql_strfcat_x( &bsi->bsi_flt_where, 1149 bsi->bsi_op->o_tmpmemctx, 1150 "cbl", 1151 '(', /* ) */ 1152 &at->bam_sel_expr_u, 1153 (ber_len_t)STRLENOF( " LIKE '%" ), 1154 " LIKE '%" ); 1155 1156 start = bsi->bsi_flt_where.bb_val.bv_len; 1157 1158 backsql_strfcat_x( &bsi->bsi_flt_where, 1159 bsi->bsi_op->o_tmpmemctx, 1160 "bl", 1161 filter_value, 1162 (ber_len_t)STRLENOF( /* (' */ "%')" ), 1163 /* (' */ "%')" ); 1164 1165 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); 1166 1167 } else { 1168 backsql_strfcat_x( &bsi->bsi_flt_where, 1169 bsi->bsi_op->o_tmpmemctx, 1170 "cblbl", 1171 '(', /* ) */ 1172 &at->bam_sel_expr, 1173 (ber_len_t)STRLENOF( " LIKE '%" ), 1174 " LIKE '%", 1175 filter_value, 1176 (ber_len_t)STRLENOF( /* (' */ "%')" ), 1177 /* (' */ "%')" ); 1178 } 1179 1180 return 1; 1181 } 1182 1183 static int 1184 backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at ) 1185 { 1186 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; 1187 int casefold = 0; 1188 struct berval *filter_value = NULL; 1189 MatchingRule *matching_rule = NULL; 1190 struct berval ordering = BER_BVC("<="); 1191 1192 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n", 1193 at->bam_ad->ad_cname.bv_val, 0, 0 ); 1194 1195 /* 1196 * need to add this attribute to list of attrs to load, 1197 * so that we can do test_filter() later 1198 */ 1199 backsql_attrlist_add( bsi, at->bam_ad ); 1200 1201 backsql_merge_from_tbls( bsi, &at->bam_from_tbls ); 1202 1203 if ( !BER_BVISNULL( &at->bam_join_where ) 1204 && strstr( bsi->bsi_join_where.bb_val.bv_val, 1205 at->bam_join_where.bv_val ) == NULL ) 1206 { 1207 backsql_strfcat_x( &bsi->bsi_join_where, 1208 bsi->bsi_op->o_tmpmemctx, 1209 "lb", 1210 (ber_len_t)STRLENOF( " AND " ), " AND ", 1211 &at->bam_join_where ); 1212 } 1213 1214 if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) { 1215 backsql_strfcat_x( &bsi->bsi_flt_where, 1216 bsi->bsi_op->o_tmpmemctx, 1217 "l", 1218 (ber_len_t)STRLENOF( "1=0" ), "1=0" ); 1219 return 1; 1220 } 1221 1222 switch ( f->f_choice ) { 1223 case LDAP_FILTER_EQUALITY: 1224 filter_value = &f->f_av_value; 1225 matching_rule = at->bam_ad->ad_type->sat_equality; 1226 1227 goto equality_match; 1228 1229 /* fail over into next case */ 1230 1231 case LDAP_FILTER_EXT: 1232 filter_value = &f->f_mra->ma_value; 1233 matching_rule = f->f_mr_rule; 1234 1235 equality_match:; 1236 /* always uppercase strings by now */ 1237 #ifdef BACKSQL_UPPERCASE_FILTER 1238 if ( SLAP_MR_ASSOCIATED( matching_rule, 1239 bi->sql_caseIgnoreMatch ) ) 1240 #endif /* BACKSQL_UPPERCASE_FILTER */ 1241 { 1242 casefold = 1; 1243 } 1244 1245 /* FIXME: directoryString filtering should use a similar 1246 * approach to deal with non-prettified values like 1247 * " A non prettified value ", by using a LIKE 1248 * filter with all whitespaces collapsed to a single '%' */ 1249 if ( SLAP_MR_ASSOCIATED( matching_rule, 1250 bi->sql_telephoneNumberMatch ) ) 1251 { 1252 struct berval bv; 1253 ber_len_t i; 1254 1255 /* 1256 * to check for matching telephone numbers 1257 * with intermized chars, e.g. val='1234' 1258 * use 1259 * 1260 * val LIKE '%1%2%3%4%' 1261 */ 1262 1263 bv.bv_len = 2 * filter_value->bv_len - 1; 1264 bv.bv_val = ch_malloc( bv.bv_len + 1 ); 1265 1266 bv.bv_val[ 0 ] = filter_value->bv_val[ 0 ]; 1267 for ( i = 1; i < filter_value->bv_len; i++ ) { 1268 bv.bv_val[ 2 * i - 1 ] = '%'; 1269 bv.bv_val[ 2 * i ] = filter_value->bv_val[ i ]; 1270 } 1271 bv.bv_val[ 2 * i - 1 ] = '\0'; 1272 1273 (void)backsql_process_filter_like( bsi, at, casefold, &bv ); 1274 ch_free( bv.bv_val ); 1275 1276 break; 1277 } 1278 1279 /* NOTE: this is required by objectClass inheritance 1280 * and auxiliary objectClass use in filters for slightly 1281 * more efficient candidate selection. */ 1282 /* FIXME: a bit too many specializations to deal with 1283 * very specific cases... */ 1284 if ( at->bam_ad == slap_schema.si_ad_objectClass 1285 || at->bam_ad == slap_schema.si_ad_structuralObjectClass ) 1286 { 1287 backsql_strfcat_x( &bsi->bsi_flt_where, 1288 bsi->bsi_op->o_tmpmemctx, 1289 "lbl", 1290 (ber_len_t)STRLENOF( "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ), 1291 "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */, 1292 filter_value, 1293 (ber_len_t)STRLENOF( /* (' */ "')" ), 1294 /* (' */ "')" ); 1295 break; 1296 } 1297 1298 /* 1299 * maybe we should check type of at->sel_expr here somehow, 1300 * to know whether upper_func is applicable, but for now 1301 * upper_func stuff is made for Oracle, where UPPER is 1302 * safely applicable to NUMBER etc. 1303 */ 1304 (void)backsql_process_filter_eq( bsi, at, casefold, filter_value ); 1305 break; 1306 1307 case LDAP_FILTER_GE: 1308 ordering.bv_val = ">="; 1309 1310 /* fall thru to next case */ 1311 1312 case LDAP_FILTER_LE: 1313 filter_value = &f->f_av_value; 1314 1315 /* always uppercase strings by now */ 1316 #ifdef BACKSQL_UPPERCASE_FILTER 1317 if ( at->bam_ad->ad_type->sat_ordering && 1318 SLAP_MR_ASSOCIATED( at->bam_ad->ad_type->sat_ordering, 1319 bi->sql_caseIgnoreMatch ) ) 1320 #endif /* BACKSQL_UPPERCASE_FILTER */ 1321 { 1322 casefold = 1; 1323 } 1324 1325 /* 1326 * FIXME: should we uppercase the operands? 1327 */ 1328 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { 1329 ber_len_t start; 1330 1331 backsql_strfcat_x( &bsi->bsi_flt_where, 1332 bsi->bsi_op->o_tmpmemctx, 1333 "cbbc", 1334 '(', /* ) */ 1335 &at->bam_sel_expr_u, 1336 &ordering, 1337 '\'' ); 1338 1339 start = bsi->bsi_flt_where.bb_val.bv_len; 1340 1341 backsql_strfcat_x( &bsi->bsi_flt_where, 1342 bsi->bsi_op->o_tmpmemctx, 1343 "bl", 1344 filter_value, 1345 (ber_len_t)STRLENOF( /* (' */ "')" ), 1346 /* (' */ "')" ); 1347 1348 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); 1349 1350 } else { 1351 backsql_strfcat_x( &bsi->bsi_flt_where, 1352 bsi->bsi_op->o_tmpmemctx, 1353 "cbbcbl", 1354 '(' /* ) */ , 1355 &at->bam_sel_expr, 1356 &ordering, 1357 '\'', 1358 &f->f_av_value, 1359 (ber_len_t)STRLENOF( /* (' */ "')" ), 1360 /* ( */ "')" ); 1361 } 1362 break; 1363 1364 case LDAP_FILTER_PRESENT: 1365 backsql_strfcat_x( &bsi->bsi_flt_where, 1366 bsi->bsi_op->o_tmpmemctx, 1367 "lbl", 1368 (ber_len_t)STRLENOF( "NOT (" /* ) */), 1369 "NOT (", /* ) */ 1370 &at->bam_sel_expr, 1371 (ber_len_t)STRLENOF( /* ( */ " IS NULL)" ), 1372 /* ( */ " IS NULL)" ); 1373 break; 1374 1375 case LDAP_FILTER_SUBSTRINGS: 1376 backsql_process_sub_filter( bsi, f, at ); 1377 break; 1378 1379 case LDAP_FILTER_APPROX: 1380 /* we do our best */ 1381 1382 /* 1383 * maybe we should check type of at->sel_expr here somehow, 1384 * to know whether upper_func is applicable, but for now 1385 * upper_func stuff is made for Oracle, where UPPER is 1386 * safely applicable to NUMBER etc. 1387 */ 1388 (void)backsql_process_filter_like( bsi, at, 1, &f->f_av_value ); 1389 break; 1390 1391 default: 1392 /* unhandled filter type; should not happen */ 1393 assert( 0 ); 1394 backsql_strfcat_x( &bsi->bsi_flt_where, 1395 bsi->bsi_op->o_tmpmemctx, 1396 "l", 1397 (ber_len_t)STRLENOF( "8=8" ), "8=8" ); 1398 break; 1399 1400 } 1401 1402 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter_attr(%s)\n", 1403 at->bam_ad->ad_cname.bv_val, 0, 0 ); 1404 1405 return 1; 1406 } 1407 1408 static int 1409 backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) 1410 { 1411 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; 1412 int rc; 1413 1414 assert( query != NULL ); 1415 BER_BVZERO( query ); 1416 1417 bsi->bsi_use_subtree_shortcut = 0; 1418 1419 Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n", 0, 0, 0 ); 1420 BER_BVZERO( &bsi->bsi_sel.bb_val ); 1421 BER_BVZERO( &bsi->bsi_sel.bb_val ); 1422 bsi->bsi_sel.bb_len = 0; 1423 BER_BVZERO( &bsi->bsi_from.bb_val ); 1424 bsi->bsi_from.bb_len = 0; 1425 BER_BVZERO( &bsi->bsi_join_where.bb_val ); 1426 bsi->bsi_join_where.bb_len = 0; 1427 BER_BVZERO( &bsi->bsi_flt_where.bb_val ); 1428 bsi->bsi_flt_where.bb_len = 0; 1429 1430 backsql_strfcat_x( &bsi->bsi_sel, 1431 bsi->bsi_op->o_tmpmemctx, 1432 "lbcbc", 1433 (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ), 1434 "SELECT DISTINCT ldap_entries.id,", 1435 &bsi->bsi_oc->bom_keytbl, 1436 '.', 1437 &bsi->bsi_oc->bom_keycol, 1438 ',' ); 1439 1440 if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) { 1441 backsql_strfcat_x( &bsi->bsi_sel, 1442 bsi->bsi_op->o_tmpmemctx, 1443 "blbl", 1444 &bi->sql_strcast_func, 1445 (ber_len_t)STRLENOF( "('" /* ') */ ), 1446 "('" /* ') */ , 1447 &bsi->bsi_oc->bom_oc->soc_cname, 1448 (ber_len_t)STRLENOF( /* (' */ "')" ), 1449 /* (' */ "')" ); 1450 } else { 1451 backsql_strfcat_x( &bsi->bsi_sel, 1452 bsi->bsi_op->o_tmpmemctx, 1453 "cbc", 1454 '\'', 1455 &bsi->bsi_oc->bom_oc->soc_cname, 1456 '\'' ); 1457 } 1458 1459 backsql_strfcat_x( &bsi->bsi_sel, 1460 bsi->bsi_op->o_tmpmemctx, 1461 "b", 1462 &bi->sql_dn_oc_aliasing ); 1463 backsql_strfcat_x( &bsi->bsi_from, 1464 bsi->bsi_op->o_tmpmemctx, 1465 "lb", 1466 (ber_len_t)STRLENOF( " FROM ldap_entries," ), 1467 " FROM ldap_entries,", 1468 &bsi->bsi_oc->bom_keytbl ); 1469 1470 backsql_strfcat_x( &bsi->bsi_join_where, 1471 bsi->bsi_op->o_tmpmemctx, 1472 "lbcbl", 1473 (ber_len_t)STRLENOF( " WHERE " ), " WHERE ", 1474 &bsi->bsi_oc->bom_keytbl, 1475 '.', 1476 &bsi->bsi_oc->bom_keycol, 1477 (ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ), 1478 "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ); 1479 1480 switch ( bsi->bsi_scope ) { 1481 case LDAP_SCOPE_BASE: 1482 if ( BACKSQL_CANUPPERCASE( bi ) ) { 1483 backsql_strfcat_x( &bsi->bsi_join_where, 1484 bsi->bsi_op->o_tmpmemctx, 1485 "bl", 1486 &bi->sql_upper_func, 1487 (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ), 1488 "(ldap_entries.dn)=?" ); 1489 } else { 1490 backsql_strfcat_x( &bsi->bsi_join_where, 1491 bsi->bsi_op->o_tmpmemctx, 1492 "l", 1493 (ber_len_t)STRLENOF( "ldap_entries.dn=?" ), 1494 "ldap_entries.dn=?" ); 1495 } 1496 break; 1497 1498 case BACKSQL_SCOPE_BASE_LIKE: 1499 if ( BACKSQL_CANUPPERCASE( bi ) ) { 1500 backsql_strfcat_x( &bsi->bsi_join_where, 1501 bsi->bsi_op->o_tmpmemctx, 1502 "bl", 1503 &bi->sql_upper_func, 1504 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ), 1505 "(ldap_entries.dn) LIKE ?" ); 1506 } else { 1507 backsql_strfcat_x( &bsi->bsi_join_where, 1508 bsi->bsi_op->o_tmpmemctx, 1509 "l", 1510 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ), 1511 "ldap_entries.dn LIKE ?" ); 1512 } 1513 break; 1514 1515 case LDAP_SCOPE_ONELEVEL: 1516 backsql_strfcat_x( &bsi->bsi_join_where, 1517 bsi->bsi_op->o_tmpmemctx, 1518 "l", 1519 (ber_len_t)STRLENOF( "ldap_entries.parent=?" ), 1520 "ldap_entries.parent=?" ); 1521 break; 1522 1523 case LDAP_SCOPE_SUBORDINATE: 1524 case LDAP_SCOPE_SUBTREE: 1525 if ( BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ) { 1526 int i; 1527 BackendDB *bd = bsi->bsi_op->o_bd; 1528 1529 assert( bd->be_nsuffix != NULL ); 1530 1531 for ( i = 0; !BER_BVISNULL( &bd->be_nsuffix[ i ] ); i++ ) 1532 { 1533 if ( dn_match( &bd->be_nsuffix[ i ], 1534 bsi->bsi_base_ndn ) ) 1535 { 1536 /* pass this to the candidate selection 1537 * routine so that the DN is not bound 1538 * to the select statement */ 1539 bsi->bsi_use_subtree_shortcut = 1; 1540 break; 1541 } 1542 } 1543 } 1544 1545 if ( bsi->bsi_use_subtree_shortcut ) { 1546 /* Skip the base DN filter, as every entry will match it */ 1547 backsql_strfcat_x( &bsi->bsi_join_where, 1548 bsi->bsi_op->o_tmpmemctx, 1549 "l", 1550 (ber_len_t)STRLENOF( "9=9"), "9=9"); 1551 1552 } else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) { 1553 /* This should always be true... */ 1554 backsql_strfcat_x( &bsi->bsi_join_where, 1555 bsi->bsi_op->o_tmpmemctx, 1556 "b", 1557 &bi->sql_subtree_cond ); 1558 1559 } else if ( BACKSQL_CANUPPERCASE( bi ) ) { 1560 backsql_strfcat_x( &bsi->bsi_join_where, 1561 bsi->bsi_op->o_tmpmemctx, 1562 "bl", 1563 &bi->sql_upper_func, 1564 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ), 1565 "(ldap_entries.dn) LIKE ?" ); 1566 1567 } else { 1568 backsql_strfcat_x( &bsi->bsi_join_where, 1569 bsi->bsi_op->o_tmpmemctx, 1570 "l", 1571 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ), 1572 "ldap_entries.dn LIKE ?" ); 1573 } 1574 1575 break; 1576 1577 default: 1578 assert( 0 ); 1579 } 1580 1581 #ifndef BACKSQL_ARBITRARY_KEY 1582 /* If paged results are in effect, ignore low ldap_entries.id numbers */ 1583 if ( get_pagedresults(bsi->bsi_op) > SLAP_CONTROL_IGNORED ) { 1584 unsigned long lowid = 0; 1585 1586 /* Pick up the previous ldap_entries.id if the previous page ended in this objectClass */ 1587 if ( bsi->bsi_oc->bom_id == PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ) ) 1588 { 1589 lowid = PAGECOOKIE_TO_SQL_ID( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ); 1590 } 1591 1592 if ( lowid ) { 1593 char lowidstring[48]; 1594 int lowidlen; 1595 1596 lowidlen = snprintf( lowidstring, sizeof( lowidstring ), 1597 " AND ldap_entries.id>%lu", lowid ); 1598 backsql_strfcat_x( &bsi->bsi_join_where, 1599 bsi->bsi_op->o_tmpmemctx, 1600 "l", 1601 (ber_len_t)lowidlen, 1602 lowidstring ); 1603 } 1604 } 1605 #endif /* ! BACKSQL_ARBITRARY_KEY */ 1606 1607 rc = backsql_process_filter( bsi, bsi->bsi_filter ); 1608 if ( rc > 0 ) { 1609 struct berbuf bb = BB_NULL; 1610 1611 backsql_strfcat_x( &bb, 1612 bsi->bsi_op->o_tmpmemctx, 1613 "bbblb", 1614 &bsi->bsi_sel.bb_val, 1615 &bsi->bsi_from.bb_val, 1616 &bsi->bsi_join_where.bb_val, 1617 (ber_len_t)STRLENOF( " AND " ), " AND ", 1618 &bsi->bsi_flt_where.bb_val ); 1619 1620 *query = bb.bb_val; 1621 1622 } else if ( rc < 0 ) { 1623 /* 1624 * Indicates that there's no possible way the filter matches 1625 * anything. No need to issue the query 1626 */ 1627 free( query->bv_val ); 1628 BER_BVZERO( query ); 1629 } 1630 1631 bsi->bsi_op->o_tmpfree( bsi->bsi_sel.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); 1632 BER_BVZERO( &bsi->bsi_sel.bb_val ); 1633 bsi->bsi_sel.bb_len = 0; 1634 bsi->bsi_op->o_tmpfree( bsi->bsi_from.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); 1635 BER_BVZERO( &bsi->bsi_from.bb_val ); 1636 bsi->bsi_from.bb_len = 0; 1637 bsi->bsi_op->o_tmpfree( bsi->bsi_join_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); 1638 BER_BVZERO( &bsi->bsi_join_where.bb_val ); 1639 bsi->bsi_join_where.bb_len = 0; 1640 bsi->bsi_op->o_tmpfree( bsi->bsi_flt_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); 1641 BER_BVZERO( &bsi->bsi_flt_where.bb_val ); 1642 bsi->bsi_flt_where.bb_len = 0; 1643 1644 Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n", 1645 query->bv_val ? query->bv_val : "NULL", 0, 0 ); 1646 1647 return ( rc <= 0 ? 1 : 0 ); 1648 } 1649 1650 static int 1651 backsql_oc_get_candidates( void *v_oc, void *v_bsi ) 1652 { 1653 backsql_oc_map_rec *oc = v_oc; 1654 backsql_srch_info *bsi = v_bsi; 1655 Operation *op = bsi->bsi_op; 1656 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; 1657 struct berval query; 1658 SQLHSTMT sth = SQL_NULL_HSTMT; 1659 RETCODE rc; 1660 int res; 1661 BACKSQL_ROW_NTS row; 1662 int i; 1663 int j; 1664 int n_candidates = bsi->bsi_n_candidates; 1665 1666 /* 1667 * + 1 because we need room for '%'; 1668 * + 1 because we need room for ',' for LDAP_SCOPE_SUBORDINATE; 1669 * this makes a subtree 1670 * search for a DN BACKSQL_MAX_DN_LEN long legal 1671 * if it returns that DN only 1672 */ 1673 char tmp_base_ndn[ BACKSQL_MAX_DN_LEN + 1 + 1 ]; 1674 1675 bsi->bsi_status = LDAP_SUCCESS; 1676 1677 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc=\"%s\"\n", 1678 BACKSQL_OC_NAME( oc ), 0, 0 ); 1679 1680 /* check for abandon */ 1681 if ( op->o_abandon ) { 1682 bsi->bsi_status = SLAPD_ABANDON; 1683 return BACKSQL_AVL_STOP; 1684 } 1685 1686 #ifndef BACKSQL_ARBITRARY_KEY 1687 /* If paged results have already completed this objectClass, skip it */ 1688 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { 1689 if ( oc->bom_id < PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)op->o_pagedresults_state)->ps_cookie ) ) 1690 { 1691 return BACKSQL_AVL_CONTINUE; 1692 } 1693 } 1694 #endif /* ! BACKSQL_ARBITRARY_KEY */ 1695 1696 if ( bsi->bsi_n_candidates == -1 ) { 1697 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1698 "unchecked limit has been overcome\n", 0, 0, 0 ); 1699 /* should never get here */ 1700 assert( 0 ); 1701 bsi->bsi_status = LDAP_ADMINLIMIT_EXCEEDED; 1702 return BACKSQL_AVL_STOP; 1703 } 1704 1705 bsi->bsi_oc = oc; 1706 res = backsql_srch_query( bsi, &query ); 1707 if ( res ) { 1708 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1709 "error while constructing query for objectclass \"%s\"\n", 1710 oc->bom_oc->soc_cname.bv_val, 0, 0 ); 1711 /* 1712 * FIXME: need to separate errors from legally 1713 * impossible filters 1714 */ 1715 switch ( bsi->bsi_status ) { 1716 case LDAP_SUCCESS: 1717 case LDAP_UNDEFINED_TYPE: 1718 case LDAP_NO_SUCH_OBJECT: 1719 /* we are conservative... */ 1720 default: 1721 bsi->bsi_status = LDAP_SUCCESS; 1722 /* try next */ 1723 return BACKSQL_AVL_CONTINUE; 1724 1725 case LDAP_ADMINLIMIT_EXCEEDED: 1726 case LDAP_OTHER: 1727 /* don't try any more */ 1728 return BACKSQL_AVL_STOP; 1729 } 1730 } 1731 1732 if ( BER_BVISNULL( &query ) ) { 1733 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1734 "could not construct query for objectclass \"%s\"\n", 1735 oc->bom_oc->soc_cname.bv_val, 0, 0 ); 1736 bsi->bsi_status = LDAP_SUCCESS; 1737 return BACKSQL_AVL_CONTINUE; 1738 } 1739 1740 Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n", 1741 query.bv_val, 0, 0 ); 1742 1743 rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 ); 1744 bsi->bsi_op->o_tmpfree( query.bv_val, bsi->bsi_op->o_tmpmemctx ); 1745 BER_BVZERO( &query ); 1746 if ( rc != SQL_SUCCESS ) { 1747 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1748 "error preparing query\n", 0, 0, 0 ); 1749 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); 1750 bsi->bsi_status = LDAP_OTHER; 1751 return BACKSQL_AVL_CONTINUE; 1752 } 1753 1754 Debug( LDAP_DEBUG_TRACE, "id: '" BACKSQL_IDNUMFMT "'\n", 1755 bsi->bsi_oc->bom_id, 0, 0 ); 1756 1757 rc = backsql_BindParamNumID( sth, 1, SQL_PARAM_INPUT, 1758 &bsi->bsi_oc->bom_id ); 1759 if ( rc != SQL_SUCCESS ) { 1760 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1761 "error binding objectclass id parameter\n", 0, 0, 0 ); 1762 bsi->bsi_status = LDAP_OTHER; 1763 return BACKSQL_AVL_CONTINUE; 1764 } 1765 1766 switch ( bsi->bsi_scope ) { 1767 case LDAP_SCOPE_BASE: 1768 case BACKSQL_SCOPE_BASE_LIKE: 1769 /* 1770 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN; 1771 * however this should be handled earlier 1772 */ 1773 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) { 1774 bsi->bsi_status = LDAP_OTHER; 1775 return BACKSQL_AVL_CONTINUE; 1776 } 1777 1778 AC_MEMCPY( tmp_base_ndn, bsi->bsi_base_ndn->bv_val, 1779 bsi->bsi_base_ndn->bv_len + 1 ); 1780 1781 /* uppercase DN only if the stored DN can be uppercased 1782 * for comparison */ 1783 if ( BACKSQL_CANUPPERCASE( bi ) ) { 1784 ldap_pvt_str2upper( tmp_base_ndn ); 1785 } 1786 1787 Debug( LDAP_DEBUG_TRACE, "(base)dn: \"%s\"\n", 1788 tmp_base_ndn, 0, 0 ); 1789 1790 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT, 1791 tmp_base_ndn, BACKSQL_MAX_DN_LEN ); 1792 if ( rc != SQL_SUCCESS ) { 1793 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1794 "error binding base_ndn parameter\n", 0, 0, 0 ); 1795 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, 1796 sth, rc ); 1797 bsi->bsi_status = LDAP_OTHER; 1798 return BACKSQL_AVL_CONTINUE; 1799 } 1800 break; 1801 1802 case LDAP_SCOPE_SUBORDINATE: 1803 case LDAP_SCOPE_SUBTREE: 1804 { 1805 /* if short-cutting the search base, 1806 * don't bind any parameter */ 1807 if ( bsi->bsi_use_subtree_shortcut ) { 1808 break; 1809 } 1810 1811 /* 1812 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN; 1813 * however this should be handled earlier 1814 */ 1815 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) { 1816 bsi->bsi_status = LDAP_OTHER; 1817 return BACKSQL_AVL_CONTINUE; 1818 } 1819 1820 /* 1821 * Sets the parameters for the SQL built earlier 1822 * NOTE that all the databases could actually use 1823 * the TimesTen version, which would be cleaner 1824 * and would also eliminate the need for the 1825 * subtree_cond line in the configuration file. 1826 * For now, I'm leaving it the way it is, 1827 * so non-TimesTen databases use the original code. 1828 * But at some point this should get cleaned up. 1829 * 1830 * If "dn" is being used, do a suffix search. 1831 * If "dn_ru" is being used, do a prefix search. 1832 */ 1833 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) { 1834 tmp_base_ndn[ 0 ] = '\0'; 1835 1836 for ( i = 0, j = bsi->bsi_base_ndn->bv_len - 1; 1837 j >= 0; i++, j--) { 1838 tmp_base_ndn[ i ] = bsi->bsi_base_ndn->bv_val[ j ]; 1839 } 1840 1841 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) { 1842 tmp_base_ndn[ i++ ] = ','; 1843 } 1844 1845 tmp_base_ndn[ i ] = '%'; 1846 tmp_base_ndn[ i + 1 ] = '\0'; 1847 1848 } else { 1849 i = 0; 1850 1851 tmp_base_ndn[ i++ ] = '%'; 1852 1853 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) { 1854 tmp_base_ndn[ i++ ] = ','; 1855 } 1856 1857 AC_MEMCPY( &tmp_base_ndn[ i ], bsi->bsi_base_ndn->bv_val, 1858 bsi->bsi_base_ndn->bv_len + 1 ); 1859 } 1860 1861 /* uppercase DN only if the stored DN can be uppercased 1862 * for comparison */ 1863 if ( BACKSQL_CANUPPERCASE( bi ) ) { 1864 ldap_pvt_str2upper( tmp_base_ndn ); 1865 } 1866 1867 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) { 1868 Debug( LDAP_DEBUG_TRACE, "(children)dn: \"%s\"\n", 1869 tmp_base_ndn, 0, 0 ); 1870 } else { 1871 Debug( LDAP_DEBUG_TRACE, "(sub)dn: \"%s\"\n", 1872 tmp_base_ndn, 0, 0 ); 1873 } 1874 1875 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT, 1876 tmp_base_ndn, BACKSQL_MAX_DN_LEN ); 1877 if ( rc != SQL_SUCCESS ) { 1878 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1879 "error binding base_ndn parameter (2)\n", 1880 0, 0, 0 ); 1881 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, 1882 sth, rc ); 1883 bsi->bsi_status = LDAP_OTHER; 1884 return BACKSQL_AVL_CONTINUE; 1885 } 1886 break; 1887 } 1888 1889 case LDAP_SCOPE_ONELEVEL: 1890 assert( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ); 1891 1892 Debug( LDAP_DEBUG_TRACE, "(one)id=" BACKSQL_IDFMT "\n", 1893 BACKSQL_IDARG(bsi->bsi_base_id.eid_id), 0, 0 ); 1894 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT, 1895 &bsi->bsi_base_id.eid_id ); 1896 if ( rc != SQL_SUCCESS ) { 1897 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1898 "error binding base id parameter\n", 0, 0, 0 ); 1899 bsi->bsi_status = LDAP_OTHER; 1900 return BACKSQL_AVL_CONTINUE; 1901 } 1902 break; 1903 } 1904 1905 rc = SQLExecute( sth ); 1906 if ( !BACKSQL_SUCCESS( rc ) ) { 1907 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1908 "error executing query\n", 0, 0, 0 ); 1909 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); 1910 SQLFreeStmt( sth, SQL_DROP ); 1911 bsi->bsi_status = LDAP_OTHER; 1912 return BACKSQL_AVL_CONTINUE; 1913 } 1914 1915 backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx ); 1916 rc = SQLFetch( sth ); 1917 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) { 1918 struct berval dn, pdn, ndn; 1919 backsql_entryID *c_id = NULL; 1920 int ret; 1921 1922 ber_str2bv( row.cols[ 3 ], 0, 0, &dn ); 1923 1924 if ( backsql_api_odbc2dn( bsi->bsi_op, bsi->bsi_rs, &dn ) ) { 1925 continue; 1926 } 1927 1928 ret = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx ); 1929 if ( dn.bv_val != row.cols[ 3 ] ) { 1930 free( dn.bv_val ); 1931 } 1932 1933 if ( ret != LDAP_SUCCESS ) { 1934 continue; 1935 } 1936 1937 if ( bi->sql_baseObject && dn_match( &ndn, &bi->sql_baseObject->e_nname ) ) { 1938 goto cleanup; 1939 } 1940 1941 c_id = (backsql_entryID *)op->o_tmpcalloc( 1, 1942 sizeof( backsql_entryID ), op->o_tmpmemctx ); 1943 #ifdef BACKSQL_ARBITRARY_KEY 1944 ber_str2bv_x( row.cols[ 0 ], 0, 1, &c_id->eid_id, 1945 op->o_tmpmemctx ); 1946 ber_str2bv_x( row.cols[ 1 ], 0, 1, &c_id->eid_keyval, 1947 op->o_tmpmemctx ); 1948 #else /* ! BACKSQL_ARBITRARY_KEY */ 1949 if ( BACKSQL_STR2ID( &c_id->eid_id, row.cols[ 0 ], 0 ) != 0 ) { 1950 goto cleanup; 1951 } 1952 if ( BACKSQL_STR2ID( &c_id->eid_keyval, row.cols[ 1 ], 0 ) != 0 ) { 1953 goto cleanup; 1954 } 1955 #endif /* ! BACKSQL_ARBITRARY_KEY */ 1956 c_id->eid_oc = bsi->bsi_oc; 1957 c_id->eid_oc_id = bsi->bsi_oc->bom_id; 1958 1959 c_id->eid_dn = pdn; 1960 c_id->eid_ndn = ndn; 1961 1962 /* append at end of list ... */ 1963 c_id->eid_next = NULL; 1964 *bsi->bsi_id_listtail = c_id; 1965 bsi->bsi_id_listtail = &c_id->eid_next; 1966 1967 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " 1968 "added entry id=" BACKSQL_IDFMT " keyval=" BACKSQL_IDFMT " dn=\"%s\"\n", 1969 BACKSQL_IDARG(c_id->eid_id), 1970 BACKSQL_IDARG(c_id->eid_keyval), 1971 row.cols[ 3 ] ); 1972 1973 /* count candidates, for unchecked limit */ 1974 bsi->bsi_n_candidates--; 1975 if ( bsi->bsi_n_candidates == -1 ) { 1976 break; 1977 } 1978 continue; 1979 1980 cleanup:; 1981 if ( !BER_BVISNULL( &pdn ) ) { 1982 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx ); 1983 } 1984 if ( !BER_BVISNULL( &ndn ) ) { 1985 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); 1986 } 1987 if ( c_id != NULL ) { 1988 ch_free( c_id ); 1989 } 1990 } 1991 backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx ); 1992 SQLFreeStmt( sth, SQL_DROP ); 1993 1994 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates(): %d\n", 1995 n_candidates - bsi->bsi_n_candidates, 0, 0 ); 1996 1997 return ( bsi->bsi_n_candidates == -1 ? BACKSQL_AVL_STOP : BACKSQL_AVL_CONTINUE ); 1998 } 1999 2000 int 2001 backsql_search( Operation *op, SlapReply *rs ) 2002 { 2003 backsql_info *bi = (backsql_info *)op->o_bd->be_private; 2004 SQLHDBC dbh = SQL_NULL_HDBC; 2005 int sres; 2006 Entry user_entry = { 0 }, 2007 base_entry = { 0 }; 2008 int manageDSAit = get_manageDSAit( op ); 2009 time_t stoptime = 0; 2010 backsql_srch_info bsi = { 0 }; 2011 backsql_entryID *eid = NULL; 2012 struct berval nbase = BER_BVNULL; 2013 #ifndef BACKSQL_ARBITRARY_KEY 2014 ID lastid = 0; 2015 #endif /* ! BACKSQL_ARBITRARY_KEY */ 2016 2017 Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): " 2018 "base=\"%s\", filter=\"%s\", scope=%d,", 2019 op->o_req_ndn.bv_val, 2020 op->ors_filterstr.bv_val, 2021 op->ors_scope ); 2022 Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, " 2023 "attributes to load: %s\n", 2024 op->ors_deref, 2025 op->ors_attrsonly, 2026 op->ors_attrs == NULL ? "all" : "custom list" ); 2027 2028 if ( op->o_req_ndn.bv_len > BACKSQL_MAX_DN_LEN ) { 2029 Debug( LDAP_DEBUG_TRACE, "backsql_search(): " 2030 "search base length (%ld) exceeds max length (%d)\n", 2031 op->o_req_ndn.bv_len, BACKSQL_MAX_DN_LEN, 0 ); 2032 /* 2033 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate 2034 * since it is impossible that such a long DN exists 2035 * in the backend 2036 */ 2037 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 2038 send_ldap_result( op, rs ); 2039 return 1; 2040 } 2041 2042 sres = backsql_get_db_conn( op, &dbh ); 2043 if ( sres != LDAP_SUCCESS ) { 2044 Debug( LDAP_DEBUG_TRACE, "backsql_search(): " 2045 "could not get connection handle - exiting\n", 2046 0, 0, 0 ); 2047 rs->sr_err = sres; 2048 rs->sr_text = sres == LDAP_OTHER ? "SQL-backend error" : NULL; 2049 send_ldap_result( op, rs ); 2050 return 1; 2051 } 2052 2053 /* compute it anyway; root does not use it */ 2054 stoptime = op->o_time + op->ors_tlimit; 2055 2056 /* init search */ 2057 bsi.bsi_e = &base_entry; 2058 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, 2059 op->ors_scope, 2060 stoptime, op->ors_filter, 2061 dbh, op, rs, op->ors_attrs, 2062 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); 2063 switch ( rs->sr_err ) { 2064 case LDAP_SUCCESS: 2065 break; 2066 2067 case LDAP_REFERRAL: 2068 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && 2069 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) ) 2070 { 2071 rs->sr_err = LDAP_SUCCESS; 2072 rs->sr_text = NULL; 2073 rs->sr_matched = NULL; 2074 if ( rs->sr_ref ) { 2075 ber_bvarray_free( rs->sr_ref ); 2076 rs->sr_ref = NULL; 2077 } 2078 break; 2079 } 2080 2081 /* an entry was created; free it */ 2082 entry_clean( bsi.bsi_e ); 2083 2084 /* fall thru */ 2085 2086 default: 2087 if ( !BER_BVISNULL( &base_entry.e_nname ) 2088 && !access_allowed( op, &base_entry, 2089 slap_schema.si_ad_entry, NULL, 2090 ACL_DISCLOSE, NULL ) ) 2091 { 2092 rs->sr_err = LDAP_NO_SUCH_OBJECT; 2093 if ( rs->sr_ref ) { 2094 ber_bvarray_free( rs->sr_ref ); 2095 rs->sr_ref = NULL; 2096 } 2097 rs->sr_matched = NULL; 2098 rs->sr_text = NULL; 2099 } 2100 2101 send_ldap_result( op, rs ); 2102 2103 if ( rs->sr_ref ) { 2104 ber_bvarray_free( rs->sr_ref ); 2105 rs->sr_ref = NULL; 2106 } 2107 2108 if ( !BER_BVISNULL( &base_entry.e_nname ) ) { 2109 entry_clean( &base_entry ); 2110 } 2111 2112 goto done; 2113 } 2114 /* NOTE: __NEW__ "search" access is required 2115 * on searchBase object */ 2116 { 2117 slap_mask_t mask; 2118 2119 if ( get_assert( op ) && 2120 ( test_filter( op, &base_entry, get_assertion( op ) ) 2121 != LDAP_COMPARE_TRUE ) ) 2122 { 2123 rs->sr_err = LDAP_ASSERTION_FAILED; 2124 2125 } 2126 if ( ! access_allowed_mask( op, &base_entry, 2127 slap_schema.si_ad_entry, 2128 NULL, ACL_SEARCH, NULL, &mask ) ) 2129 { 2130 if ( rs->sr_err == LDAP_SUCCESS ) { 2131 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 2132 } 2133 } 2134 2135 if ( rs->sr_err != LDAP_SUCCESS ) { 2136 if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) { 2137 rs->sr_err = LDAP_NO_SUCH_OBJECT; 2138 rs->sr_text = NULL; 2139 } 2140 send_ldap_result( op, rs ); 2141 goto done; 2142 } 2143 } 2144 2145 bsi.bsi_e = NULL; 2146 2147 bsi.bsi_n_candidates = 2148 ( op->ors_limit == NULL /* isroot == TRUE */ ? -2 : 2149 ( op->ors_limit->lms_s_unchecked == -1 ? -2 : 2150 ( op->ors_limit->lms_s_unchecked ) ) ); 2151 2152 #ifndef BACKSQL_ARBITRARY_KEY 2153 /* If paged results are in effect, check the paging cookie */ 2154 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { 2155 rs->sr_err = parse_paged_cookie( op, rs ); 2156 if ( rs->sr_err != LDAP_SUCCESS ) { 2157 send_ldap_result( op, rs ); 2158 goto done; 2159 } 2160 } 2161 #endif /* ! BACKSQL_ARBITRARY_KEY */ 2162 2163 switch ( bsi.bsi_scope ) { 2164 case LDAP_SCOPE_BASE: 2165 case BACKSQL_SCOPE_BASE_LIKE: 2166 /* 2167 * probably already found... 2168 */ 2169 bsi.bsi_id_list = &bsi.bsi_base_id; 2170 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next; 2171 break; 2172 2173 case LDAP_SCOPE_SUBTREE: 2174 /* 2175 * if baseObject is defined, and if it is the root 2176 * of the search, add it to the candidate list 2177 */ 2178 if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &bsi.bsi_base_id.eid_id ) ) 2179 { 2180 bsi.bsi_id_list = &bsi.bsi_base_id; 2181 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next; 2182 } 2183 2184 /* FALLTHRU */ 2185 default: 2186 2187 /* 2188 * for each objectclass we try to construct query which gets IDs 2189 * of entries matching LDAP query filter and scope (or at least 2190 * candidates), and get the IDs. Do this in ID order for paging. 2191 */ 2192 avl_apply( bi->sql_oc_by_id, backsql_oc_get_candidates, 2193 &bsi, BACKSQL_AVL_STOP, AVL_INORDER ); 2194 2195 /* check for abandon */ 2196 if ( op->o_abandon ) { 2197 eid = bsi.bsi_id_list; 2198 rs->sr_err = SLAPD_ABANDON; 2199 goto send_results; 2200 } 2201 } 2202 2203 if ( op->ors_limit != NULL /* isroot == FALSE */ 2204 && op->ors_limit->lms_s_unchecked != -1 2205 && bsi.bsi_n_candidates == -1 ) 2206 { 2207 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 2208 send_ldap_result( op, rs ); 2209 goto done; 2210 } 2211 2212 /* 2213 * now we load candidate entries (only those attributes 2214 * mentioned in attrs and filter), test it against full filter 2215 * and then send to client; don't free entry_id if baseObject... 2216 */ 2217 for ( eid = bsi.bsi_id_list; 2218 eid != NULL; 2219 eid = backsql_free_entryID( 2220 eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) ) 2221 { 2222 int rc; 2223 Attribute *a_hasSubordinate = NULL, 2224 *a_entryUUID = NULL, 2225 *a_entryCSN = NULL, 2226 **ap = NULL; 2227 Entry *e = NULL; 2228 2229 /* check for abandon */ 2230 if ( op->o_abandon ) { 2231 rs->sr_err = SLAPD_ABANDON; 2232 goto send_results; 2233 } 2234 2235 /* check time limit */ 2236 if ( op->ors_tlimit != SLAP_NO_LIMIT 2237 && slap_get_time() > stoptime ) 2238 { 2239 rs->sr_err = LDAP_TIMELIMIT_EXCEEDED; 2240 rs->sr_ctrls = NULL; 2241 rs->sr_ref = rs->sr_v2ref; 2242 goto send_results; 2243 } 2244 2245 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data " 2246 "for entry id=" BACKSQL_IDFMT " oc_id=" BACKSQL_IDNUMFMT ", keyval=" BACKSQL_IDFMT "\n", 2247 BACKSQL_IDARG(eid->eid_id), 2248 eid->eid_oc_id, 2249 BACKSQL_IDARG(eid->eid_keyval) ); 2250 2251 /* check scope */ 2252 switch ( op->ors_scope ) { 2253 case LDAP_SCOPE_BASE: 2254 case BACKSQL_SCOPE_BASE_LIKE: 2255 if ( !dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) { 2256 goto next_entry2; 2257 } 2258 break; 2259 2260 case LDAP_SCOPE_ONE: 2261 { 2262 struct berval rdn = eid->eid_ndn; 2263 2264 rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," ); 2265 if ( !dnIsOneLevelRDN( &rdn ) ) { 2266 goto next_entry2; 2267 } 2268 /* fall thru */ 2269 } 2270 2271 case LDAP_SCOPE_SUBORDINATE: 2272 /* discard the baseObject entry */ 2273 if ( dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) { 2274 goto next_entry2; 2275 } 2276 /* FALLTHRU */ 2277 case LDAP_SCOPE_SUBTREE: 2278 /* FIXME: this should never fail... */ 2279 if ( !dnIsSuffix( &eid->eid_ndn, &op->o_req_ndn ) ) { 2280 goto next_entry2; 2281 } 2282 break; 2283 } 2284 2285 if ( BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) { 2286 /* don't recollect baseObject... */ 2287 e = bi->sql_baseObject; 2288 2289 } else if ( eid == &bsi.bsi_base_id ) { 2290 /* don't recollect searchBase object... */ 2291 e = &base_entry; 2292 2293 } else { 2294 bsi.bsi_e = &user_entry; 2295 rc = backsql_id2entry( &bsi, eid ); 2296 if ( rc != LDAP_SUCCESS ) { 2297 Debug( LDAP_DEBUG_TRACE, "backsql_search(): " 2298 "error %d in backsql_id2entry() " 2299 "- skipping\n", rc, 0, 0 ); 2300 continue; 2301 } 2302 e = &user_entry; 2303 } 2304 2305 if ( !manageDSAit && 2306 op->ors_scope != LDAP_SCOPE_BASE && 2307 op->ors_scope != BACKSQL_SCOPE_BASE_LIKE && 2308 is_entry_referral( e ) ) 2309 { 2310 BerVarray refs; 2311 2312 refs = get_entry_referrals( op, e ); 2313 if ( !refs ) { 2314 backsql_srch_info bsi2 = { 0 }; 2315 Entry user_entry2 = { 0 }; 2316 2317 /* retry with the full entry... */ 2318 bsi2.bsi_e = &user_entry2; 2319 rc = backsql_init_search( &bsi2, 2320 &e->e_nname, 2321 LDAP_SCOPE_BASE, 2322 (time_t)(-1), NULL, 2323 dbh, op, rs, NULL, 2324 BACKSQL_ISF_GET_ENTRY ); 2325 if ( rc == LDAP_SUCCESS ) { 2326 if ( is_entry_referral( &user_entry2 ) ) 2327 { 2328 refs = get_entry_referrals( op, 2329 &user_entry2 ); 2330 } else { 2331 rs->sr_err = LDAP_OTHER; 2332 } 2333 backsql_entry_clean( op, &user_entry2 ); 2334 } 2335 if ( bsi2.bsi_attrs != NULL ) { 2336 op->o_tmpfree( bsi2.bsi_attrs, 2337 op->o_tmpmemctx ); 2338 } 2339 } 2340 2341 if ( refs ) { 2342 rs->sr_ref = referral_rewrite( refs, 2343 &e->e_name, 2344 &op->o_req_dn, 2345 op->ors_scope ); 2346 ber_bvarray_free( refs ); 2347 } 2348 2349 if ( rs->sr_ref ) { 2350 rs->sr_err = LDAP_REFERRAL; 2351 2352 } else { 2353 rs->sr_text = "bad referral object"; 2354 } 2355 2356 rs->sr_entry = e; 2357 rs->sr_matched = user_entry.e_name.bv_val; 2358 send_search_reference( op, rs ); 2359 2360 ber_bvarray_free( rs->sr_ref ); 2361 rs->sr_ref = NULL; 2362 rs->sr_matched = NULL; 2363 rs->sr_entry = NULL; 2364 if ( rs->sr_err == LDAP_REFERRAL ) { 2365 rs->sr_err = LDAP_SUCCESS; 2366 } 2367 2368 goto next_entry; 2369 } 2370 2371 /* 2372 * We use this flag since we need to parse the filter 2373 * anyway; we should have used the frontend API function 2374 * filter_has_subordinates() 2375 */ 2376 if ( bsi.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) { 2377 rc = backsql_has_children( op, dbh, &e->e_nname ); 2378 2379 switch ( rc ) { 2380 case LDAP_COMPARE_TRUE: 2381 case LDAP_COMPARE_FALSE: 2382 a_hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE ); 2383 if ( a_hasSubordinate != NULL ) { 2384 for ( ap = &user_entry.e_attrs; 2385 *ap; 2386 ap = &(*ap)->a_next ); 2387 2388 *ap = a_hasSubordinate; 2389 } 2390 rc = 0; 2391 break; 2392 2393 default: 2394 Debug(LDAP_DEBUG_TRACE, 2395 "backsql_search(): " 2396 "has_children failed( %d)\n", 2397 rc, 0, 0 ); 2398 rc = 1; 2399 goto next_entry; 2400 } 2401 } 2402 2403 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYUUID ) { 2404 a_entryUUID = backsql_operational_entryUUID( bi, eid ); 2405 if ( a_entryUUID != NULL ) { 2406 if ( ap == NULL ) { 2407 ap = &user_entry.e_attrs; 2408 } 2409 2410 for ( ; *ap; ap = &(*ap)->a_next ); 2411 2412 *ap = a_entryUUID; 2413 } 2414 } 2415 2416 #ifdef BACKSQL_SYNCPROV 2417 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYCSN ) { 2418 a_entryCSN = backsql_operational_entryCSN( op ); 2419 if ( a_entryCSN != NULL ) { 2420 if ( ap == NULL ) { 2421 ap = &user_entry.e_attrs; 2422 } 2423 2424 for ( ; *ap; ap = &(*ap)->a_next ); 2425 2426 *ap = a_entryCSN; 2427 } 2428 } 2429 #endif /* BACKSQL_SYNCPROV */ 2430 2431 if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) 2432 { 2433 #ifndef BACKSQL_ARBITRARY_KEY 2434 /* If paged results are in effect, see if the page limit was exceeded */ 2435 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { 2436 if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) 2437 { 2438 e = NULL; 2439 send_paged_response( op, rs, &lastid ); 2440 goto done; 2441 } 2442 lastid = SQL_TO_PAGECOOKIE( eid->eid_id, eid->eid_oc_id ); 2443 } 2444 #endif /* ! BACKSQL_ARBITRARY_KEY */ 2445 rs->sr_attrs = op->ors_attrs; 2446 rs->sr_operational_attrs = NULL; 2447 rs->sr_entry = e; 2448 e->e_private = (void *)eid; 2449 rs->sr_flags = ( e == &user_entry ) ? REP_ENTRY_MODIFIABLE : 0; 2450 /* FIXME: need the whole entry (ITS#3480) */ 2451 rs->sr_err = send_search_entry( op, rs ); 2452 e->e_private = NULL; 2453 rs->sr_entry = NULL; 2454 rs->sr_attrs = NULL; 2455 rs->sr_operational_attrs = NULL; 2456 2457 switch ( rs->sr_err ) { 2458 case LDAP_UNAVAILABLE: 2459 /* 2460 * FIXME: send_search_entry failed; 2461 * better stop 2462 */ 2463 Debug( LDAP_DEBUG_TRACE, "backsql_search(): " 2464 "connection lost\n", 0, 0, 0 ); 2465 goto end_of_search; 2466 2467 case LDAP_SIZELIMIT_EXCEEDED: 2468 case LDAP_BUSY: 2469 goto send_results; 2470 } 2471 } 2472 2473 next_entry:; 2474 if ( e == &user_entry ) { 2475 backsql_entry_clean( op, &user_entry ); 2476 } 2477 2478 next_entry2:; 2479 } 2480 2481 end_of_search:; 2482 if ( rs->sr_nentries > 0 ) { 2483 rs->sr_ref = rs->sr_v2ref; 2484 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS 2485 : LDAP_REFERRAL; 2486 2487 } else { 2488 rs->sr_err = bsi.bsi_status; 2489 } 2490 2491 send_results:; 2492 if ( rs->sr_err != SLAPD_ABANDON ) { 2493 #ifndef BACKSQL_ARBITRARY_KEY 2494 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { 2495 send_paged_response( op, rs, NULL ); 2496 } else 2497 #endif /* ! BACKSQL_ARBITRARY_KEY */ 2498 { 2499 send_ldap_result( op, rs ); 2500 } 2501 } 2502 2503 /* cleanup in case of abandon */ 2504 for ( ; eid != NULL; 2505 eid = backsql_free_entryID( 2506 eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) ) 2507 ; 2508 2509 backsql_entry_clean( op, &base_entry ); 2510 2511 /* in case we got here accidentally */ 2512 backsql_entry_clean( op, &user_entry ); 2513 2514 if ( rs->sr_v2ref ) { 2515 ber_bvarray_free( rs->sr_v2ref ); 2516 rs->sr_v2ref = NULL; 2517 } 2518 2519 #ifdef BACKSQL_SYNCPROV 2520 if ( op->o_sync ) { 2521 Operation op2 = *op; 2522 SlapReply rs2 = { REP_RESULT }; 2523 Entry *e = entry_alloc(); 2524 slap_callback cb = { 0 }; 2525 2526 op2.o_tag = LDAP_REQ_ADD; 2527 op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0 ); 2528 op2.ora_e = e; 2529 op2.o_callback = &cb; 2530 2531 ber_dupbv( &e->e_name, op->o_bd->be_suffix ); 2532 ber_dupbv( &e->e_nname, op->o_bd->be_nsuffix ); 2533 2534 cb.sc_response = slap_null_cb; 2535 2536 op2.o_bd->be_add( &op2, &rs2 ); 2537 2538 if ( op2.ora_e == e ) 2539 entry_free( e ); 2540 } 2541 #endif /* BACKSQL_SYNCPROV */ 2542 2543 done:; 2544 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); 2545 2546 if ( bsi.bsi_attrs != NULL ) { 2547 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx ); 2548 } 2549 2550 if ( !BER_BVISNULL( &nbase ) 2551 && nbase.bv_val != op->o_req_ndn.bv_val ) 2552 { 2553 ch_free( nbase.bv_val ); 2554 } 2555 2556 /* restore scope ... FIXME: this should be done before ANY 2557 * frontend call that uses op */ 2558 if ( op->ors_scope == BACKSQL_SCOPE_BASE_LIKE ) { 2559 op->ors_scope = LDAP_SCOPE_BASE; 2560 } 2561 2562 Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 ); 2563 2564 return rs->sr_err; 2565 } 2566 2567 /* return LDAP_SUCCESS IFF we can retrieve the specified entry. 2568 */ 2569 int 2570 backsql_entry_get( 2571 Operation *op, 2572 struct berval *ndn, 2573 ObjectClass *oc, 2574 AttributeDescription *at, 2575 int rw, 2576 Entry **ent ) 2577 { 2578 backsql_srch_info bsi = { 0 }; 2579 SQLHDBC dbh = SQL_NULL_HDBC; 2580 int rc; 2581 SlapReply rs = { 0 }; 2582 AttributeName anlist[ 2 ]; 2583 2584 *ent = NULL; 2585 2586 rc = backsql_get_db_conn( op, &dbh ); 2587 if ( rc != LDAP_SUCCESS ) { 2588 return rc; 2589 } 2590 2591 if ( at ) { 2592 anlist[ 0 ].an_name = at->ad_cname; 2593 anlist[ 0 ].an_desc = at; 2594 BER_BVZERO( &anlist[ 1 ].an_name ); 2595 } 2596 2597 bsi.bsi_e = entry_alloc(); 2598 rc = backsql_init_search( &bsi, 2599 ndn, 2600 LDAP_SCOPE_BASE, 2601 (time_t)(-1), NULL, 2602 dbh, op, &rs, at ? anlist : NULL, 2603 BACKSQL_ISF_GET_ENTRY ); 2604 2605 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { 2606 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); 2607 } 2608 2609 if ( rc == LDAP_SUCCESS ) { 2610 2611 #if 0 /* not supported at present */ 2612 /* find attribute values */ 2613 if ( is_entry_alias( bsi.bsi_e ) ) { 2614 Debug( LDAP_DEBUG_ACL, 2615 "<= backsql_entry_get: entry is an alias\n", 2616 0, 0, 0 ); 2617 rc = LDAP_ALIAS_PROBLEM; 2618 goto return_results; 2619 } 2620 #endif 2621 2622 if ( is_entry_referral( bsi.bsi_e ) ) { 2623 Debug( LDAP_DEBUG_ACL, 2624 "<= backsql_entry_get: entry is a referral\n", 2625 0, 0, 0 ); 2626 rc = LDAP_REFERRAL; 2627 goto return_results; 2628 } 2629 2630 if ( oc && !is_entry_objectclass( bsi.bsi_e, oc, 0 ) ) { 2631 Debug( LDAP_DEBUG_ACL, 2632 "<= backsql_entry_get: " 2633 "failed to find objectClass\n", 2634 0, 0, 0 ); 2635 rc = LDAP_NO_SUCH_ATTRIBUTE; 2636 goto return_results; 2637 } 2638 2639 *ent = bsi.bsi_e; 2640 } 2641 2642 return_results:; 2643 if ( bsi.bsi_attrs != NULL ) { 2644 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx ); 2645 } 2646 2647 if ( rc != LDAP_SUCCESS ) { 2648 if ( bsi.bsi_e ) { 2649 entry_free( bsi.bsi_e ); 2650 } 2651 } 2652 2653 return rc; 2654 } 2655 2656 void 2657 backsql_entry_clean( 2658 Operation *op, 2659 Entry *e ) 2660 { 2661 void *ctx; 2662 2663 ctx = ldap_pvt_thread_pool_context(); 2664 2665 if ( ctx == NULL || ctx != op->o_tmpmemctx ) { 2666 if ( !BER_BVISNULL( &e->e_name ) ) { 2667 op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx ); 2668 BER_BVZERO( &e->e_name ); 2669 } 2670 2671 if ( !BER_BVISNULL( &e->e_nname ) ) { 2672 op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx ); 2673 BER_BVZERO( &e->e_nname ); 2674 } 2675 } 2676 2677 entry_clean( e ); 2678 } 2679 2680 int 2681 backsql_entry_release( 2682 Operation *op, 2683 Entry *e, 2684 int rw ) 2685 { 2686 backsql_entry_clean( op, e ); 2687 2688 entry_free( e ); 2689 2690 return 0; 2691 } 2692 2693 #ifndef BACKSQL_ARBITRARY_KEY 2694 /* This function is copied verbatim from back-bdb/search.c */ 2695 static int 2696 parse_paged_cookie( Operation *op, SlapReply *rs ) 2697 { 2698 int rc = LDAP_SUCCESS; 2699 PagedResultsState *ps = op->o_pagedresults_state; 2700 2701 /* this function must be invoked only if the pagedResults 2702 * control has been detected, parsed and partially checked 2703 * by the frontend */ 2704 assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ); 2705 2706 /* cookie decoding/checks deferred to backend... */ 2707 if ( ps->ps_cookieval.bv_len ) { 2708 PagedResultsCookie reqcookie; 2709 if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) { 2710 /* bad cookie */ 2711 rs->sr_text = "paged results cookie is invalid"; 2712 rc = LDAP_PROTOCOL_ERROR; 2713 goto done; 2714 } 2715 2716 AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie )); 2717 2718 if ( reqcookie > ps->ps_cookie ) { 2719 /* bad cookie */ 2720 rs->sr_text = "paged results cookie is invalid"; 2721 rc = LDAP_PROTOCOL_ERROR; 2722 goto done; 2723 2724 } else if ( reqcookie < ps->ps_cookie ) { 2725 rs->sr_text = "paged results cookie is invalid or old"; 2726 rc = LDAP_UNWILLING_TO_PERFORM; 2727 goto done; 2728 } 2729 2730 } else { 2731 /* Initial request. Initialize state. */ 2732 ps->ps_cookie = 0; 2733 ps->ps_count = 0; 2734 } 2735 2736 done:; 2737 2738 return rc; 2739 } 2740 2741 /* This function is copied nearly verbatim from back-bdb/search.c */ 2742 static void 2743 send_paged_response( 2744 Operation *op, 2745 SlapReply *rs, 2746 ID *lastid ) 2747 { 2748 LDAPControl ctrl, *ctrls[2]; 2749 BerElementBuffer berbuf; 2750 BerElement *ber = (BerElement *)&berbuf; 2751 PagedResultsCookie respcookie; 2752 struct berval cookie; 2753 2754 Debug(LDAP_DEBUG_ARGS, 2755 "send_paged_response: lastid=0x%08lx nentries=%d\n", 2756 lastid ? *lastid : 0, rs->sr_nentries, NULL ); 2757 2758 BER_BVZERO( &ctrl.ldctl_value ); 2759 ctrls[0] = &ctrl; 2760 ctrls[1] = NULL; 2761 2762 ber_init2( ber, NULL, LBER_USE_DER ); 2763 2764 if ( lastid ) { 2765 respcookie = ( PagedResultsCookie )(*lastid); 2766 cookie.bv_len = sizeof( respcookie ); 2767 cookie.bv_val = (char *)&respcookie; 2768 2769 } else { 2770 respcookie = ( PagedResultsCookie )0; 2771 BER_BVSTR( &cookie, "" ); 2772 } 2773 2774 op->o_conn->c_pagedresults_state.ps_cookie = respcookie; 2775 op->o_conn->c_pagedresults_state.ps_count = 2776 ((PagedResultsState *)op->o_pagedresults_state)->ps_count + 2777 rs->sr_nentries; 2778 2779 /* return size of 0 -- no estimate */ 2780 ber_printf( ber, "{iO}", 0, &cookie ); 2781 2782 if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) { 2783 goto done; 2784 } 2785 2786 ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; 2787 ctrls[0]->ldctl_iscritical = 0; 2788 2789 rs->sr_ctrls = ctrls; 2790 rs->sr_err = LDAP_SUCCESS; 2791 send_ldap_result( op, rs ); 2792 rs->sr_ctrls = NULL; 2793 2794 done: 2795 (void) ber_free_buf( ber ); 2796 } 2797 #endif /* ! BACKSQL_ARBITRARY_KEY */ 2798