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