1/* $NetBSD: search.c,v 1.3 2021/08/14 16:14:59 christos Exp $ */ 2 3/* search.c - ldap backend search function */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1999-2021 The OpenLDAP Foundation. 8 * Portions Copyright 1999-2003 Howard Chu. 9 * Portions Copyright 2000-2003 Pierangelo Masarati. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted only as authorized by the OpenLDAP 14 * Public License. 15 * 16 * A copy of this license is available in the file LICENSE in the 17 * top-level directory of the distribution or, alternatively, at 18 * <http://www.OpenLDAP.org/license.html>. 19 */ 20/* ACKNOWLEDGEMENTS: 21 * This work was initially developed by the Howard Chu for inclusion 22 * in OpenLDAP Software and subsequently enhanced by Pierangelo 23 * Masarati. 24 */ 25 26#include <sys/cdefs.h> 27__RCSID("$NetBSD: search.c,v 1.3 2021/08/14 16:14:59 christos Exp $"); 28 29#include "portable.h" 30 31#include <stdio.h> 32 33#include <ac/socket.h> 34#include <ac/string.h> 35#include <ac/time.h> 36 37#include "slap.h" 38#include "back-ldap.h" 39#include "../../../libraries/liblber/lber-int.h" 40 41#include "lutil.h" 42 43static int 44ldap_build_entry( Operation *op, LDAPMessage *e, Entry *ent, 45 struct berval *bdn, int remove_unknown_schema ); 46 47 48static ObjectClass * 49oc_bvfind_undef_ex( struct berval *ocname, int flag ) 50{ 51 ObjectClass *oc = oc_bvfind( ocname ); 52 53 if ( oc || flag ) { 54 /* oc defined or remove-unknown-schema flag set */ 55 return oc; 56 } 57 58 return oc_bvfind_undef( ocname ); 59} 60 61 62/* 63 * replaces (&) with (objectClass=*) and (|) with (!(objectClass=*)) 64 * as the best replacement for RFC 4526 absolute true/absolute false 65 * filters; the only difference (AFAIK) is that they require search 66 * access to objectClass. 67 * 68 * filter->bv_val may be alloc'd on the thread's slab, if equal to 69 * op->ors_filterstr.bv_val, or realloc'd on the thread's slab otherwise. 70 */ 71static int 72ldap_back_munge_filter( 73 Operation *op, 74 struct berval *filter ) 75{ 76 char *ptr; 77 int gotit = 0; 78 79 Debug( LDAP_DEBUG_ARGS, "=> ldap_back_munge_filter \"%s\"\n", 80 filter->bv_val ); 81 82 for ( ptr = strchr( filter->bv_val, '(' ); 83 ptr; 84 ptr = strchr( ptr, '(' ) ) 85 { 86 static struct berval 87 bv_t = BER_BVC( "(&)" ), 88 bv_f = BER_BVC( "(|)" ), 89 bv_T = BER_BVC( "(objectClass=*)" ), 90 bv_F = BER_BVC( "(!(objectClass=*))" ); 91 struct berval *oldbv = NULL, 92 *newbv = NULL, 93 oldfilter = BER_BVNULL; 94 95 if ( ptr[2] != ')' ) { 96 ptr++; 97 continue; 98 } 99 100 switch ( ptr[1] ) { 101 case '&': 102 oldbv = &bv_t; 103 newbv = &bv_T; 104 break; 105 106 case '|': 107 oldbv = &bv_f; 108 newbv = &bv_F; 109 break; 110 111 default: 112 /* should be an error */ 113 continue; 114 } 115 116 oldfilter = *filter; 117 filter->bv_len += newbv->bv_len - oldbv->bv_len; 118 if ( filter->bv_val == op->ors_filterstr.bv_val ) { 119 filter->bv_val = op->o_tmpalloc( filter->bv_len + 1, 120 op->o_tmpmemctx ); 121 122 AC_MEMCPY( filter->bv_val, op->ors_filterstr.bv_val, 123 ptr - oldfilter.bv_val ); 124 125 } else { 126 filter->bv_val = op->o_tmprealloc( filter->bv_val, 127 filter->bv_len + 1, op->o_tmpmemctx ); 128 } 129 130 ptr = filter->bv_val + ( ptr - oldfilter.bv_val ); 131 132 AC_MEMCPY( &ptr[ newbv->bv_len ], 133 &ptr[ oldbv->bv_len ], 134 oldfilter.bv_len - ( ptr - filter->bv_val ) - oldbv->bv_len + 1 ); 135 AC_MEMCPY( ptr, newbv->bv_val, newbv->bv_len ); 136 137 ptr += newbv->bv_len; 138 139 gotit++; 140 } 141 142 Debug( LDAP_DEBUG_ARGS, "<= ldap_back_munge_filter \"%s\" (%d)\n", 143 filter->bv_val, gotit ); 144 145 return gotit; 146} 147 148int 149ldap_back_search( 150 Operation *op, 151 SlapReply *rs ) 152{ 153 ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private; 154 155 ldapconn_t *lc = NULL; 156 struct timeval tv; 157 time_t stoptime = (time_t)(-1); 158 LDAPMessage *res, 159 *e; 160 int rc = 0, 161 msgid; 162 struct berval match = BER_BVNULL, 163 filter = BER_BVNULL; 164 int i, x; 165 char **attrs = NULL; 166 int freetext = 0, filter_undef = 0; 167 int do_retry = 1, dont_retry = 0; 168 LDAPControl **ctrls = NULL; 169 char **references = NULL; 170 int remove_unknown_schema = 171 LDAP_BACK_OMIT_UNKNOWN_SCHEMA (li); 172 173 rs_assert_ready( rs ); 174 rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */ 175 176 if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) { 177 return rs->sr_err; 178 } 179 180 /* 181 * FIXME: in case of values return filter, we might want 182 * to map attrs and maybe rewrite value 183 */ 184 185 if ( op->ors_tlimit != SLAP_NO_LIMIT ) { 186 tv.tv_sec = op->ors_tlimit; 187 tv.tv_usec = 0; 188 stoptime = op->o_time + op->ors_tlimit; 189 190 } else { 191 LDAP_BACK_TV_SET( &tv ); 192 } 193 194 i = 0; 195 if ( op->ors_attrs ) { 196 for ( ; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ ) 197 /* just count attrs */ ; 198 } 199 200 x = 0; 201 if ( op->o_bd->be_extra_anlist ) { 202 for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) 203 /* just count attrs */ ; 204 } 205 206 if ( i > 0 || x > 0 ) { 207 int j = 0; 208 209 attrs = op->o_tmpalloc( ( i + x + 1 )*sizeof( char * ), 210 op->o_tmpmemctx ); 211 if ( attrs == NULL ) { 212 rs->sr_err = LDAP_NO_MEMORY; 213 rc = -1; 214 goto finish; 215 } 216 217 if ( i > 0 ) { 218 for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++, j++ ) { 219 attrs[ j ] = op->ors_attrs[i].an_name.bv_val; 220 } 221 } 222 223 if ( x > 0 ) { 224 for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++, j++ ) { 225 if ( op->o_bd->be_extra_anlist[x].an_desc && 226 ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, op->ors_attrs ) ) 227 { 228 continue; 229 } 230 231 attrs[ j ] = op->o_bd->be_extra_anlist[x].an_name.bv_val; 232 } 233 } 234 235 attrs[ j ] = NULL; 236 } 237 238 ctrls = op->o_ctrls; 239 rc = ldap_back_controls_add( op, rs, lc, &ctrls ); 240 if ( rc != LDAP_SUCCESS ) { 241 goto finish; 242 } 243 244 /* deal with <draft-zeilenga-ldap-t-f> filters */ 245 filter = op->ors_filterstr; 246retry: 247 /* this goes after retry because ldap_back_munge_filter() 248 * optionally replaces RFC 4526 T-F filters (&) (|) 249 * if already computed, they will be re-installed 250 * by filter2bv_undef_x() later */ 251 if ( !LDAP_BACK_T_F( li ) ) { 252 ldap_back_munge_filter( op, &filter ); 253 } 254 255 rs->sr_err = ldap_pvt_search( lc->lc_ld, op->o_req_dn.bv_val, 256 op->ors_scope, filter.bv_val, 257 attrs, op->ors_attrsonly, ctrls, NULL, 258 tv.tv_sec ? &tv : NULL, 259 op->ors_slimit, op->ors_deref, &msgid ); 260 261 ldap_pvt_thread_mutex_lock( &li->li_counter_mutex ); 262 ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_SEARCH ], 1 ); 263 ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex ); 264 265 if ( rs->sr_err != LDAP_SUCCESS ) { 266 switch ( rs->sr_err ) { 267 case LDAP_SERVER_DOWN: 268 if ( do_retry ) { 269 do_retry = 0; 270 if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) { 271 goto retry; 272 } 273 } 274 275 if ( lc == NULL ) { 276 /* reset by ldap_back_retry ... */ 277 rs->sr_err = slap_map_api2result( rs ); 278 279 } else { 280 rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_DONTSEND ); 281 } 282 283 goto finish; 284 285 case LDAP_FILTER_ERROR: 286 /* first try? */ 287 if ( !filter_undef && 288 strstr( filter.bv_val, "(?" ) && 289 !LDAP_BACK_NOUNDEFFILTER( li ) ) 290 { 291 BER_BVZERO( &filter ); 292 filter2bv_undef_x( op, op->ors_filter, 1, &filter ); 293 filter_undef = 1; 294 goto retry; 295 } 296 297 /* invalid filters return success with no data */ 298 rs->sr_err = LDAP_SUCCESS; 299 rs->sr_text = NULL; 300 goto finish; 301 302 default: 303 rs->sr_err = slap_map_api2result( rs ); 304 rs->sr_text = NULL; 305 goto finish; 306 } 307 } 308 309 /* if needed, initialize timeout */ 310 if ( li->li_timeout[ SLAP_OP_SEARCH ] ) { 311 if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) { 312 tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ]; 313 tv.tv_usec = 0; 314 } 315 } 316 317 /* We pull apart the ber result, stuff it into a slapd entry, and 318 * let send_search_entry stuff it back into ber format. Slow & ugly, 319 * but this is necessary for version matching, and for ACL processing. 320 */ 321 322 for ( rc = -2; rc != -1; rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ONE, &tv, &res ) ) 323 { 324 /* check for abandon */ 325 if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( lc ) ) { 326 if ( rc > 0 ) { 327 ldap_msgfree( res ); 328 } 329 (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND ); 330 rc = SLAPD_ABANDON; 331 goto finish; 332 } 333 334 if ( rc == 0 || rc == -2 ) { 335 ldap_pvt_thread_yield(); 336 337 /* check timeout */ 338 if ( li->li_timeout[ SLAP_OP_SEARCH ] ) { 339 if ( rc == 0 ) { 340 (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND ); 341 rs->sr_text = "Operation timed out"; 342 rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ? 343 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; 344 goto finish; 345 } 346 347 } else { 348 LDAP_BACK_TV_SET( &tv ); 349 } 350 351 /* check time limit */ 352 if ( op->ors_tlimit != SLAP_NO_LIMIT 353 && slap_get_time() > stoptime ) 354 { 355 (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND ); 356 rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED; 357 goto finish; 358 } 359 continue; 360 361 } else { 362 /* only touch when activity actually took place... */ 363 if ( li->li_idle_timeout ) { 364 lc->lc_time = op->o_time; 365 } 366 367 /* don't retry any more */ 368 dont_retry = 1; 369 } 370 371 372 if ( rc == LDAP_RES_SEARCH_ENTRY ) { 373 Entry ent = { 0 }; 374 struct berval bdn = BER_BVNULL; 375 376 do_retry = 0; 377 378 e = ldap_first_entry( lc->lc_ld, res ); 379 rc = ldap_build_entry( op, e, &ent, &bdn, 380 remove_unknown_schema); 381 if ( rc == LDAP_SUCCESS ) { 382 ldap_get_entry_controls( lc->lc_ld, res, &rs->sr_ctrls ); 383 rs->sr_entry = &ent; 384 rs->sr_attrs = op->ors_attrs; 385 rs->sr_operational_attrs = NULL; 386 rs->sr_flags = 0; 387 rs->sr_err = LDAP_SUCCESS; 388 rc = rs->sr_err = send_search_entry( op, rs ); 389 if ( rs->sr_ctrls ) { 390 ldap_controls_free( rs->sr_ctrls ); 391 rs->sr_ctrls = NULL; 392 } 393 rs->sr_entry = NULL; 394 rs->sr_flags = 0; 395 if ( !BER_BVISNULL( &ent.e_name ) ) { 396 assert( ent.e_name.bv_val != bdn.bv_val ); 397 op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx ); 398 BER_BVZERO( &ent.e_name ); 399 } 400 if ( !BER_BVISNULL( &ent.e_nname ) ) { 401 op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx ); 402 BER_BVZERO( &ent.e_nname ); 403 } 404 entry_clean( &ent ); 405 } 406 ldap_msgfree( res ); 407 switch ( rc ) { 408 case LDAP_SUCCESS: 409 case LDAP_INSUFFICIENT_ACCESS: 410 break; 411 412 default: 413 if ( rc == LDAP_UNAVAILABLE ) { 414 rc = rs->sr_err = LDAP_OTHER; 415 } else { 416 (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND ); 417 } 418 goto finish; 419 } 420 421 } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) { 422 if ( LDAP_BACK_NOREFS( li ) ) { 423 ldap_msgfree( res ); 424 continue; 425 } 426 427 do_retry = 0; 428 rc = ldap_parse_reference( lc->lc_ld, res, 429 &references, &rs->sr_ctrls, 1 ); 430 431 if ( rc != LDAP_SUCCESS ) { 432 continue; 433 } 434 435 /* FIXME: there MUST be at least one */ 436 if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) { 437 int cnt; 438 439 for ( cnt = 0; references[ cnt ]; cnt++ ) 440 /* NO OP */ ; 441 442 /* FIXME: there MUST be at least one */ 443 rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ), 444 op->o_tmpmemctx ); 445 446 for ( cnt = 0; references[ cnt ]; cnt++ ) { 447 ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] ); 448 } 449 BER_BVZERO( &rs->sr_ref[ cnt ] ); 450 451 /* ignore return value by now */ 452 RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) ); 453 rs->sr_entry = NULL; 454 ( void )send_search_reference( op, rs ); 455 456 } else { 457 Debug( LDAP_DEBUG_ANY, 458 "%s ldap_back_search: " 459 "got SEARCH_REFERENCE " 460 "with no referrals\n", 461 op->o_log_prefix ); 462 } 463 464 /* cleanup */ 465 if ( references ) { 466 ber_memvfree( (void **)references ); 467 op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); 468 rs->sr_ref = NULL; 469 references = NULL; 470 } 471 472 if ( rs->sr_ctrls ) { 473 ldap_controls_free( rs->sr_ctrls ); 474 rs->sr_ctrls = NULL; 475 } 476 477 } else if ( rc == LDAP_RES_INTERMEDIATE ) { 478 /* FIXME: response controls 479 * are passed without checks */ 480 rc = ldap_parse_intermediate( lc->lc_ld, 481 res, 482 (char **)&rs->sr_rspoid, 483 &rs->sr_rspdata, 484 &rs->sr_ctrls, 485 0 ); 486 if ( rc != LDAP_SUCCESS ) { 487 continue; 488 } 489 490 slap_send_ldap_intermediate( op, rs ); 491 492 if ( rs->sr_rspoid != NULL ) { 493 ber_memfree( (char *)rs->sr_rspoid ); 494 rs->sr_rspoid = NULL; 495 } 496 497 if ( rs->sr_rspdata != NULL ) { 498 ber_bvfree( rs->sr_rspdata ); 499 rs->sr_rspdata = NULL; 500 } 501 502 if ( rs->sr_ctrls != NULL ) { 503 ldap_controls_free( rs->sr_ctrls ); 504 rs->sr_ctrls = NULL; 505 } 506 507 } else { 508 char *err = NULL; 509 510 rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err, 511 &match.bv_val, &err, 512 &references, &rs->sr_ctrls, 1 ); 513 if ( rc == LDAP_SUCCESS ) { 514 if ( err ) { 515 rs->sr_text = err; 516 freetext = 1; 517 } 518 } else { 519 rs->sr_err = rc; 520 } 521 rs->sr_err = slap_map_api2result( rs ); 522 523 /* RFC 4511: referrals can only appear 524 * if result code is LDAP_REFERRAL */ 525 if ( references 526 && references[ 0 ] 527 && references[ 0 ][ 0 ] ) 528 { 529 if ( rs->sr_err != LDAP_REFERRAL ) { 530 Debug( LDAP_DEBUG_ANY, 531 "%s ldap_back_search: " 532 "got referrals with err=%d\n", 533 op->o_log_prefix, 534 rs->sr_err ); 535 536 } else { 537 int cnt; 538 539 for ( cnt = 0; references[ cnt ]; cnt++ ) 540 /* NO OP */ ; 541 542 rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ), 543 op->o_tmpmemctx ); 544 545 for ( cnt = 0; references[ cnt ]; cnt++ ) { 546 /* duplicating ...*/ 547 ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] ); 548 } 549 BER_BVZERO( &rs->sr_ref[ cnt ] ); 550 } 551 552 } else if ( rs->sr_err == LDAP_REFERRAL ) { 553 Debug( LDAP_DEBUG_ANY, 554 "%s ldap_back_search: " 555 "got err=%d with null " 556 "or empty referrals\n", 557 op->o_log_prefix, 558 rs->sr_err ); 559 560 rs->sr_err = LDAP_NO_SUCH_OBJECT; 561 } 562 563 if ( match.bv_val != NULL ) { 564 match.bv_len = strlen( match.bv_val ); 565 } 566 567 rc = 0; 568 break; 569 } 570 571 /* if needed, restore timeout */ 572 if ( li->li_timeout[ SLAP_OP_SEARCH ] ) { 573 if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) { 574 tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ]; 575 tv.tv_usec = 0; 576 } 577 } 578 } 579 580 if ( rc == -1 ) { 581 if ( dont_retry == 0 ) { 582 if ( do_retry ) { 583 do_retry = 0; 584 if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) { 585 goto retry; 586 } 587 } 588 589 rs->sr_err = LDAP_SERVER_DOWN; 590 rs->sr_err = slap_map_api2result( rs ); 591 goto finish; 592 593 } else if ( LDAP_BACK_ONERR_STOP( li ) ) { 594 /* if onerr == STOP */ 595 rs->sr_err = LDAP_SERVER_DOWN; 596 rs->sr_err = slap_map_api2result( rs ); 597 goto finish; 598 } 599 } 600 601 /* 602 * Rewrite the matched portion of the search base, if required 603 */ 604 if ( !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) { 605 struct berval pmatch; 606 607 if ( dnPretty( NULL, &match, &pmatch, op->o_tmpmemctx ) != LDAP_SUCCESS ) { 608 pmatch.bv_val = match.bv_val; 609 match.bv_val = NULL; 610 } 611 rs->sr_matched = pmatch.bv_val; 612 rs->sr_flags |= REP_MATCHED_MUSTBEFREED; 613 } 614 615finish:; 616 if ( !BER_BVISNULL( &match ) ) { 617 ber_memfree( match.bv_val ); 618 } 619 620 if ( rs->sr_v2ref ) { 621 rs->sr_err = LDAP_REFERRAL; 622 } 623 624 if ( LDAP_BACK_QUARANTINE( li ) ) { 625 ldap_back_quarantine( op, rs ); 626 } 627 628 if ( filter.bv_val != op->ors_filterstr.bv_val ) { 629 op->o_tmpfree( filter.bv_val, op->o_tmpmemctx ); 630 } 631 632#if 0 633 /* let send_ldap_result play cleanup handlers (ITS#4645) */ 634 if ( rc != SLAPD_ABANDON ) 635#endif 636 { 637 send_ldap_result( op, rs ); 638 } 639 640 (void)ldap_back_controls_free( op, rs, &ctrls ); 641 642 if ( rs->sr_ctrls ) { 643 ldap_controls_free( rs->sr_ctrls ); 644 rs->sr_ctrls = NULL; 645 } 646 647 if ( rs->sr_text ) { 648 if ( freetext ) { 649 ber_memfree( (char *)rs->sr_text ); 650 } 651 rs->sr_text = NULL; 652 } 653 654 if ( rs->sr_ref ) { 655 op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); 656 rs->sr_ref = NULL; 657 } 658 659 if ( references ) { 660 ber_memvfree( (void **)references ); 661 } 662 663 if ( attrs ) { 664 op->o_tmpfree( attrs, op->o_tmpmemctx ); 665 } 666 667 if ( lc != NULL ) { 668 ldap_back_release_conn( li, lc ); 669 } 670 671 if ( rs->sr_err == LDAP_UNAVAILABLE && 672 /* if we originally bound and wanted rebind-as-user, must drop 673 * the connection now because we just discarded the credentials. 674 * ITS#7464, #8142 675 */ 676 LDAP_BACK_SAVECRED( li ) && SLAP_IS_AUTHZ_BACKEND( op ) ) 677 rs->sr_err = SLAPD_DISCONNECT; 678 return rs->sr_err; 679} 680 681static int 682ldap_build_entry( 683 Operation *op, 684 LDAPMessage *e, 685 Entry *ent, 686 struct berval *bdn, 687 int remove_unknown_schema) 688{ 689 struct berval a; 690 BerElement ber = *ldap_get_message_ber( e ); 691 Attribute *attr, **attrp; 692 const char *text; 693 int last; 694 char *lastb; 695 ber_len_t len; 696 697 /* safe assumptions ... */ 698 assert( ent != NULL ); 699 BER_BVZERO( &ent->e_bv ); 700 701 if ( ber_scanf( &ber, "{m", bdn ) == LBER_ERROR ) { 702 return LDAP_DECODING_ERROR; 703 } 704 705 /* 706 * Note: this may fail if the target host(s) schema differs 707 * from the one known to the meta, and a DN with unknown 708 * attributes is returned. 709 * 710 * FIXME: should we log anything, or delegate to dnNormalize? 711 */ 712 /* Note: if the distinguished values or the naming attributes 713 * change, should we massage them as well? 714 */ 715 if ( dnPrettyNormal( NULL, bdn, &ent->e_name, &ent->e_nname, 716 op->o_tmpmemctx ) != LDAP_SUCCESS ) 717 { 718 return LDAP_INVALID_DN_SYNTAX; 719 } 720 721 ent->e_attrs = NULL; 722 if ( ber_first_element( &ber, &len, &lastb ) != LBER_SEQUENCE ) { 723 return LDAP_SUCCESS; 724 } 725 726 attrp = &ent->e_attrs; 727 while ( ber_next_element( &ber, &len, lastb ) == LBER_SEQUENCE && 728 ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { 729 int i; 730 slap_syntax_validate_func *validate; 731 slap_syntax_transform_func *pretty; 732 733 attr = attr_alloc( NULL ); 734 if ( attr == NULL ) { 735 return LDAP_OTHER; 736 } 737 if ( slap_bv2ad( &a, &attr->a_desc, &text ) 738 != LDAP_SUCCESS ) 739 { 740 if ( slap_bv2undef_ad( &a, &attr->a_desc, &text, 741 (remove_unknown_schema ? SLAP_AD_NOINSERT : SLAP_AD_PROXIED )) != LDAP_SUCCESS ) 742 { 743 Debug( LDAP_DEBUG_ANY, 744 "%s ldap_build_entry: " 745 "slap_bv2undef_ad(%s): %s\n", 746 op->o_log_prefix, a.bv_val, text ); 747 748 ( void )ber_scanf( &ber, "x" /* [W] */ ); 749 attr_free( attr ); 750 continue; 751 } 752 } 753 754 /* no subschemaSubentry */ 755 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry 756 || attr->a_desc == slap_schema.si_ad_entryDN ) 757 { 758 759 /* 760 * We eat target's subschemaSubentry because 761 * a search for this value is likely not 762 * to resolve to the appropriate backend; 763 * later, the local subschemaSubentry is 764 * added. 765 * 766 * We also eat entryDN because the frontend 767 * will reattach it without checking if already 768 * present... 769 */ 770 ( void )ber_scanf( &ber, "x" /* [W] */ ); 771 attr_free( attr ); 772 continue; 773 } 774 775 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR 776 || attr->a_vals == NULL ) 777 { 778 /* 779 * Note: attr->a_vals can be null when using 780 * values result filter 781 */ 782 attr->a_vals = (struct berval *)&slap_dummy_bv; 783 } 784 785 validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate; 786 pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty; 787 788 if ( !validate && !pretty ) { 789 attr->a_nvals = NULL; 790 attr_free( attr ); 791 goto next_attr; 792 } 793 794 for ( i = 0; !BER_BVISNULL( &attr->a_vals[i] ); i++ ) ; 795 last = i; 796 797 /* 798 * check that each value is valid per syntax 799 * and pretty if appropriate 800 */ 801 for ( i = 0; i<last; i++ ) { 802 struct berval pval; 803 int rc; 804 805 if ( pretty ) { 806 rc = ordered_value_pretty( attr->a_desc, 807 &attr->a_vals[i], &pval, NULL ); 808 809 } else { 810 rc = ordered_value_validate( attr->a_desc, 811 &attr->a_vals[i], 0 ); 812 } 813 814 if ( rc != LDAP_SUCCESS ) { 815 ObjectClass *oc; 816 817 /* check if, by chance, it's an undefined objectClass */ 818 if ( attr->a_desc == slap_schema.si_ad_objectClass && 819 ( oc = oc_bvfind_undef_ex( &attr->a_vals[i], 820 remove_unknown_schema ) ) != NULL ) 821 { 822 ber_dupbv( &pval, &oc->soc_cname ); 823 rc = LDAP_SUCCESS; 824 825 } else { 826 ber_memfree( attr->a_vals[i].bv_val ); 827 if ( --last == i ) { 828 BER_BVZERO( &attr->a_vals[i] ); 829 break; 830 } 831 attr->a_vals[i] = attr->a_vals[last]; 832 BER_BVZERO( &attr->a_vals[last] ); 833 i--; 834 } 835 } 836 837 if ( rc == LDAP_SUCCESS && pretty ) { 838 ber_memfree( attr->a_vals[i].bv_val ); 839 attr->a_vals[i] = pval; 840 } 841 } 842 attr->a_numvals = last = i; 843 if ( last == 0 && attr->a_vals != &slap_dummy_bv ) { 844 attr->a_nvals = NULL; 845 attr_free( attr ); 846 goto next_attr; 847 } 848 849 if ( last && attr->a_desc->ad_type->sat_equality && 850 attr->a_desc->ad_type->sat_equality->smr_normalize ) 851 { 852 attr->a_nvals = ch_malloc( ( last + 1 )*sizeof( struct berval ) ); 853 for ( i = 0; i < last; i++ ) { 854 int rc; 855 856 rc = ordered_value_normalize( 857 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 858 attr->a_desc, 859 attr->a_desc->ad_type->sat_equality, 860 &attr->a_vals[i], &attr->a_nvals[i], 861 NULL ); 862 863 if ( rc != LDAP_SUCCESS ) { 864 ber_memfree( attr->a_vals[i].bv_val ); 865 if ( --last == i ) { 866 BER_BVZERO( &attr->a_vals[i] ); 867 break; 868 } 869 attr->a_vals[i] = attr->a_vals[last]; 870 BER_BVZERO( &attr->a_vals[last] ); 871 i--; 872 } 873 } 874 BER_BVZERO( &attr->a_nvals[i] ); 875 if ( last == 0 ) { 876 attr_free( attr ); 877 goto next_attr; 878 } 879 880 } else { 881 attr->a_nvals = attr->a_vals; 882 } 883 884 attr->a_numvals = last; 885 886 /* Handle sorted vals, strip dups but keep the attr */ 887 if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) { 888 while ( attr->a_numvals > 1 ) { 889 int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx ); 890 if ( rc != LDAP_TYPE_OR_VALUE_EXISTS ) 891 break; 892 893 /* Strip duplicate values */ 894 if ( attr->a_nvals != attr->a_vals ) 895 ber_memfree( attr->a_nvals[i].bv_val ); 896 ber_memfree( attr->a_vals[i].bv_val ); 897 attr->a_numvals--; 898 899 assert( i >= 0 ); 900 if ( (unsigned)i < attr->a_numvals ) { 901 attr->a_vals[i] = attr->a_vals[attr->a_numvals]; 902 if ( attr->a_nvals != attr->a_vals ) 903 attr->a_nvals[i] = attr->a_nvals[attr->a_numvals]; 904 } 905 BER_BVZERO(&attr->a_vals[attr->a_numvals]); 906 if ( attr->a_nvals != attr->a_vals ) 907 BER_BVZERO(&attr->a_nvals[attr->a_numvals]); 908 } 909 attr->a_flags |= SLAP_ATTR_SORTED_VALS; 910 } 911 912 *attrp = attr; 913 attrp = &attr->a_next; 914 915next_attr:; 916 } 917 918 return LDAP_SUCCESS; 919} 920 921/* return 0 IFF we can retrieve the entry with ndn 922 */ 923int 924ldap_back_entry_get( 925 Operation *op, 926 struct berval *ndn, 927 ObjectClass *oc, 928 AttributeDescription *at, 929 int rw, 930 Entry **ent ) 931{ 932 ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private; 933 934 ldapconn_t *lc = NULL; 935 int rc; 936 struct berval bdn; 937 LDAPMessage *result = NULL, 938 *e = NULL; 939 char *attr[3], **attrp = NULL; 940 char *filter = NULL; 941 SlapReply rs; 942 int do_retry = 1; 943 LDAPControl **ctrls = NULL; 944 Operation op2 = *op; 945 946 int remove_unknown_schema = 947 LDAP_BACK_OMIT_UNKNOWN_SCHEMA (li); 948 *ent = NULL; 949 950 /* Tell getconn this is a privileged op */ 951 op2.o_do_not_cache = 1; 952 /* use rootdn to be doubly explicit this is privileged */ 953 op2.o_dn = op->o_bd->be_rootdn; 954 op2.o_ndn = op->o_bd->be_rootndn; 955 /* ldap_back_entry_get() is an entry lookup, so it does not need 956 * to know what the entry is being looked up for */ 957 op2.o_tag = LDAP_REQ_SEARCH; 958 op2.o_ctrls = NULL; 959 rc = ldap_back_dobind( &lc, &op2, &rs, LDAP_BACK_DONTSEND ); 960 if ( !rc ) { 961 return rs.sr_err; 962 } 963 964 if ( at ) { 965 attrp = attr; 966 if ( oc && at != slap_schema.si_ad_objectClass ) { 967 attr[0] = slap_schema.si_ad_objectClass->ad_cname.bv_val; 968 attr[1] = at->ad_cname.bv_val; 969 attr[2] = NULL; 970 971 } else { 972 attr[0] = at->ad_cname.bv_val; 973 attr[1] = NULL; 974 } 975 } 976 977 if ( oc ) { 978 char *ptr; 979 980 filter = op->o_tmpalloc( STRLENOF( "(objectClass=" ")" ) 981 + oc->soc_cname.bv_len + 1, op->o_tmpmemctx ); 982 ptr = lutil_strcopy( filter, "(objectClass=" ); 983 ptr = lutil_strcopy( ptr, oc->soc_cname.bv_val ); 984 *ptr++ = ')'; 985 *ptr++ = '\0'; 986 } 987 988retry: 989 ctrls = NULL; 990 rc = ldap_back_controls_add( &op2, &rs, lc, &ctrls ); 991 if ( rc != LDAP_SUCCESS ) { 992 goto cleanup; 993 } 994 995 /* TODO: timeout? */ 996 rc = ldap_pvt_search_s( lc->lc_ld, ndn->bv_val, LDAP_SCOPE_BASE, filter, 997 attrp, LDAP_DEREF_NEVER, ctrls, NULL, 998 NULL, LDAP_NO_LIMIT, 0, &result ); 999 if ( rc != LDAP_SUCCESS ) { 1000 if ( rc == LDAP_SERVER_DOWN && do_retry ) { 1001 do_retry = 0; 1002 if ( ldap_back_retry( &lc, &op2, &rs, LDAP_BACK_DONTSEND ) ) { 1003 /* if the identity changed, there might be need to re-authz */ 1004 (void)ldap_back_controls_free( &op2, &rs, &ctrls ); 1005 goto retry; 1006 } 1007 } 1008 goto cleanup; 1009 } 1010 1011 e = ldap_first_entry( lc->lc_ld, result ); 1012 if ( e == NULL ) { 1013 /* the entry exists, but it doesn't match the filter? */ 1014 rc = LDAP_NO_RESULTS_RETURNED; 1015 goto cleanup; 1016 } 1017 1018 *ent = entry_alloc(); 1019 if ( *ent == NULL ) { 1020 rc = LDAP_NO_MEMORY; 1021 goto cleanup; 1022 } 1023 1024 rc = ldap_build_entry( op, e, *ent, &bdn, remove_unknown_schema ); 1025 1026 if ( rc != LDAP_SUCCESS ) { 1027 entry_free( *ent ); 1028 *ent = NULL; 1029 } 1030 1031cleanup: 1032 (void)ldap_back_controls_free( &op2, &rs, &ctrls ); 1033 1034 if ( result ) { 1035 ldap_msgfree( result ); 1036 } 1037 1038 if ( filter ) { 1039 op->o_tmpfree( filter, op->o_tmpmemctx ); 1040 } 1041 1042 if ( lc != NULL ) { 1043 ldap_back_release_conn( li, lc ); 1044 } 1045 1046 return rc; 1047} 1048