1/* $NetBSD: result.c,v 1.1.1.4 2010/12/12 15:22:38 adam Exp $ */ 2 3/* result.c - routines to send ldap results, errors, and referrals */ 4/* OpenLDAP: pkg/ldap/servers/slapd/result.c,v 1.289.2.33 2010/04/14 17:28:47 quanah Exp */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2010 The OpenLDAP Foundation. 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/* Portions Copyright (c) 1995 Regents of the University of Michigan. 19 * All rights reserved. 20 * 21 * Redistribution and use in source and binary forms are permitted 22 * provided that this notice is preserved and that due credit is given 23 * to the University of Michigan at Ann Arbor. The name of the University 24 * may not be used to endorse or promote products derived from this 25 * software without specific prior written permission. This software 26 * is provided ``as is'' without express or implied warranty. 27 */ 28 29#include "portable.h" 30 31#include <stdio.h> 32 33#include <ac/socket.h> 34#include <ac/errno.h> 35#include <ac/string.h> 36#include <ac/ctype.h> 37#include <ac/time.h> 38#include <ac/unistd.h> 39 40#include "slap.h" 41 42const struct berval slap_dummy_bv = BER_BVNULL; 43 44int slap_null_cb( Operation *op, SlapReply *rs ) 45{ 46 return 0; 47} 48 49int slap_freeself_cb( Operation *op, SlapReply *rs ) 50{ 51 assert( op->o_callback != NULL ); 52 53 op->o_tmpfree( op->o_callback, op->o_tmpmemctx ); 54 op->o_callback = NULL; 55 56 return SLAP_CB_CONTINUE; 57} 58 59static char *v2ref( BerVarray ref, const char *text ) 60{ 61 size_t len = 0, i = 0; 62 char *v2; 63 64 if(ref == NULL) { 65 if (text) { 66 return ch_strdup(text); 67 } else { 68 return NULL; 69 } 70 } 71 72 if ( text != NULL ) { 73 len = strlen( text ); 74 if (text[len-1] != '\n') { 75 i = 1; 76 } 77 } 78 79 v2 = ch_malloc( len+i+sizeof("Referral:") ); 80 81 if( text != NULL ) { 82 strcpy(v2, text); 83 if( i ) { 84 v2[len++] = '\n'; 85 } 86 } 87 strcpy( v2+len, "Referral:" ); 88 len += sizeof("Referral:"); 89 90 for( i=0; ref[i].bv_val != NULL; i++ ) { 91 v2 = ch_realloc( v2, len + ref[i].bv_len + 1 ); 92 v2[len-1] = '\n'; 93 AC_MEMCPY(&v2[len], ref[i].bv_val, ref[i].bv_len ); 94 len += ref[i].bv_len; 95 if (ref[i].bv_val[ref[i].bv_len-1] != '/') { 96 ++len; 97 } 98 } 99 100 v2[len-1] = '\0'; 101 return v2; 102} 103 104ber_tag_t 105slap_req2res( ber_tag_t tag ) 106{ 107 switch( tag ) { 108 case LDAP_REQ_ADD: 109 case LDAP_REQ_BIND: 110 case LDAP_REQ_COMPARE: 111 case LDAP_REQ_EXTENDED: 112 case LDAP_REQ_MODIFY: 113 case LDAP_REQ_MODRDN: 114 tag++; 115 break; 116 117 case LDAP_REQ_DELETE: 118 tag = LDAP_RES_DELETE; 119 break; 120 121 case LDAP_REQ_ABANDON: 122 case LDAP_REQ_UNBIND: 123 tag = LBER_SEQUENCE; 124 break; 125 126 case LDAP_REQ_SEARCH: 127 tag = LDAP_RES_SEARCH_RESULT; 128 break; 129 130 default: 131 tag = LBER_SEQUENCE; 132 } 133 134 return tag; 135} 136 137#ifdef RS_ASSERT 138#elif 0 && defined LDAP_DEVEL /* FIXME: this should not crash. ITS#5340. */ 139#define RS_ASSERT assert 140#else 141#define RS_ASSERT(cond) ((void) 0) 142#endif 143 144/* Set rs->sr_entry after obyeing and clearing sr_flags & REP_ENTRY_MASK. */ 145void 146rs_replace_entry( Operation *op, SlapReply *rs, slap_overinst *on, Entry *e ) 147{ 148 slap_mask_t e_flags = rs->sr_flags & REP_ENTRY_MUSTFLUSH; 149 150 if ( e_flags && rs->sr_entry != NULL ) { 151 RS_ASSERT( e_flags != REP_ENTRY_MUSTFLUSH ); 152 if ( !(e_flags & REP_ENTRY_MUSTRELEASE) ) { 153 entry_free( rs->sr_entry ); 154 } else if ( on != NULL ) { 155 overlay_entry_release_ov( op, rs->sr_entry, 0, on ); 156 } else { 157 be_entry_release_rw( op, rs->sr_entry, 0 ); 158 } 159 } 160 rs->sr_flags &= ~REP_ENTRY_MASK; 161 rs->sr_entry = e; 162} 163 164/* 165 * Ensure rs->sr_entry is modifiable, by duplicating it if necessary. 166 * Obey sr_flags. Set REP_ENTRY_<MODIFIABLE, and MUSTBEFREED if duplicated>. 167 * Return nonzero if rs->sr_entry was replaced. 168 */ 169int 170rs_ensure_entry_modifiable( Operation *op, SlapReply *rs, slap_overinst *on ) 171{ 172 if ( rs->sr_flags & REP_ENTRY_MODIFIABLE ) { 173 RS_ASSERT((rs->sr_flags & REP_ENTRY_MUSTFLUSH)==REP_ENTRY_MUSTBEFREED); 174 return 0; 175 } 176 rs_replace_entry( op, rs, on, entry_dup( rs->sr_entry )); 177 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED; 178 return 1; 179} 180 181static long send_ldap_ber( 182 Operation *op, 183 BerElement *ber ) 184{ 185 Connection *conn = op->o_conn; 186 ber_len_t bytes; 187 long ret = 0; 188 189 ber_get_option( ber, LBER_OPT_BER_BYTES_TO_WRITE, &bytes ); 190 191 /* write only one pdu at a time - wait til it's our turn */ 192 ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex ); 193 if (( op->o_abandon && !op->o_cancel ) || !connection_valid( conn ) || 194 conn->c_writers < 0 ) { 195 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); 196 return 0; 197 } 198 199 conn->c_writers++; 200 201 while ( conn->c_writers > 0 && conn->c_writing ) { 202 ldap_pvt_thread_cond_wait( &conn->c_write1_cv, &conn->c_write1_mutex ); 203 } 204 205 /* connection was closed under us */ 206 if ( conn->c_writers < 0 ) { 207 /* we're the last waiter, let the closer continue */ 208 if ( conn->c_writers == -1 ) 209 ldap_pvt_thread_cond_signal( &conn->c_write1_cv ); 210 conn->c_writers++; 211 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); 212 return 0; 213 } 214 215 /* Our turn */ 216 conn->c_writing = 1; 217 218 /* write the pdu */ 219 while( 1 ) { 220 int err; 221 222 /* lock the connection */ 223 if ( ldap_pvt_thread_mutex_trylock( &conn->c_mutex )) { 224 if ( !connection_valid(conn)) { 225 ret = 0; 226 break; 227 } 228 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); 229 ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex ); 230 if ( conn->c_writers < 0 ) { 231 ret = 0; 232 break; 233 } 234 continue; 235 } 236 237 if ( ber_flush2( conn->c_sb, ber, LBER_FLUSH_FREE_NEVER ) == 0 ) { 238 ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); 239 ret = bytes; 240 break; 241 } 242 243 err = sock_errno(); 244 245 /* 246 * we got an error. if it's ewouldblock, we need to 247 * wait on the socket being writable. otherwise, figure 248 * it's a hard error and return. 249 */ 250 251 Debug( LDAP_DEBUG_CONNS, "ber_flush2 failed errno=%d reason=\"%s\"\n", 252 err, sock_errstr(err), 0 ); 253 254 if ( err != EWOULDBLOCK && err != EAGAIN ) { 255 conn->c_writers--; 256 conn->c_writing = 0; 257 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); 258 connection_closing( conn, "connection lost on write" ); 259 260 ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); 261 return -1; 262 } 263 264 /* wait for socket to be write-ready */ 265 ldap_pvt_thread_mutex_lock( &conn->c_write2_mutex ); 266 conn->c_writewaiter = 1; 267 slapd_set_write( conn->c_sd, 2 ); 268 269 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); 270 ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); 271 ldap_pvt_thread_cond_wait( &conn->c_write2_cv, &conn->c_write2_mutex ); 272 conn->c_writewaiter = 0; 273 ldap_pvt_thread_mutex_unlock( &conn->c_write2_mutex ); 274 ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex ); 275 if ( conn->c_writers < 0 ) { 276 ret = 0; 277 break; 278 } 279 } 280 281 conn->c_writing = 0; 282 if ( conn->c_writers < 0 ) { 283 conn->c_writers++; 284 if ( !conn->c_writers ) 285 ldap_pvt_thread_cond_signal( &conn->c_write1_cv ); 286 } else { 287 conn->c_writers--; 288 ldap_pvt_thread_cond_signal( &conn->c_write1_cv ); 289 } 290 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); 291 292 return ret; 293} 294 295static int 296send_ldap_control( BerElement *ber, LDAPControl *c ) 297{ 298 int rc; 299 300 assert( c != NULL ); 301 302 rc = ber_printf( ber, "{s" /*}*/, c->ldctl_oid ); 303 304 if( c->ldctl_iscritical ) { 305 rc = ber_printf( ber, "b", 306 (ber_int_t) c->ldctl_iscritical ) ; 307 if( rc == -1 ) return rc; 308 } 309 310 if( c->ldctl_value.bv_val != NULL ) { 311 rc = ber_printf( ber, "O", &c->ldctl_value ); 312 if( rc == -1 ) return rc; 313 } 314 315 rc = ber_printf( ber, /*{*/"N}" ); 316 if( rc == -1 ) return rc; 317 318 return 0; 319} 320 321static int 322send_ldap_controls( Operation *o, BerElement *ber, LDAPControl **c ) 323{ 324 int rc; 325 326 if( c == NULL ) 327 return 0; 328 329 rc = ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ); 330 if( rc == -1 ) return rc; 331 332 for( ; *c != NULL; c++) { 333 rc = send_ldap_control( ber, *c ); 334 if( rc == -1 ) return rc; 335 } 336 337#ifdef SLAP_CONTROL_X_SORTEDRESULTS 338 /* this is a hack to avoid having to modify op->s_ctrls */ 339 if( o->o_sortedresults ) { 340 BerElementBuffer berbuf; 341 BerElement *sber = (BerElement *) &berbuf; 342 LDAPControl sorted; 343 BER_BVZERO( &sorted.ldctl_value ); 344 sorted.ldctl_oid = LDAP_CONTROL_SORTRESPONSE; 345 sorted.ldctl_iscritical = 0; 346 347 ber_init2( sber, NULL, LBER_USE_DER ); 348 349 ber_printf( sber, "{e}", LDAP_UNWILLING_TO_PERFORM ); 350 351 if( ber_flatten2( sber, &sorted.ldctl_value, 0 ) == -1 ) { 352 return -1; 353 } 354 355 (void) ber_free_buf( sber ); 356 357 rc = send_ldap_control( ber, &sorted ); 358 if( rc == -1 ) return rc; 359 } 360#endif 361 362 rc = ber_printf( ber, /*{*/"N}" ); 363 364 return rc; 365} 366 367/* 368 * slap_response_play() 369 * 370 * plays the callback list; rationale: a callback can 371 * - remove itself from the list, by setting op->o_callback = NULL; 372 * malloc()'ed callbacks should free themselves from inside the 373 * sc_response() function. 374 * - replace itself with another (list of) callback(s), by setting 375 * op->o_callback = a new (list of) callback(s); in this case, it 376 * is the callback's responsibility to to append existing subsequent 377 * callbacks to the end of the list that is passed to the sc_response() 378 * function. 379 * - modify the list of subsequent callbacks by modifying the value 380 * of the sc_next field from inside the sc_response() function; this 381 * case does not require any handling from inside slap_response_play() 382 * 383 * To stop execution of the playlist, the sc_response() function must return 384 * a value different from SLAP_SC_CONTINUE. 385 * 386 * The same applies to slap_cleanup_play(); only, there is no means to stop 387 * execution of the playlist, since all cleanup functions must be called. 388 */ 389static int 390slap_response_play( 391 Operation *op, 392 SlapReply *rs ) 393{ 394 int rc; 395 396 slap_callback *sc = op->o_callback, **scp; 397 398 rc = SLAP_CB_CONTINUE; 399 for ( scp = ≻ *scp; ) { 400 slap_callback *sc_next = (*scp)->sc_next, **sc_nextp = &(*scp)->sc_next; 401 402 op->o_callback = *scp; 403 if ( op->o_callback->sc_response ) { 404 rc = op->o_callback->sc_response( op, rs ); 405 if ( op->o_callback == NULL ) { 406 /* the callback has been removed; 407 * repair the list */ 408 *scp = sc_next; 409 sc_nextp = scp; 410 411 } else if ( op->o_callback != *scp ) { 412 /* a new callback has been inserted 413 * in place of the existing one; repair the list */ 414 *scp = op->o_callback; 415 sc_nextp = scp; 416 } 417 if ( rc != SLAP_CB_CONTINUE ) break; 418 } 419 scp = sc_nextp; 420 } 421 422 op->o_callback = sc; 423 return rc; 424} 425 426static int 427slap_cleanup_play( 428 Operation *op, 429 SlapReply *rs ) 430{ 431 slap_callback *sc = op->o_callback, **scp; 432 433 for ( scp = ≻ *scp; ) { 434 slap_callback *sc_next = (*scp)->sc_next, **sc_nextp = &(*scp)->sc_next; 435 436 op->o_callback = *scp; 437 if ( op->o_callback->sc_cleanup ) { 438 (void)op->o_callback->sc_cleanup( op, rs ); 439 if ( op->o_callback == NULL ) { 440 /* the callback has been removed; 441 * repair the list */ 442 *scp = sc_next; 443 sc_nextp = scp; 444 445 } else if ( op->o_callback != *scp ) { 446 /* a new callback has been inserted 447 * after the existing one; repair the list */ 448 /* a new callback has been inserted 449 * in place of the existing one; repair the list */ 450 *scp = op->o_callback; 451 sc_nextp = scp; 452 } 453 /* don't care about the result; do all cleanup */ 454 } 455 scp = sc_nextp; 456 } 457 458 op->o_callback = sc; 459 return LDAP_SUCCESS; 460} 461 462static int 463send_ldap_response( 464 Operation *op, 465 SlapReply *rs ) 466{ 467 BerElementBuffer berbuf; 468 BerElement *ber = (BerElement *) &berbuf; 469 int rc = LDAP_SUCCESS; 470 long bytes; 471 472 if (( rs->sr_err == SLAPD_ABANDON || op->o_abandon ) && !op->o_cancel ) { 473 rc = SLAPD_ABANDON; 474 goto clean2; 475 } 476 477 if ( op->o_callback ) { 478 rc = slap_response_play( op, rs ); 479 if ( rc != SLAP_CB_CONTINUE ) { 480 goto clean2; 481 } 482 } 483 484#ifdef LDAP_CONNECTIONLESS 485 if (op->o_conn && op->o_conn->c_is_udp) 486 ber = op->o_res_ber; 487 else 488#endif 489 { 490 ber_init_w_nullc( ber, LBER_USE_DER ); 491 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 492 } 493 494 rc = rs->sr_err; 495 if ( rc == SLAPD_ABANDON && op->o_cancel ) 496 rc = LDAP_CANCELLED; 497 498 Debug( LDAP_DEBUG_TRACE, 499 "send_ldap_response: msgid=%d tag=%lu err=%d\n", 500 rs->sr_msgid, rs->sr_tag, rc ); 501 502 if( rs->sr_ref ) { 503 Debug( LDAP_DEBUG_ARGS, "send_ldap_response: ref=\"%s\"\n", 504 rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL", 505 NULL, NULL ); 506 } 507 508#ifdef LDAP_CONNECTIONLESS 509 if (op->o_conn && op->o_conn->c_is_udp && 510 op->o_protocol == LDAP_VERSION2 ) 511 { 512 rc = ber_printf( ber, "t{ess" /*"}"*/, 513 rs->sr_tag, rc, 514 rs->sr_matched == NULL ? "" : rs->sr_matched, 515 rs->sr_text == NULL ? "" : rs->sr_text ); 516 } else 517#endif 518 if ( rs->sr_type == REP_INTERMEDIATE ) { 519 rc = ber_printf( ber, "{it{" /*"}}"*/, 520 rs->sr_msgid, rs->sr_tag ); 521 522 } else { 523 rc = ber_printf( ber, "{it{ess" /*"}}"*/, 524 rs->sr_msgid, rs->sr_tag, rc, 525 rs->sr_matched == NULL ? "" : rs->sr_matched, 526 rs->sr_text == NULL ? "" : rs->sr_text ); 527 } 528 529 if( rc != -1 ) { 530 if ( rs->sr_ref != NULL ) { 531 assert( rs->sr_err == LDAP_REFERRAL ); 532 rc = ber_printf( ber, "t{W}", 533 LDAP_TAG_REFERRAL, rs->sr_ref ); 534 } else { 535 assert( rs->sr_err != LDAP_REFERRAL ); 536 } 537 } 538 539 if( rc != -1 && rs->sr_type == REP_SASL && rs->sr_sasldata != NULL ) { 540 rc = ber_printf( ber, "tO", 541 LDAP_TAG_SASL_RES_CREDS, rs->sr_sasldata ); 542 } 543 544 if( rc != -1 && 545 ( rs->sr_type == REP_EXTENDED || rs->sr_type == REP_INTERMEDIATE )) 546 { 547 if ( rs->sr_rspoid != NULL ) { 548 rc = ber_printf( ber, "ts", 549 rs->sr_type == REP_EXTENDED 550 ? LDAP_TAG_EXOP_RES_OID : LDAP_TAG_IM_RES_OID, 551 rs->sr_rspoid ); 552 } 553 if( rc != -1 && rs->sr_rspdata != NULL ) { 554 rc = ber_printf( ber, "tO", 555 rs->sr_type == REP_EXTENDED 556 ? LDAP_TAG_EXOP_RES_VALUE : LDAP_TAG_IM_RES_VALUE, 557 rs->sr_rspdata ); 558 } 559 } 560 561 if( rc != -1 ) { 562 rc = ber_printf( ber, /*"{"*/ "N}" ); 563 } 564 565 if( rc != -1 ) { 566 rc = send_ldap_controls( op, ber, rs->sr_ctrls ); 567 } 568 569 if( rc != -1 ) { 570 rc = ber_printf( ber, /*"{"*/ "N}" ); 571 } 572 573#ifdef LDAP_CONNECTIONLESS 574 if( op->o_conn && op->o_conn->c_is_udp && op->o_protocol == LDAP_VERSION2 575 && rc != -1 ) 576 { 577 rc = ber_printf( ber, /*"{"*/ "N}" ); 578 } 579#endif 580 581 if ( rc == -1 ) { 582 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); 583 584#ifdef LDAP_CONNECTIONLESS 585 if (!op->o_conn || op->o_conn->c_is_udp == 0) 586#endif 587 { 588 ber_free_buf( ber ); 589 } 590 goto cleanup; 591 } 592 593 /* send BER */ 594 bytes = send_ldap_ber( op, ber ); 595#ifdef LDAP_CONNECTIONLESS 596 if (!op->o_conn || op->o_conn->c_is_udp == 0) 597#endif 598 { 599 ber_free_buf( ber ); 600 } 601 602 if ( bytes < 0 ) { 603 Debug( LDAP_DEBUG_ANY, 604 "send_ldap_response: ber write failed\n", 605 0, 0, 0 ); 606 607 goto cleanup; 608 } 609 610 ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex ); 611 ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 ); 612 ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes ); 613 ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex ); 614 615cleanup:; 616 /* Tell caller that we did this for real, as opposed to being 617 * overridden by a callback 618 */ 619 rc = SLAP_CB_CONTINUE; 620 621clean2:; 622 if ( op->o_callback ) { 623 (void)slap_cleanup_play( op, rs ); 624 } 625 626 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) { 627 rs->sr_flags ^= REP_MATCHED_MUSTBEFREED; /* paranoia */ 628 if ( rs->sr_matched ) { 629 free( (char *)rs->sr_matched ); 630 rs->sr_matched = NULL; 631 } 632 } 633 634 if ( rs->sr_flags & REP_REF_MUSTBEFREED ) { 635 rs->sr_flags ^= REP_REF_MUSTBEFREED; /* paranoia */ 636 if ( rs->sr_ref ) { 637 ber_bvarray_free( rs->sr_ref ); 638 rs->sr_ref = NULL; 639 } 640 } 641 642 if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) { 643 rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */ 644 if ( rs->sr_ctrls ) { 645 slap_free_ctrls( op, rs->sr_ctrls ); 646 rs->sr_ctrls = NULL; 647 } 648 } 649 650 return rc; 651} 652 653 654void 655send_ldap_disconnect( Operation *op, SlapReply *rs ) 656{ 657#define LDAP_UNSOLICITED_ERROR(e) \ 658 ( (e) == LDAP_PROTOCOL_ERROR \ 659 || (e) == LDAP_STRONG_AUTH_REQUIRED \ 660 || (e) == LDAP_UNAVAILABLE ) 661 662 assert( LDAP_UNSOLICITED_ERROR( rs->sr_err ) ); 663 664 rs->sr_type = REP_EXTENDED; 665 rs->sr_rspdata = NULL; 666 667 Debug( LDAP_DEBUG_TRACE, 668 "send_ldap_disconnect %d:%s\n", 669 rs->sr_err, rs->sr_text ? rs->sr_text : "", NULL ); 670 671 if ( op->o_protocol < LDAP_VERSION3 ) { 672 rs->sr_rspoid = NULL; 673 rs->sr_tag = slap_req2res( op->o_tag ); 674 rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0; 675 676 } else { 677 rs->sr_rspoid = LDAP_NOTICE_DISCONNECT; 678 rs->sr_tag = LDAP_RES_EXTENDED; 679 rs->sr_msgid = LDAP_RES_UNSOLICITED; 680 } 681 682 if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) { 683 Statslog( LDAP_DEBUG_STATS, 684 "%s DISCONNECT tag=%lu err=%d text=%s\n", 685 op->o_log_prefix, rs->sr_tag, rs->sr_err, 686 rs->sr_text ? rs->sr_text : "", 0 ); 687 } 688} 689 690void 691slap_send_ldap_result( Operation *op, SlapReply *rs ) 692{ 693 char *tmp = NULL; 694 const char *otext = rs->sr_text; 695 BerVarray oref = rs->sr_ref; 696 697 rs->sr_type = REP_RESULT; 698 699 /* Propagate Abandons so that cleanup callbacks can be processed */ 700 if ( rs->sr_err == SLAPD_ABANDON || op->o_abandon ) 701 goto abandon; 702 703 assert( !LDAP_API_ERROR( rs->sr_err ) ); 704 705 Debug( LDAP_DEBUG_TRACE, 706 "send_ldap_result: %s p=%d\n", 707 op->o_log_prefix, op->o_protocol, 0 ); 708 709 Debug( LDAP_DEBUG_ARGS, 710 "send_ldap_result: err=%d matched=\"%s\" text=\"%s\"\n", 711 rs->sr_err, rs->sr_matched ? rs->sr_matched : "", 712 rs->sr_text ? rs->sr_text : "" ); 713 714 715 if( rs->sr_ref ) { 716 Debug( LDAP_DEBUG_ARGS, 717 "send_ldap_result: referral=\"%s\"\n", 718 rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL", 719 NULL, NULL ); 720 } 721 722 assert( rs->sr_err != LDAP_PARTIAL_RESULTS ); 723 724 if ( rs->sr_err == LDAP_REFERRAL ) { 725 if( op->o_domain_scope ) rs->sr_ref = NULL; 726 727 if( rs->sr_ref == NULL ) { 728 rs->sr_err = LDAP_NO_SUCH_OBJECT; 729 } else if ( op->o_protocol < LDAP_VERSION3 ) { 730 rs->sr_err = LDAP_PARTIAL_RESULTS; 731 } 732 } 733 734 if ( op->o_protocol < LDAP_VERSION3 ) { 735 tmp = v2ref( rs->sr_ref, rs->sr_text ); 736 rs->sr_text = tmp; 737 rs->sr_ref = NULL; 738 } 739 740abandon: 741 rs->sr_tag = slap_req2res( op->o_tag ); 742 rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0; 743 744 if ( rs->sr_flags & REP_REF_MUSTBEFREED ) { 745 if ( rs->sr_ref == NULL ) { 746 rs->sr_flags ^= REP_REF_MUSTBEFREED; 747 ber_bvarray_free( oref ); 748 } 749 oref = NULL; /* send_ldap_response() will free rs->sr_ref if != NULL */ 750 } 751 752 if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) { 753 if ( op->o_tag == LDAP_REQ_SEARCH ) { 754 Statslog( LDAP_DEBUG_STATS, 755 "%s SEARCH RESULT tag=%lu err=%d nentries=%d text=%s\n", 756 op->o_log_prefix, rs->sr_tag, rs->sr_err, 757 rs->sr_nentries, rs->sr_text ? rs->sr_text : "" ); 758 } else { 759 Statslog( LDAP_DEBUG_STATS, 760 "%s RESULT tag=%lu err=%d text=%s\n", 761 op->o_log_prefix, rs->sr_tag, rs->sr_err, 762 rs->sr_text ? rs->sr_text : "", 0 ); 763 } 764 } 765 766 if( tmp != NULL ) ch_free(tmp); 767 rs->sr_text = otext; 768 rs->sr_ref = oref; 769} 770 771void 772send_ldap_sasl( Operation *op, SlapReply *rs ) 773{ 774 rs->sr_type = REP_SASL; 775 Debug( LDAP_DEBUG_TRACE, "send_ldap_sasl: err=%d len=%ld\n", 776 rs->sr_err, 777 rs->sr_sasldata ? (long) rs->sr_sasldata->bv_len : -1, NULL ); 778 779 rs->sr_tag = slap_req2res( op->o_tag ); 780 rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0; 781 782 if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) { 783 Statslog( LDAP_DEBUG_STATS, 784 "%s RESULT tag=%lu err=%d text=%s\n", 785 op->o_log_prefix, rs->sr_tag, rs->sr_err, 786 rs->sr_text ? rs->sr_text : "", 0 ); 787 } 788} 789 790void 791slap_send_ldap_extended( Operation *op, SlapReply *rs ) 792{ 793 rs->sr_type = REP_EXTENDED; 794 795 Debug( LDAP_DEBUG_TRACE, 796 "send_ldap_extended: err=%d oid=%s len=%ld\n", 797 rs->sr_err, 798 rs->sr_rspoid ? rs->sr_rspoid : "", 799 rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 ); 800 801 rs->sr_tag = slap_req2res( op->o_tag ); 802 rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0; 803 804 if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) { 805 Statslog( LDAP_DEBUG_STATS, 806 "%s RESULT oid=%s err=%d text=%s\n", 807 op->o_log_prefix, rs->sr_rspoid ? rs->sr_rspoid : "", 808 rs->sr_err, rs->sr_text ? rs->sr_text : "", 0 ); 809 } 810} 811 812void 813slap_send_ldap_intermediate( Operation *op, SlapReply *rs ) 814{ 815 rs->sr_type = REP_INTERMEDIATE; 816 Debug( LDAP_DEBUG_TRACE, 817 "send_ldap_intermediate: err=%d oid=%s len=%ld\n", 818 rs->sr_err, 819 rs->sr_rspoid ? rs->sr_rspoid : "", 820 rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 ); 821 rs->sr_tag = LDAP_RES_INTERMEDIATE; 822 rs->sr_msgid = op->o_msgid; 823 if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) { 824 Statslog( LDAP_DEBUG_STATS2, 825 "%s INTERM oid=%s\n", 826 op->o_log_prefix, 827 rs->sr_rspoid ? rs->sr_rspoid : "", 0, 0, 0 ); 828 } 829} 830 831/* 832 * returns: 833 * 834 * LDAP_SUCCESS entry sent 835 * LDAP_OTHER entry not sent (other) 836 * LDAP_INSUFFICIENT_ACCESS entry not sent (ACL) 837 * LDAP_UNAVAILABLE entry not sent (connection closed) 838 * LDAP_SIZELIMIT_EXCEEDED entry not sent (caller must send sizelimitExceeded) 839 */ 840 841int 842slap_send_search_entry( Operation *op, SlapReply *rs ) 843{ 844 BerElementBuffer berbuf; 845 BerElement *ber = (BerElement *) &berbuf; 846 Attribute *a; 847 int i, j, rc = LDAP_UNAVAILABLE, bytes; 848 int userattrs; 849 AccessControlState acl_state = ACL_STATE_INIT; 850 int attrsonly; 851 AttributeDescription *ad_entry = slap_schema.si_ad_entry; 852 853 /* a_flags: array of flags telling if the i-th element will be 854 * returned or filtered out 855 * e_flags: array of a_flags 856 */ 857 char **e_flags = NULL; 858 859 if ( op->ors_slimit >= 0 && rs->sr_nentries >= op->ors_slimit ) { 860 return LDAP_SIZELIMIT_EXCEEDED; 861 } 862 863 /* Every 64 entries, check for thread pool pause */ 864 if ( ( ( rs->sr_nentries & 0x3f ) == 0x3f ) && 865 ldap_pvt_thread_pool_pausing( &connection_pool ) > 0 ) 866 { 867 return LDAP_BUSY; 868 } 869 870 rs->sr_type = REP_SEARCH; 871 872 /* eventually will loop through generated operational attribute types 873 * currently implemented types include: 874 * entryDN, subschemaSubentry, and hasSubordinates */ 875 /* NOTE: moved before overlays callback circling because 876 * they may modify entry and other stuff in rs */ 877 /* check for special all operational attributes ("+") type */ 878 /* FIXME: maybe we could set this flag at the operation level; 879 * however, in principle the caller of send_search_entry() may 880 * change the attribute list at each call */ 881 rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs ); 882 883 rc = backend_operational( op, rs ); 884 if ( rc ) { 885 goto error_return; 886 } 887 888 if ( op->o_callback ) { 889 rc = slap_response_play( op, rs ); 890 if ( rc != SLAP_CB_CONTINUE ) { 891 goto error_return; 892 } 893 } 894 895 Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: conn %lu dn=\"%s\"%s\n", 896 op->o_connid, rs->sr_entry->e_name.bv_val, 897 op->ors_attrsonly ? " (attrsOnly)" : "" ); 898 899 attrsonly = op->ors_attrsonly; 900 901 if ( !access_allowed( op, rs->sr_entry, ad_entry, NULL, ACL_READ, NULL )) { 902 Debug( LDAP_DEBUG_ACL, 903 "send_search_entry: conn %lu access to entry (%s) not allowed\n", 904 op->o_connid, rs->sr_entry->e_name.bv_val, 0 ); 905 906 rc = LDAP_INSUFFICIENT_ACCESS; 907 goto error_return; 908 } 909 910 if ( op->o_res_ber ) { 911 /* read back control or LDAP_CONNECTIONLESS */ 912 ber = op->o_res_ber; 913 } else { 914 struct berval bv; 915 916 bv.bv_len = entry_flatsize( rs->sr_entry, 0 ); 917 bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx ); 918 919 ber_init2( ber, &bv, LBER_USE_DER ); 920 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 921 } 922 923#ifdef LDAP_CONNECTIONLESS 924 if ( op->o_conn && op->o_conn->c_is_udp ) { 925 /* CONNECTIONLESS */ 926 if ( op->o_protocol == LDAP_VERSION2 ) { 927 rc = ber_printf(ber, "t{O{" /*}}*/, 928 LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name ); 929 } else { 930 rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid, 931 LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name ); 932 } 933 } else 934#endif 935 if ( op->o_res_ber ) { 936 /* read back control */ 937 rc = ber_printf( ber, "{O{" /*}}*/, &rs->sr_entry->e_name ); 938 } else { 939 rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid, 940 LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name ); 941 } 942 943 if ( rc == -1 ) { 944 Debug( LDAP_DEBUG_ANY, 945 "send_search_entry: conn %lu ber_printf failed\n", 946 op->o_connid, 0, 0 ); 947 948 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 949 send_ldap_error( op, rs, LDAP_OTHER, "encoding DN error" ); 950 rc = rs->sr_err; 951 goto error_return; 952 } 953 954 /* check for special all user attributes ("*") type */ 955 userattrs = SLAP_USERATTRS( rs->sr_attr_flags ); 956 957 /* create an array of arrays of flags. Each flag corresponds 958 * to particular value of attribute and equals 1 if value matches 959 * to ValuesReturnFilter or 0 if not 960 */ 961 if ( op->o_vrFilter != NULL ) { 962 int k = 0; 963 size_t size; 964 965 for ( a = rs->sr_entry->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) { 966 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++; 967 } 968 969 size = i * sizeof(char *) + k; 970 if ( size > 0 ) { 971 char *a_flags; 972 e_flags = slap_sl_calloc ( 1, i * sizeof(char *) + k, op->o_tmpmemctx ); 973 if( e_flags == NULL ) { 974 Debug( LDAP_DEBUG_ANY, 975 "send_search_entry: conn %lu slap_sl_calloc failed\n", 976 op->o_connid, 0, 0 ); 977 ber_free( ber, 1 ); 978 979 send_ldap_error( op, rs, LDAP_OTHER, "out of memory" ); 980 goto error_return; 981 } 982 a_flags = (char *)(e_flags + i); 983 memset( a_flags, 0, k ); 984 for ( a=rs->sr_entry->e_attrs, i=0; a != NULL; a=a->a_next, i++ ) { 985 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ); 986 e_flags[i] = a_flags; 987 a_flags += j; 988 } 989 990 rc = filter_matched_values(op, rs->sr_entry->e_attrs, &e_flags) ; 991 if ( rc == -1 ) { 992 Debug( LDAP_DEBUG_ANY, "send_search_entry: " 993 "conn %lu matched values filtering failed\n", 994 op->o_connid, 0, 0 ); 995 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 996 send_ldap_error( op, rs, LDAP_OTHER, 997 "matched values filtering error" ); 998 rc = rs->sr_err; 999 goto error_return; 1000 } 1001 } 1002 } 1003 1004 for ( a = rs->sr_entry->e_attrs, j = 0; a != NULL; a = a->a_next, j++ ) { 1005 AttributeDescription *desc = a->a_desc; 1006 int finish = 0; 1007 1008 if ( rs->sr_attrs == NULL ) { 1009 /* all user attrs request, skip operational attributes */ 1010 if( is_at_operational( desc->ad_type ) ) { 1011 continue; 1012 } 1013 1014 } else { 1015 /* specific attrs requested */ 1016 if ( is_at_operational( desc->ad_type ) ) { 1017 /* if not explicitly requested */ 1018 if ( !ad_inlist( desc, rs->sr_attrs )) { 1019 /* if not all op attrs requested, skip */ 1020 if ( !SLAP_OPATTRS( rs->sr_attr_flags )) 1021 continue; 1022 /* if DSA-specific and replicating, skip */ 1023 if ( op->o_sync != SLAP_CONTROL_NONE && 1024 desc->ad_type->sat_usage == LDAP_SCHEMA_DSA_OPERATION ) 1025 continue; 1026 } 1027 } else { 1028 if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) { 1029 continue; 1030 } 1031 } 1032 } 1033 1034 if ( attrsonly ) { 1035 if ( ! access_allowed( op, rs->sr_entry, desc, NULL, 1036 ACL_READ, &acl_state ) ) 1037 { 1038 Debug( LDAP_DEBUG_ACL, "send_search_entry: " 1039 "conn %lu access to attribute %s not allowed\n", 1040 op->o_connid, desc->ad_cname.bv_val, 0 ); 1041 continue; 1042 } 1043 1044 if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) { 1045 Debug( LDAP_DEBUG_ANY, 1046 "send_search_entry: conn %lu ber_printf failed\n", 1047 op->o_connid, 0, 0 ); 1048 1049 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 1050 send_ldap_error( op, rs, LDAP_OTHER, 1051 "encoding description error"); 1052 rc = rs->sr_err; 1053 goto error_return; 1054 } 1055 finish = 1; 1056 1057 } else { 1058 int first = 1; 1059 for ( i = 0; a->a_nvals[i].bv_val != NULL; i++ ) { 1060 if ( ! access_allowed( op, rs->sr_entry, 1061 desc, &a->a_nvals[i], ACL_READ, &acl_state ) ) 1062 { 1063 Debug( LDAP_DEBUG_ACL, 1064 "send_search_entry: conn %lu " 1065 "access to attribute %s, value #%d not allowed\n", 1066 op->o_connid, desc->ad_cname.bv_val, i ); 1067 1068 continue; 1069 } 1070 1071 if ( op->o_vrFilter && e_flags[j][i] == 0 ){ 1072 continue; 1073 } 1074 1075 if ( first ) { 1076 first = 0; 1077 finish = 1; 1078 if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) { 1079 Debug( LDAP_DEBUG_ANY, 1080 "send_search_entry: conn %lu ber_printf failed\n", 1081 op->o_connid, 0, 0 ); 1082 1083 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 1084 send_ldap_error( op, rs, LDAP_OTHER, 1085 "encoding description error"); 1086 rc = rs->sr_err; 1087 goto error_return; 1088 } 1089 } 1090 if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) { 1091 Debug( LDAP_DEBUG_ANY, 1092 "send_search_entry: conn %lu " 1093 "ber_printf failed.\n", op->o_connid, 0, 0 ); 1094 1095 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 1096 send_ldap_error( op, rs, LDAP_OTHER, 1097 "encoding values error" ); 1098 rc = rs->sr_err; 1099 goto error_return; 1100 } 1101 } 1102 } 1103 1104 if ( finish && ( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) { 1105 Debug( LDAP_DEBUG_ANY, 1106 "send_search_entry: conn %lu ber_printf failed\n", 1107 op->o_connid, 0, 0 ); 1108 1109 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 1110 send_ldap_error( op, rs, LDAP_OTHER, "encode end error" ); 1111 rc = rs->sr_err; 1112 goto error_return; 1113 } 1114 } 1115 1116 /* NOTE: moved before overlays callback circling because 1117 * they may modify entry and other stuff in rs */ 1118 if ( rs->sr_operational_attrs != NULL && op->o_vrFilter != NULL ) { 1119 int k = 0; 1120 size_t size; 1121 1122 for ( a = rs->sr_operational_attrs, i=0; a != NULL; a = a->a_next, i++ ) { 1123 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++; 1124 } 1125 1126 size = i * sizeof(char *) + k; 1127 if ( size > 0 ) { 1128 char *a_flags, **tmp; 1129 1130 /* 1131 * Reuse previous memory - we likely need less space 1132 * for operational attributes 1133 */ 1134 tmp = slap_sl_realloc( e_flags, i * sizeof(char *) + k, 1135 op->o_tmpmemctx ); 1136 if ( tmp == NULL ) { 1137 Debug( LDAP_DEBUG_ANY, 1138 "send_search_entry: conn %lu " 1139 "not enough memory " 1140 "for matched values filtering\n", 1141 op->o_connid, 0, 0 ); 1142 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 1143 send_ldap_error( op, rs, LDAP_OTHER, 1144 "not enough memory for matched values filtering" ); 1145 goto error_return; 1146 } 1147 e_flags = tmp; 1148 a_flags = (char *)(e_flags + i); 1149 memset( a_flags, 0, k ); 1150 for ( a = rs->sr_operational_attrs, i=0; a != NULL; a = a->a_next, i++ ) { 1151 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ); 1152 e_flags[i] = a_flags; 1153 a_flags += j; 1154 } 1155 rc = filter_matched_values(op, rs->sr_operational_attrs, &e_flags) ; 1156 1157 if ( rc == -1 ) { 1158 Debug( LDAP_DEBUG_ANY, 1159 "send_search_entry: conn %lu " 1160 "matched values filtering failed\n", 1161 op->o_connid, 0, 0); 1162 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 1163 send_ldap_error( op, rs, LDAP_OTHER, 1164 "matched values filtering error" ); 1165 rc = rs->sr_err; 1166 goto error_return; 1167 } 1168 } 1169 } 1170 1171 for (a = rs->sr_operational_attrs, j=0; a != NULL; a = a->a_next, j++ ) { 1172 AttributeDescription *desc = a->a_desc; 1173 1174 if ( rs->sr_attrs == NULL ) { 1175 /* all user attrs request, skip operational attributes */ 1176 if( is_at_operational( desc->ad_type ) ) { 1177 continue; 1178 } 1179 1180 } else { 1181 /* specific attrs requested */ 1182 if( is_at_operational( desc->ad_type ) ) { 1183 if ( !SLAP_OPATTRS( rs->sr_attr_flags ) && 1184 !ad_inlist( desc, rs->sr_attrs ) ) 1185 { 1186 continue; 1187 } 1188 } else { 1189 if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) { 1190 continue; 1191 } 1192 } 1193 } 1194 1195 if ( ! access_allowed( op, rs->sr_entry, desc, NULL, 1196 ACL_READ, &acl_state ) ) 1197 { 1198 Debug( LDAP_DEBUG_ACL, 1199 "send_search_entry: conn %lu " 1200 "access to attribute %s not allowed\n", 1201 op->o_connid, desc->ad_cname.bv_val, 0 ); 1202 1203 continue; 1204 } 1205 1206 rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname ); 1207 if ( rc == -1 ) { 1208 Debug( LDAP_DEBUG_ANY, 1209 "send_search_entry: conn %lu " 1210 "ber_printf failed\n", op->o_connid, 0, 0 ); 1211 1212 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 1213 send_ldap_error( op, rs, LDAP_OTHER, 1214 "encoding description error" ); 1215 rc = rs->sr_err; 1216 goto error_return; 1217 } 1218 1219 if ( ! attrsonly ) { 1220 for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) { 1221 if ( ! access_allowed( op, rs->sr_entry, 1222 desc, &a->a_vals[i], ACL_READ, &acl_state ) ) 1223 { 1224 Debug( LDAP_DEBUG_ACL, 1225 "send_search_entry: conn %lu " 1226 "access to %s, value %d not allowed\n", 1227 op->o_connid, desc->ad_cname.bv_val, i ); 1228 1229 continue; 1230 } 1231 1232 if ( op->o_vrFilter && e_flags[j][i] == 0 ){ 1233 continue; 1234 } 1235 1236 if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) { 1237 Debug( LDAP_DEBUG_ANY, 1238 "send_search_entry: conn %lu ber_printf failed\n", 1239 op->o_connid, 0, 0 ); 1240 1241 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 1242 send_ldap_error( op, rs, LDAP_OTHER, 1243 "encoding values error" ); 1244 rc = rs->sr_err; 1245 goto error_return; 1246 } 1247 } 1248 } 1249 1250 if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) { 1251 Debug( LDAP_DEBUG_ANY, 1252 "send_search_entry: conn %lu ber_printf failed\n", 1253 op->o_connid, 0, 0 ); 1254 1255 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 1256 send_ldap_error( op, rs, LDAP_OTHER, "encode end error" ); 1257 rc = rs->sr_err; 1258 goto error_return; 1259 } 1260 } 1261 1262 /* free e_flags */ 1263 if ( e_flags ) { 1264 slap_sl_free( e_flags, op->o_tmpmemctx ); 1265 e_flags = NULL; 1266 } 1267 1268 rc = ber_printf( ber, /*{{*/ "}N}" ); 1269 1270 if( rc != -1 ) { 1271 rc = send_ldap_controls( op, ber, rs->sr_ctrls ); 1272 } 1273 1274 if( rc != -1 ) { 1275#ifdef LDAP_CONNECTIONLESS 1276 if( op->o_conn && op->o_conn->c_is_udp ) { 1277 if ( op->o_protocol != LDAP_VERSION2 ) { 1278 rc = ber_printf( ber, /*{*/ "N}" ); 1279 } 1280 } else 1281#endif 1282 if ( op->o_res_ber == NULL ) { 1283 rc = ber_printf( ber, /*{*/ "N}" ); 1284 } 1285 } 1286 1287 if ( rc == -1 ) { 1288 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); 1289 1290 if ( op->o_res_ber == NULL ) ber_free_buf( ber ); 1291 send_ldap_error( op, rs, LDAP_OTHER, "encode entry end error" ); 1292 rc = rs->sr_err; 1293 goto error_return; 1294 } 1295 1296 Statslog( LDAP_DEBUG_STATS2, "%s ENTRY dn=\"%s\"\n", 1297 op->o_log_prefix, rs->sr_entry->e_nname.bv_val, 0, 0, 0 ); 1298 1299 if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) { 1300 be_entry_release_rw( op, rs->sr_entry, 0 ); 1301 rs->sr_flags ^= REP_ENTRY_MUSTRELEASE; 1302 rs->sr_entry = NULL; 1303 } 1304 1305 if ( op->o_res_ber == NULL ) { 1306 bytes = send_ldap_ber( op, ber ); 1307 ber_free_buf( ber ); 1308 1309 if ( bytes < 0 ) { 1310 Debug( LDAP_DEBUG_ANY, 1311 "send_search_entry: conn %lu ber write failed.\n", 1312 op->o_connid, 0, 0 ); 1313 1314 rc = LDAP_UNAVAILABLE; 1315 goto error_return; 1316 } 1317 rs->sr_nentries++; 1318 1319 ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex ); 1320 ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes ); 1321 ldap_pvt_mp_add_ulong( op->o_counters->sc_entries, 1 ); 1322 ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 ); 1323 ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex ); 1324 } 1325 1326 Debug( LDAP_DEBUG_TRACE, 1327 "<= send_search_entry: conn %lu exit.\n", op->o_connid, 0, 0 ); 1328 1329 rc = LDAP_SUCCESS; 1330 1331error_return:; 1332 if ( op->o_callback ) { 1333 (void)slap_cleanup_play( op, rs ); 1334 } 1335 1336 if ( e_flags ) { 1337 slap_sl_free( e_flags, op->o_tmpmemctx ); 1338 } 1339 1340 if ( rs->sr_operational_attrs ) { 1341 attrs_free( rs->sr_operational_attrs ); 1342 rs->sr_operational_attrs = NULL; 1343 } 1344 rs->sr_attr_flags = SLAP_ATTRS_UNDEFINED; 1345 1346 /* FIXME: I think rs->sr_type should be explicitly set to 1347 * REP_SEARCH here. That's what it was when we entered this 1348 * function. send_ldap_error may have changed it, but we 1349 * should set it back so that the cleanup functions know 1350 * what they're doing. 1351 */ 1352 if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH 1353 && rs->sr_entry 1354 && ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) ) 1355 { 1356 entry_free( rs->sr_entry ); 1357 rs->sr_entry = NULL; 1358 rs->sr_flags &= ~REP_ENTRY_MUSTBEFREED; 1359 } 1360 1361 return( rc ); 1362} 1363 1364int 1365slap_send_search_reference( Operation *op, SlapReply *rs ) 1366{ 1367 BerElementBuffer berbuf; 1368 BerElement *ber = (BerElement *) &berbuf; 1369 int rc = 0; 1370 int bytes; 1371 char *edn = rs->sr_entry ? rs->sr_entry->e_name.bv_val : "(null)"; 1372 1373 AttributeDescription *ad_ref = slap_schema.si_ad_ref; 1374 AttributeDescription *ad_entry = slap_schema.si_ad_entry; 1375 1376 rs->sr_type = REP_SEARCHREF; 1377 if ( op->o_callback ) { 1378 rc = slap_response_play( op, rs ); 1379 if ( rc != SLAP_CB_CONTINUE ) { 1380 goto rel; 1381 } 1382 } 1383 1384 Debug( LDAP_DEBUG_TRACE, 1385 "=> send_search_reference: dn=\"%s\"\n", 1386 edn, 0, 0 ); 1387 1388 if ( rs->sr_entry && ! access_allowed( op, rs->sr_entry, 1389 ad_entry, NULL, ACL_READ, NULL ) ) 1390 { 1391 Debug( LDAP_DEBUG_ACL, 1392 "send_search_reference: access to entry not allowed\n", 1393 0, 0, 0 ); 1394 rc = 1; 1395 goto rel; 1396 } 1397 1398 if ( rs->sr_entry && ! access_allowed( op, rs->sr_entry, 1399 ad_ref, NULL, ACL_READ, NULL ) ) 1400 { 1401 Debug( LDAP_DEBUG_ACL, 1402 "send_search_reference: access " 1403 "to reference not allowed\n", 1404 0, 0, 0 ); 1405 rc = 1; 1406 goto rel; 1407 } 1408 1409 if( op->o_domain_scope ) { 1410 Debug( LDAP_DEBUG_ANY, 1411 "send_search_reference: domainScope control in (%s)\n", 1412 edn, 0, 0 ); 1413 rc = 0; 1414 goto rel; 1415 } 1416 1417 if( rs->sr_ref == NULL ) { 1418 Debug( LDAP_DEBUG_ANY, 1419 "send_search_reference: null ref in (%s)\n", 1420 edn, 0, 0 ); 1421 rc = 1; 1422 goto rel; 1423 } 1424 1425 if( op->o_protocol < LDAP_VERSION3 ) { 1426 rc = 0; 1427 /* save the references for the result */ 1428 if( rs->sr_ref[0].bv_val != NULL ) { 1429 if( value_add( &rs->sr_v2ref, rs->sr_ref ) ) 1430 rc = LDAP_OTHER; 1431 } 1432 goto rel; 1433 } 1434 1435#ifdef LDAP_CONNECTIONLESS 1436 if( op->o_conn && op->o_conn->c_is_udp ) { 1437 ber = op->o_res_ber; 1438 } else 1439#endif 1440 { 1441 ber_init_w_nullc( ber, LBER_USE_DER ); 1442 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 1443 } 1444 1445 rc = ber_printf( ber, "{it{W}" /*"}"*/ , op->o_msgid, 1446 LDAP_RES_SEARCH_REFERENCE, rs->sr_ref ); 1447 1448 if( rc != -1 ) { 1449 rc = send_ldap_controls( op, ber, rs->sr_ctrls ); 1450 } 1451 1452 if( rc != -1 ) { 1453 rc = ber_printf( ber, /*"{"*/ "N}" ); 1454 } 1455 1456 if ( rc == -1 ) { 1457 Debug( LDAP_DEBUG_ANY, 1458 "send_search_reference: ber_printf failed\n", 0, 0, 0 ); 1459 1460#ifdef LDAP_CONNECTIONLESS 1461 if (!op->o_conn || op->o_conn->c_is_udp == 0) 1462#endif 1463 ber_free_buf( ber ); 1464 send_ldap_error( op, rs, LDAP_OTHER, "encode DN error" ); 1465 goto rel; 1466 } 1467 1468 rc = 0; 1469 if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) { 1470 assert( rs->sr_entry != NULL ); 1471 be_entry_release_rw( op, rs->sr_entry, 0 ); 1472 rs->sr_flags ^= REP_ENTRY_MUSTRELEASE; 1473 rs->sr_entry = NULL; 1474 } 1475 1476#ifdef LDAP_CONNECTIONLESS 1477 if (!op->o_conn || op->o_conn->c_is_udp == 0) { 1478#endif 1479 bytes = send_ldap_ber( op, ber ); 1480 ber_free_buf( ber ); 1481 1482 if ( bytes < 0 ) { 1483 rc = LDAP_UNAVAILABLE; 1484 } else { 1485 ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex ); 1486 ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes ); 1487 ldap_pvt_mp_add_ulong( op->o_counters->sc_refs, 1 ); 1488 ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 ); 1489 ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex ); 1490 } 1491#ifdef LDAP_CONNECTIONLESS 1492 } 1493#endif 1494 if ( rs->sr_ref != NULL ) { 1495 int r; 1496 1497 for ( r = 0; !BER_BVISNULL( &rs->sr_ref[ r ] ); r++ ) { 1498 Statslog( LDAP_DEBUG_STATS2, "%s REF #%d \"%s\"\n", 1499 op->o_log_prefix, r, rs->sr_ref[0].bv_val, 1500 0, 0 ); 1501 } 1502 1503 } else { 1504 Statslog( LDAP_DEBUG_STATS2, "%s REF \"(null)\"\n", 1505 op->o_log_prefix, 0, 0, 0, 0 ); 1506 } 1507 1508 Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 ); 1509 1510rel: 1511 if ( op->o_callback ) { 1512 (void)slap_cleanup_play( op, rs ); 1513 } 1514 1515 return rc; 1516} 1517 1518int 1519str2result( 1520 char *s, 1521 int *code, 1522 char **matched, 1523 char **info ) 1524{ 1525 int rc; 1526 char *c; 1527 1528 *code = LDAP_SUCCESS; 1529 *matched = NULL; 1530 *info = NULL; 1531 1532 if ( strncasecmp( s, "RESULT", STRLENOF( "RESULT" ) ) != 0 ) { 1533 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n", 1534 s, 0, 0 ); 1535 1536 return( -1 ); 1537 } 1538 1539 rc = 0; 1540 while ( (s = strchr( s, '\n' )) != NULL ) { 1541 *s++ = '\0'; 1542 if ( *s == '\0' ) { 1543 break; 1544 } 1545 if ( (c = strchr( s, ':' )) != NULL ) { 1546 c++; 1547 } 1548 1549 if ( strncasecmp( s, "code", STRLENOF( "code" ) ) == 0 ) { 1550 char *next = NULL; 1551 long retcode; 1552 1553 if ( c == NULL ) { 1554 Debug( LDAP_DEBUG_ANY, "str2result (%s) missing value\n", 1555 s, 0, 0 ); 1556 rc = -1; 1557 continue; 1558 } 1559 1560 while ( isspace( (unsigned char) c[ 0 ] ) ) c++; 1561 if ( c[ 0 ] == '\0' ) { 1562 Debug( LDAP_DEBUG_ANY, "str2result (%s) missing or empty value\n", 1563 s, 0, 0 ); 1564 rc = -1; 1565 continue; 1566 } 1567 1568 retcode = strtol( c, &next, 10 ); 1569 if ( next == NULL || next == c ) { 1570 Debug( LDAP_DEBUG_ANY, "str2result (%s) unable to parse value\n", 1571 s, 0, 0 ); 1572 rc = -1; 1573 continue; 1574 } 1575 1576 while ( isspace( (unsigned char) next[ 0 ] ) ) next++; 1577 if ( next[ 0 ] != '\0' ) { 1578 Debug( LDAP_DEBUG_ANY, "str2result (%s) extra cruft after value\n", 1579 s, 0, 0 ); 1580 rc = -1; 1581 continue; 1582 } 1583 1584 /* FIXME: what if it's larger that max int? */ 1585 *code = (int)retcode; 1586 1587 } else if ( strncasecmp( s, "matched", STRLENOF( "matched" ) ) == 0 ) { 1588 if ( c != NULL ) { 1589 *matched = c; 1590 } 1591 } else if ( strncasecmp( s, "info", STRLENOF( "info" ) ) == 0 ) { 1592 if ( c != NULL ) { 1593 *info = c; 1594 } 1595 } else { 1596 Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n", 1597 s, 0, 0 ); 1598 1599 rc = -1; 1600 } 1601 } 1602 1603 return( rc ); 1604} 1605 1606int slap_read_controls( 1607 Operation *op, 1608 SlapReply *rs, 1609 Entry *e, 1610 const struct berval *oid, 1611 LDAPControl **ctrl ) 1612{ 1613 int rc; 1614 struct berval bv; 1615 BerElementBuffer berbuf; 1616 BerElement *ber = (BerElement *) &berbuf; 1617 LDAPControl c; 1618 Operation myop; 1619 1620 Debug( LDAP_DEBUG_ANY, "%s slap_read_controls: (%s) %s\n", 1621 op->o_log_prefix, oid->bv_val, e->e_dn ); 1622 1623 rs->sr_entry = e; 1624 rs->sr_attrs = ( oid == &slap_pre_read_bv ) ? 1625 op->o_preread_attrs : op->o_postread_attrs; 1626 1627 bv.bv_len = entry_flatsize( rs->sr_entry, 0 ); 1628 bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx ); 1629 1630 ber_init2( ber, &bv, LBER_USE_DER ); 1631 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 1632 1633 /* create new operation */ 1634 myop = *op; 1635 /* FIXME: o_bd needed for ACL */ 1636 myop.o_bd = op->o_bd; 1637 myop.o_res_ber = ber; 1638 myop.o_callback = NULL; 1639 myop.ors_slimit = 1; 1640 1641 rc = slap_send_search_entry( &myop, rs ); 1642 if( rc ) return rc; 1643 1644 rc = ber_flatten2( ber, &c.ldctl_value, 0 ); 1645 1646 if( rc == -1 ) return LDAP_OTHER; 1647 1648 c.ldctl_oid = oid->bv_val; 1649 c.ldctl_iscritical = 0; 1650 1651 if ( *ctrl == NULL ) { 1652 /* first try */ 1653 *ctrl = (LDAPControl *) slap_sl_calloc( 1, sizeof(LDAPControl), NULL ); 1654 } else { 1655 /* retry: free previous try */ 1656 slap_sl_free( (*ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 1657 } 1658 1659 **ctrl = c; 1660 return LDAP_SUCCESS; 1661} 1662 1663/* Map API errors to protocol errors... */ 1664int 1665slap_map_api2result( SlapReply *rs ) 1666{ 1667 switch(rs->sr_err) { 1668 case LDAP_SERVER_DOWN: 1669 return LDAP_UNAVAILABLE; 1670 case LDAP_LOCAL_ERROR: 1671 return LDAP_OTHER; 1672 case LDAP_ENCODING_ERROR: 1673 case LDAP_DECODING_ERROR: 1674 return LDAP_PROTOCOL_ERROR; 1675 case LDAP_TIMEOUT: 1676 return LDAP_UNAVAILABLE; 1677 case LDAP_AUTH_UNKNOWN: 1678 return LDAP_AUTH_METHOD_NOT_SUPPORTED; 1679 case LDAP_FILTER_ERROR: 1680 rs->sr_text = "Filter error"; 1681 return LDAP_OTHER; 1682 case LDAP_USER_CANCELLED: 1683 rs->sr_text = "User cancelled"; 1684 return LDAP_OTHER; 1685 case LDAP_PARAM_ERROR: 1686 return LDAP_PROTOCOL_ERROR; 1687 case LDAP_NO_MEMORY: 1688 return LDAP_OTHER; 1689 case LDAP_CONNECT_ERROR: 1690 return LDAP_UNAVAILABLE; 1691 case LDAP_NOT_SUPPORTED: 1692 return LDAP_UNWILLING_TO_PERFORM; 1693 case LDAP_CONTROL_NOT_FOUND: 1694 return LDAP_PROTOCOL_ERROR; 1695 case LDAP_NO_RESULTS_RETURNED: 1696 return LDAP_NO_SUCH_OBJECT; 1697 case LDAP_MORE_RESULTS_TO_RETURN: 1698 rs->sr_text = "More results to return"; 1699 return LDAP_OTHER; 1700 case LDAP_CLIENT_LOOP: 1701 case LDAP_REFERRAL_LIMIT_EXCEEDED: 1702 return LDAP_LOOP_DETECT; 1703 default: 1704 if ( LDAP_API_ERROR(rs->sr_err) ) return LDAP_OTHER; 1705 return rs->sr_err; 1706 } 1707} 1708 1709 1710slap_mask_t 1711slap_attr_flags( AttributeName *an ) 1712{ 1713 slap_mask_t flags = SLAP_ATTRS_UNDEFINED; 1714 1715 if ( an == NULL ) { 1716 flags |= ( SLAP_OPATTRS_NO | SLAP_USERATTRS_YES ); 1717 1718 } else { 1719 flags |= an_find( an, slap_bv_all_operational_attrs ) 1720 ? SLAP_OPATTRS_YES : SLAP_OPATTRS_NO; 1721 flags |= an_find( an, slap_bv_all_user_attrs ) 1722 ? SLAP_USERATTRS_YES : SLAP_USERATTRS_NO; 1723 } 1724 1725 return flags; 1726} 1727