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