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