Back to index

openldap  2.4.31
search.c
Go to the documentation of this file.
00001 /* search.c - ldap backend search function */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1999-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 1999-2003 Howard Chu.
00007  * Portions Copyright 2000-2003 Pierangelo Masarati.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted only as authorized by the OpenLDAP
00012  * Public License.
00013  *
00014  * A copy of this license is available in the file LICENSE in the
00015  * top-level directory of the distribution or, alternatively, at
00016  * <http://www.OpenLDAP.org/license.html>.
00017  */
00018 /* ACKNOWLEDGEMENTS:
00019  * This work was initially developed by the Howard Chu for inclusion
00020  * in OpenLDAP Software and subsequently enhanced by Pierangelo
00021  * Masarati.
00022  */
00023 
00024 #include "portable.h"
00025 
00026 #include <stdio.h>
00027 
00028 #include <ac/socket.h>
00029 #include <ac/string.h>
00030 #include <ac/time.h>
00031 
00032 #include "slap.h"
00033 #include "back-ldap.h"
00034 #include "../../../libraries/liblber/lber-int.h"
00035 
00036 #include "lutil.h"
00037 
00038 static int
00039 ldap_build_entry( Operation *op, LDAPMessage *e, Entry *ent,
00040         struct berval *bdn );
00041 
00042 /*
00043  * replaces (&) with (objectClass=*) and (|) with (!(objectClass=*))
00044  * as the best replacement for RFC 4526 absolute true/absolute false
00045  * filters; the only difference (AFAIK) is that they require search
00046  * access to objectClass.
00047  *
00048  * filter->bv_val may be alloc'd on the thread's slab, if equal to
00049  * op->ors_filterstr.bv_val, or realloc'd on the thread's slab otherwise.
00050  */
00051 static int
00052 ldap_back_munge_filter(
00053        Operation     *op,
00054        struct berval *filter )
00055 {
00056        char *ptr;
00057        int gotit = 0;
00058 
00059        Debug( LDAP_DEBUG_ARGS, "=> ldap_back_munge_filter \"%s\"\n",
00060                      filter->bv_val, 0, 0 );
00061 
00062        for ( ptr = strchr( filter->bv_val, '(' ); 
00063                      ptr;
00064                      ptr = strchr( ptr, '(' ) )
00065        {
00066               static struct berval
00067                      bv_t = BER_BVC( "(&)" ),
00068                      bv_f = BER_BVC( "(|)" ),
00069                      bv_T = BER_BVC( "(objectClass=*)" ),
00070                      bv_F = BER_BVC( "(!(objectClass=*))" );
00071               struct berval *oldbv = NULL,
00072                      *newbv = NULL,
00073                      oldfilter = BER_BVNULL;
00074 
00075               if ( ptr[2] != ')' ) {
00076                      ptr++;
00077                      continue;
00078               }
00079 
00080               switch ( ptr[1] ) {
00081               case '&':
00082                      oldbv = &bv_t;
00083                      newbv = &bv_T;
00084                      break;
00085 
00086               case '|':
00087                      oldbv = &bv_f;
00088                      newbv = &bv_F;
00089                      break;
00090 
00091               default:
00092                      /* should be an error */
00093                      continue;
00094               }
00095 
00096               oldfilter = *filter;
00097               filter->bv_len += newbv->bv_len - oldbv->bv_len;
00098               if ( filter->bv_val == op->ors_filterstr.bv_val ) {
00099                      filter->bv_val = op->o_tmpalloc( filter->bv_len + 1,
00100                                    op->o_tmpmemctx );
00101 
00102                      AC_MEMCPY( filter->bv_val, op->ors_filterstr.bv_val,
00103                                    ptr - oldfilter.bv_val );
00104 
00105               } else {
00106                      filter->bv_val = op->o_tmprealloc( filter->bv_val,
00107                                    filter->bv_len + 1, op->o_tmpmemctx );
00108               }
00109 
00110               ptr = filter->bv_val + ( ptr - oldfilter.bv_val );
00111 
00112               AC_MEMCPY( &ptr[ newbv->bv_len ],
00113                             &ptr[ oldbv->bv_len ], 
00114                             oldfilter.bv_len - ( ptr - filter->bv_val ) - oldbv->bv_len + 1 );
00115               AC_MEMCPY( ptr, newbv->bv_val, newbv->bv_len );
00116 
00117               ptr += newbv->bv_len;
00118 
00119               gotit++;
00120        }
00121 
00122        Debug( LDAP_DEBUG_ARGS, "<= ldap_back_munge_filter \"%s\" (%d)\n",
00123                      filter->bv_val, gotit, 0 );
00124 
00125        return gotit;
00126 }
00127 
00128 int
00129 ldap_back_search(
00130               Operation     *op,
00131               SlapReply     *rs )
00132 {
00133        ldapinfo_t    *li = (ldapinfo_t *) op->o_bd->be_private;
00134 
00135        ldapconn_t    *lc = NULL;
00136        struct timeval       tv;
00137        time_t        stoptime = (time_t)(-1);
00138        LDAPMessage   *res,
00139                      *e;
00140        int           rc = 0,
00141                      msgid; 
00142        struct berval match = BER_BVNULL,
00143                      filter = BER_BVNULL;
00144        int           i, x;
00145        char          **attrs = NULL;
00146        int           freetext = 0, filter_undef = 0;
00147        int           do_retry = 1, dont_retry = 0;
00148        LDAPControl   **ctrls = NULL;
00149        char          **references = NULL;
00150 
00151        rs_assert_ready( rs );
00152        rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */
00153 
00154        if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
00155               return rs->sr_err;
00156        }
00157 
00158        /*
00159         * FIXME: in case of values return filter, we might want
00160         * to map attrs and maybe rewrite value
00161         */
00162 
00163        if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
00164               tv.tv_sec = op->ors_tlimit;
00165               tv.tv_usec = 0;
00166               stoptime = op->o_time + op->ors_tlimit;
00167 
00168        } else {
00169               LDAP_BACK_TV_SET( &tv );
00170        }
00171 
00172        i = 0;
00173        if ( op->ors_attrs ) {
00174               for ( ; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ )
00175                      /* just count attrs */ ;
00176        }
00177 
00178        x = 0;
00179        if ( op->o_bd->be_extra_anlist ) {
00180               for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ )
00181                      /* just count attrs */ ;
00182        }
00183 
00184        if ( i > 0 || x > 0 ) {
00185               int j = 0;
00186 
00187               attrs = op->o_tmpalloc( ( i + x + 1 )*sizeof( char * ),
00188                      op->o_tmpmemctx );
00189               if ( attrs == NULL ) {
00190                      rs->sr_err = LDAP_NO_MEMORY;
00191                      rc = -1;
00192                      goto finish;
00193               }
00194 
00195               if ( i > 0 ) {       
00196                      for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++, j++ ) {
00197                             attrs[ j ] = op->ors_attrs[i].an_name.bv_val;
00198                      }
00199               }
00200 
00201               if ( x > 0 ) {
00202                      for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++, j++ ) {
00203                             if ( op->o_bd->be_extra_anlist[x].an_desc &&
00204                                    ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, op->ors_attrs ) )
00205                             {
00206                                    continue;
00207                             }
00208 
00209                             attrs[ j ] = op->o_bd->be_extra_anlist[x].an_name.bv_val;
00210                      }
00211               }
00212 
00213               attrs[ j ] = NULL;
00214        }
00215 
00216        ctrls = op->o_ctrls;
00217        rc = ldap_back_controls_add( op, rs, lc, &ctrls );
00218        if ( rc != LDAP_SUCCESS ) {
00219               goto finish;
00220        }
00221 
00222        /* deal with <draft-zeilenga-ldap-t-f> filters */
00223        filter = op->ors_filterstr;
00224 retry:
00225        /* this goes after retry because ldap_back_munge_filter()
00226         * optionally replaces RFC 4526 T-F filters (&) (|)
00227         * if already computed, they will be re-installed
00228         * by filter2bv_undef_x() later */
00229        if ( !LDAP_BACK_T_F( li ) ) {
00230               ldap_back_munge_filter( op, &filter );
00231        }
00232 
00233        rs->sr_err = ldap_pvt_search( lc->lc_ld, op->o_req_dn.bv_val,
00234                      op->ors_scope, filter.bv_val,
00235                      attrs, op->ors_attrsonly, ctrls, NULL,
00236                      tv.tv_sec ? &tv : NULL,
00237                      op->ors_slimit, op->ors_deref, &msgid );
00238 
00239        if ( rs->sr_err != LDAP_SUCCESS ) {
00240               switch ( rs->sr_err ) {
00241               case LDAP_SERVER_DOWN:
00242                      if ( do_retry ) {
00243                             do_retry = 0;
00244                             if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) {
00245                                    goto retry;
00246                             }
00247                      }
00248 
00249                      if ( lc == NULL ) {
00250                             /* reset by ldap_back_retry ... */
00251                             rs->sr_err = slap_map_api2result( rs );
00252 
00253                      } else {
00254                             rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_DONTSEND );
00255                      }
00256                             
00257                      goto finish;
00258 
00259               case LDAP_FILTER_ERROR:
00260                      /* first try? */
00261                      if ( !filter_undef &&
00262                             strstr( filter.bv_val, "(?" ) &&
00263                             !LDAP_BACK_NOUNDEFFILTER( li ) )
00264                      {
00265                             BER_BVZERO( &filter );
00266                             filter2bv_undef_x( op, op->ors_filter, 1, &filter );
00267                             filter_undef = 1;
00268                             goto retry;
00269                      }
00270 
00271                      /* invalid filters return success with no data */
00272                      rs->sr_err = LDAP_SUCCESS;
00273                      rs->sr_text = NULL;
00274                      goto finish;
00275               
00276               default:
00277                      rs->sr_err = slap_map_api2result( rs );
00278                      rs->sr_text = NULL;
00279                      goto finish;
00280               }
00281        }
00282 
00283        /* if needed, initialize timeout */
00284        if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
00285               if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) {
00286                      tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ];
00287                      tv.tv_usec = 0;
00288               }
00289        }
00290 
00291        /* We pull apart the ber result, stuff it into a slapd entry, and
00292         * let send_search_entry stuff it back into ber format. Slow & ugly,
00293         * but this is necessary for version matching, and for ACL processing.
00294         */
00295 
00296        for ( rc = -2; rc != -1; rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ONE, &tv, &res ) )
00297        {
00298               /* check for abandon */
00299               if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( lc ) ) {
00300                      if ( rc > 0 ) {
00301                             ldap_msgfree( res );
00302                      }
00303                      (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
00304                      rc = SLAPD_ABANDON;
00305                      goto finish;
00306               }
00307 
00308               if ( rc == 0 || rc == -2 ) {
00309                      ldap_pvt_thread_yield();
00310 
00311                      /* check timeout */
00312                      if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
00313                             if ( rc == 0 ) {
00314                                    (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
00315                                    rs->sr_text = "Operation timed out";
00316                                    rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
00317                                           LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
00318                                    goto finish;
00319                             }
00320 
00321                      } else {
00322                             LDAP_BACK_TV_SET( &tv );
00323                      }
00324 
00325                      /* check time limit */
00326                      if ( op->ors_tlimit != SLAP_NO_LIMIT
00327                                    && slap_get_time() > stoptime )
00328                      {
00329                             (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
00330                             rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
00331                             goto finish;
00332                      }
00333                      continue;
00334 
00335               } else {
00336                      /* only touch when activity actually took place... */
00337                      if ( li->li_idle_timeout && lc ) {
00338                             lc->lc_time = op->o_time;
00339                      }
00340 
00341                      /* don't retry any more */
00342                      dont_retry = 1;
00343               }
00344 
00345 
00346               if ( rc == LDAP_RES_SEARCH_ENTRY ) {
00347                      Entry         ent = { 0 };
00348                      struct berval bdn = BER_BVNULL;
00349 
00350                      do_retry = 0;
00351 
00352                      e = ldap_first_entry( lc->lc_ld, res );
00353                      rc = ldap_build_entry( op, e, &ent, &bdn );
00354                      if ( rc == LDAP_SUCCESS ) {
00355                             ldap_get_entry_controls( lc->lc_ld, res, &rs->sr_ctrls );
00356                             rs->sr_entry = &ent;
00357                             rs->sr_attrs = op->ors_attrs;
00358                             rs->sr_operational_attrs = NULL;
00359                             rs->sr_flags = 0;
00360                             rs->sr_err = LDAP_SUCCESS;
00361                             rc = rs->sr_err = send_search_entry( op, rs );
00362                             if ( rs->sr_ctrls ) {
00363                                    ldap_controls_free( rs->sr_ctrls );
00364                                    rs->sr_ctrls = NULL;
00365                             }
00366                             rs->sr_entry = NULL;
00367                             rs->sr_flags = 0;
00368                             if ( !BER_BVISNULL( &ent.e_name ) ) {
00369                                    assert( ent.e_name.bv_val != bdn.bv_val );
00370                                    op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx );
00371                                    BER_BVZERO( &ent.e_name );
00372                             }
00373                             if ( !BER_BVISNULL( &ent.e_nname ) ) {
00374                                    op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx );
00375                                    BER_BVZERO( &ent.e_nname );
00376                             }
00377                             entry_clean( &ent );
00378                      }
00379                      ldap_msgfree( res );
00380                      switch ( rc ) {
00381                      case LDAP_SUCCESS:
00382                      case LDAP_INSUFFICIENT_ACCESS:
00383                             break;
00384 
00385                      default:
00386                             if ( rc == LDAP_UNAVAILABLE ) {
00387                                    rc = rs->sr_err = LDAP_OTHER;
00388                             } else {
00389                                    (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
00390                             }
00391                             goto finish;
00392                      }
00393 
00394               } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
00395                      if ( LDAP_BACK_NOREFS( li ) ) {
00396                             ldap_msgfree( res );
00397                             continue;
00398                      }
00399 
00400                      do_retry = 0;
00401                      rc = ldap_parse_reference( lc->lc_ld, res,
00402                                    &references, &rs->sr_ctrls, 1 );
00403 
00404                      if ( rc != LDAP_SUCCESS ) {
00405                             continue;
00406                      }
00407 
00408                      /* FIXME: there MUST be at least one */
00409                      if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) {
00410                             int           cnt;
00411 
00412                             for ( cnt = 0; references[ cnt ]; cnt++ )
00413                                    /* NO OP */ ;
00414 
00415                             /* FIXME: there MUST be at least one */
00416                             rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
00417                                    op->o_tmpmemctx );
00418 
00419                             for ( cnt = 0; references[ cnt ]; cnt++ ) {
00420                                    ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
00421                             }
00422                             BER_BVZERO( &rs->sr_ref[ cnt ] );
00423 
00424                             /* ignore return value by now */
00425                             RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
00426                             rs->sr_entry = NULL;
00427                             ( void )send_search_reference( op, rs );
00428 
00429                      } else {
00430                             Debug( LDAP_DEBUG_ANY,
00431                                    "%s ldap_back_search: "
00432                                    "got SEARCH_REFERENCE "
00433                                    "with no referrals\n",
00434                                    op->o_log_prefix, 0, 0 );
00435                      }
00436 
00437                      /* cleanup */
00438                      if ( references ) {
00439                             ber_memvfree( (void **)references );
00440                             op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
00441                             rs->sr_ref = NULL;
00442                             references = NULL;
00443                      }
00444 
00445                      if ( rs->sr_ctrls ) {
00446                             ldap_controls_free( rs->sr_ctrls );
00447                             rs->sr_ctrls = NULL;
00448                      }
00449 
00450               } else if ( rc == LDAP_RES_INTERMEDIATE ) {
00451                      /* FIXME: response controls
00452                       * are passed without checks */
00453                      rc = ldap_parse_intermediate( lc->lc_ld,
00454                             res,
00455                             (char **)&rs->sr_rspoid,
00456                             &rs->sr_rspdata,
00457                             &rs->sr_ctrls,
00458                             0 );
00459                      if ( rc != LDAP_SUCCESS ) {
00460                             continue;
00461                      }
00462 
00463                      slap_send_ldap_intermediate( op, rs );
00464 
00465                      if ( rs->sr_rspoid != NULL ) {
00466                             ber_memfree( (char *)rs->sr_rspoid );
00467                             rs->sr_rspoid = NULL;
00468                      }
00469 
00470                      if ( rs->sr_rspdata != NULL ) {
00471                             ber_bvfree( rs->sr_rspdata );
00472                             rs->sr_rspdata = NULL;
00473                      }
00474 
00475                      if ( rs->sr_ctrls != NULL ) {
00476                             ldap_controls_free( rs->sr_ctrls );
00477                             rs->sr_ctrls = NULL;
00478                      }
00479 
00480               } else {
00481                      char          *err = NULL;
00482 
00483                      rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
00484                                    &match.bv_val, &err,
00485                                    &references, &rs->sr_ctrls, 1 );
00486                      if ( rc == LDAP_SUCCESS ) {
00487                             if ( err ) {
00488                                    rs->sr_text = err;
00489                                    freetext = 1;
00490                             }
00491                      } else {
00492                             rs->sr_err = rc;
00493                      }
00494                      rs->sr_err = slap_map_api2result( rs );
00495 
00496                      /* RFC 4511: referrals can only appear
00497                       * if result code is LDAP_REFERRAL */
00498                      if ( references 
00499                             && references[ 0 ]
00500                             && references[ 0 ][ 0 ] )
00501                      {
00502                             if ( rs->sr_err != LDAP_REFERRAL ) {
00503                                    Debug( LDAP_DEBUG_ANY,
00504                                           "%s ldap_back_search: "
00505                                           "got referrals with err=%d\n",
00506                                           op->o_log_prefix,
00507                                           rs->sr_err, 0 );
00508 
00509                             } else {
00510                                    int    cnt;
00511 
00512                                    for ( cnt = 0; references[ cnt ]; cnt++ )
00513                                           /* NO OP */ ;
00514                             
00515                                    rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
00516                                           op->o_tmpmemctx );
00517 
00518                                    for ( cnt = 0; references[ cnt ]; cnt++ ) {
00519                                           /* duplicating ...*/
00520                                           ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
00521                                    }
00522                                    BER_BVZERO( &rs->sr_ref[ cnt ] );
00523                             }
00524 
00525                      } else if ( rs->sr_err == LDAP_REFERRAL ) {
00526                             Debug( LDAP_DEBUG_ANY,
00527                                    "%s ldap_back_search: "
00528                                    "got err=%d with null "
00529                                    "or empty referrals\n",
00530                                    op->o_log_prefix,
00531                                    rs->sr_err, 0 );
00532 
00533                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
00534                      }
00535 
00536                      if ( match.bv_val != NULL ) {
00537                             match.bv_len = strlen( match.bv_val );
00538                      }
00539 
00540                      rc = 0;
00541                      break;
00542               }
00543 
00544               /* if needed, restore timeout */
00545               if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
00546                      if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) {
00547                             tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ];
00548                             tv.tv_usec = 0;
00549                      }
00550               }
00551        }
00552 
00553        if ( rc == -1 && dont_retry == 0 ) {
00554               if ( do_retry ) {
00555                      do_retry = 0;
00556                      if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) {
00557                             goto retry;
00558                      }
00559               }
00560               rs->sr_err = LDAP_SERVER_DOWN;
00561               rs->sr_err = slap_map_api2result( rs );
00562               goto finish;
00563        }
00564 
00565        /*
00566         * Rewrite the matched portion of the search base, if required
00567         */
00568        if ( !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) {
00569               struct berval pmatch;
00570 
00571               if ( dnPretty( NULL, &match, &pmatch, op->o_tmpmemctx ) != LDAP_SUCCESS ) {
00572                      pmatch.bv_val = match.bv_val;
00573                      match.bv_val = NULL;
00574               }
00575               rs->sr_matched = pmatch.bv_val;
00576               rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
00577        }
00578        if ( !BER_BVISNULL( &match ) ) {
00579               ber_memfree( match.bv_val );
00580        }
00581 
00582        if ( rs->sr_v2ref ) {
00583               rs->sr_err = LDAP_REFERRAL;
00584        }
00585 
00586 finish:;
00587        if ( LDAP_BACK_QUARANTINE( li ) ) {
00588               ldap_back_quarantine( op, rs );
00589        }
00590 
00591        if ( filter.bv_val != op->ors_filterstr.bv_val ) {
00592               op->o_tmpfree( filter.bv_val, op->o_tmpmemctx );
00593        }
00594 
00595 #if 0
00596        /* let send_ldap_result play cleanup handlers (ITS#4645) */
00597        if ( rc != SLAPD_ABANDON )
00598 #endif
00599        {
00600               send_ldap_result( op, rs );
00601        }
00602 
00603        (void)ldap_back_controls_free( op, rs, &ctrls );
00604 
00605        if ( rs->sr_ctrls ) {
00606               ldap_controls_free( rs->sr_ctrls );
00607               rs->sr_ctrls = NULL;
00608        }
00609 
00610        if ( rs->sr_text ) {
00611               if ( freetext ) {
00612                      ber_memfree( (char *)rs->sr_text );
00613               }
00614               rs->sr_text = NULL;
00615        }
00616 
00617        if ( rs->sr_ref ) {
00618               op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
00619               rs->sr_ref = NULL;
00620        }
00621 
00622        if ( references ) {
00623               ber_memvfree( (void **)references );
00624        }
00625 
00626        if ( attrs ) {
00627               op->o_tmpfree( attrs, op->o_tmpmemctx );
00628        }
00629 
00630        if ( lc != NULL ) {
00631               ldap_back_release_conn( li, lc );
00632        }
00633 
00634        return rs->sr_err;
00635 }
00636 
00637 static int
00638 ldap_build_entry(
00639               Operation     *op,
00640               LDAPMessage   *e,
00641               Entry         *ent,
00642               struct berval *bdn )
00643 {
00644        struct berval a;
00645        BerElement    ber = *ldap_get_message_ber( e );
00646        Attribute     *attr, **attrp;
00647        const char    *text;
00648        int           last;
00649        char *lastb;
00650        ber_len_t len;
00651 
00652        /* safe assumptions ... */
00653        assert( ent != NULL );
00654        BER_BVZERO( &ent->e_bv );
00655 
00656        if ( ber_scanf( &ber, "{m", bdn ) == LBER_ERROR ) {
00657               return LDAP_DECODING_ERROR;
00658        }
00659 
00660        /*
00661         * Note: this may fail if the target host(s) schema differs
00662         * from the one known to the meta, and a DN with unknown
00663         * attributes is returned.
00664         * 
00665         * FIXME: should we log anything, or delegate to dnNormalize?
00666         */
00667        /* Note: if the distinguished values or the naming attributes
00668         * change, should we massage them as well?
00669         */
00670        if ( dnPrettyNormal( NULL, bdn, &ent->e_name, &ent->e_nname,
00671               op->o_tmpmemctx ) != LDAP_SUCCESS )
00672        {
00673               return LDAP_INVALID_DN_SYNTAX;
00674        }
00675 
00676        ent->e_attrs = NULL;
00677        if ( ber_first_element( &ber, &len, &lastb ) != LBER_SEQUENCE ) {
00678               return LDAP_SUCCESS;
00679        }
00680 
00681        attrp = &ent->e_attrs;
00682        while ( ber_next_element( &ber, &len, lastb ) == LBER_SEQUENCE &&
00683               ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
00684               int                         i;
00685               slap_syntax_validate_func   *validate;
00686               slap_syntax_transform_func  *pretty;
00687 
00688               attr = attr_alloc( NULL );
00689               if ( attr == NULL ) {
00690                      return LDAP_OTHER;
00691               }
00692               if ( slap_bv2ad( &a, &attr->a_desc, &text ) 
00693                             != LDAP_SUCCESS )
00694               {
00695                      if ( slap_bv2undef_ad( &a, &attr->a_desc, &text,
00696                             SLAP_AD_PROXIED ) != LDAP_SUCCESS )
00697                      {
00698                             Debug( LDAP_DEBUG_ANY, 
00699                                    "%s ldap_build_entry: "
00700                                    "slap_bv2undef_ad(%s): %s\n",
00701                                    op->o_log_prefix, a.bv_val, text );
00702 
00703                             ( void )ber_scanf( &ber, "x" /* [W] */ );
00704                             attr_free( attr );
00705                             continue;
00706                      }
00707               }
00708 
00709               /* no subschemaSubentry */
00710               if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
00711                      || attr->a_desc == slap_schema.si_ad_entryDN )
00712               {
00713 
00714                      /* 
00715                       * We eat target's subschemaSubentry because
00716                       * a search for this value is likely not
00717                       * to resolve to the appropriate backend;
00718                       * later, the local subschemaSubentry is
00719                       * added.
00720                       *
00721                       * We also eat entryDN because the frontend
00722                       * will reattach it without checking if already
00723                       * present...
00724                       */
00725                      ( void )ber_scanf( &ber, "x" /* [W] */ );
00726                      attr_free( attr );
00727                      continue;
00728               }
00729               
00730               if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
00731                             || attr->a_vals == NULL )
00732               {
00733                      /*
00734                       * Note: attr->a_vals can be null when using
00735                       * values result filter
00736                       */
00737                      attr->a_vals = (struct berval *)&slap_dummy_bv;
00738               }
00739 
00740               validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
00741               pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
00742 
00743               if ( !validate && !pretty ) {
00744                      attr->a_nvals = NULL;
00745                      attr_free( attr );
00746                      goto next_attr;
00747               }
00748 
00749               for ( i = 0; !BER_BVISNULL( &attr->a_vals[i] ); i++ ) ;
00750               last = i;
00751 
00752               /*
00753                * check that each value is valid per syntax
00754                * and pretty if appropriate
00755                */
00756               for ( i = 0; i<last; i++ ) {
00757                      struct berval pval;
00758                      int           rc;
00759 
00760                      if ( pretty ) {
00761                             rc = ordered_value_pretty( attr->a_desc,
00762                                    &attr->a_vals[i], &pval, NULL );
00763 
00764                      } else {
00765                             rc = ordered_value_validate( attr->a_desc,
00766                                    &attr->a_vals[i], 0 );
00767                      }
00768 
00769                      if ( rc != LDAP_SUCCESS ) {
00770                             ObjectClass *oc;
00771 
00772                             /* check if, by chance, it's an undefined objectClass */
00773                             if ( attr->a_desc == slap_schema.si_ad_objectClass &&
00774                                           ( oc = oc_bvfind_undef( &attr->a_vals[i] ) ) != NULL )
00775                             {
00776                                    ber_dupbv( &pval, &oc->soc_cname );
00777                                    rc = LDAP_SUCCESS;
00778 
00779                             } else {
00780                                    ber_memfree( attr->a_vals[i].bv_val );
00781                                    if ( --last == i ) {
00782                                           BER_BVZERO( &attr->a_vals[i] );
00783                                           break;
00784                                    }
00785                                    attr->a_vals[i] = attr->a_vals[last];
00786                                    BER_BVZERO( &attr->a_vals[last] );
00787                                    i--;
00788                             }
00789                      }
00790 
00791                      if ( rc == LDAP_SUCCESS && pretty ) {
00792                             ber_memfree( attr->a_vals[i].bv_val );
00793                             attr->a_vals[i] = pval;
00794                      }
00795               }
00796               attr->a_numvals = last = i;
00797               if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
00798                      attr->a_nvals = NULL;
00799                      attr_free( attr );
00800                      goto next_attr;
00801               }
00802 
00803               if ( last && attr->a_desc->ad_type->sat_equality &&
00804                             attr->a_desc->ad_type->sat_equality->smr_normalize )
00805               {
00806                      attr->a_nvals = ch_malloc( ( last + 1 )*sizeof( struct berval ) );
00807                      for ( i = 0; i < last; i++ ) {
00808                             int           rc;
00809 
00810                             rc = ordered_value_normalize(
00811                                    SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
00812                                    attr->a_desc,
00813                                    attr->a_desc->ad_type->sat_equality,
00814                                    &attr->a_vals[i], &attr->a_nvals[i],
00815                                    NULL );
00816 
00817                             if ( rc != LDAP_SUCCESS ) {
00818                                    ber_memfree( attr->a_vals[i].bv_val );
00819                                    if ( --last == i ) {
00820                                           BER_BVZERO( &attr->a_vals[i] );
00821                                           break;
00822                                    }
00823                                    attr->a_vals[i] = attr->a_vals[last];
00824                                    BER_BVZERO( &attr->a_vals[last] );
00825                                    i--;
00826                             }
00827                      }
00828                      BER_BVZERO( &attr->a_nvals[i] );
00829                      if ( last == 0 ) {
00830                             attr_free( attr );
00831                             goto next_attr;
00832                      }
00833 
00834               } else {
00835                      attr->a_nvals = attr->a_vals;
00836               }
00837 
00838               attr->a_numvals = last;
00839 
00840               /* Handle sorted vals, strip dups but keep the attr */
00841               if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
00842                      while ( attr->a_numvals > 1 ) {
00843                             int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx );
00844                             if ( rc != LDAP_TYPE_OR_VALUE_EXISTS )
00845                                    break;
00846 
00847                             /* Strip duplicate values */
00848                             if ( attr->a_nvals != attr->a_vals )
00849                                    ber_memfree( attr->a_nvals[i].bv_val );
00850                             ber_memfree( attr->a_vals[i].bv_val );
00851                             attr->a_numvals--;
00852 
00853                             assert( i >= 0 );
00854                             if ( (unsigned)i < attr->a_numvals ) {
00855                                    attr->a_vals[i] = attr->a_vals[attr->a_numvals];
00856                                    if ( attr->a_nvals != attr->a_vals )
00857                                           attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];
00858                             }
00859                             BER_BVZERO(&attr->a_vals[attr->a_numvals]);
00860                             if ( attr->a_nvals != attr->a_vals )
00861                                    BER_BVZERO(&attr->a_nvals[attr->a_numvals]);
00862                      }
00863                      attr->a_flags |= SLAP_ATTR_SORTED_VALS;
00864               }
00865 
00866               *attrp = attr;
00867               attrp = &attr->a_next;
00868 
00869 next_attr:;
00870        }
00871 
00872        return LDAP_SUCCESS;
00873 }
00874 
00875 /* return 0 IFF we can retrieve the entry with ndn
00876  */
00877 int
00878 ldap_back_entry_get(
00879               Operation            *op,
00880               struct berval        *ndn,
00881               ObjectClass          *oc,
00882               AttributeDescription *at,
00883               int                  rw,
00884               Entry                **ent )
00885 {
00886        ldapinfo_t    *li = (ldapinfo_t *) op->o_bd->be_private;
00887 
00888        ldapconn_t    *lc = NULL;
00889        int           rc,
00890                      do_not_cache;
00891        ber_tag_t     tag;
00892        struct berval bdn;
00893        LDAPMessage   *result = NULL,
00894                      *e = NULL;
00895        char          *attr[3], **attrp = NULL;
00896        char          *filter = NULL;
00897        SlapReply     rs;
00898        int           do_retry = 1;
00899        LDAPControl   **ctrls = NULL;
00900 
00901        *ent = NULL;
00902 
00903        /* Tell getconn this is a privileged op */
00904        do_not_cache = op->o_do_not_cache;
00905        tag = op->o_tag;
00906        /* do not cache */
00907        op->o_do_not_cache = 1;
00908        /* ldap_back_entry_get() is an entry lookup, so it does not need
00909         * to know what the entry is being looked up for */
00910        op->o_tag = LDAP_REQ_SEARCH;
00911        rc = ldap_back_dobind( &lc, op, &rs, LDAP_BACK_DONTSEND );
00912        op->o_do_not_cache = do_not_cache;
00913        op->o_tag = tag;
00914        if ( !rc ) {
00915               return rs.sr_err;
00916        }
00917 
00918        if ( at ) {
00919               attrp = attr;
00920               if ( oc && at != slap_schema.si_ad_objectClass ) {
00921                      attr[0] = slap_schema.si_ad_objectClass->ad_cname.bv_val;
00922                      attr[1] = at->ad_cname.bv_val;
00923                      attr[2] = NULL;
00924 
00925               } else {
00926                      attr[0] = at->ad_cname.bv_val;
00927                      attr[1] = NULL;
00928               }
00929        }
00930 
00931        if ( oc ) {
00932               char   *ptr;
00933 
00934               filter = op->o_tmpalloc( STRLENOF( "(objectClass=" ")" ) 
00935                             + oc->soc_cname.bv_len + 1, op->o_tmpmemctx );
00936               ptr = lutil_strcopy( filter, "(objectClass=" );
00937               ptr = lutil_strcopy( ptr, oc->soc_cname.bv_val );
00938               *ptr++ = ')';
00939               *ptr++ = '\0';
00940        }
00941 
00942 retry:
00943        ctrls = op->o_ctrls;
00944        rc = ldap_back_controls_add( op, &rs, lc, &ctrls );
00945        if ( rc != LDAP_SUCCESS ) {
00946               goto cleanup;
00947        }
00948 
00949        /* TODO: timeout? */
00950        rc = ldap_pvt_search_s( lc->lc_ld, ndn->bv_val, LDAP_SCOPE_BASE, filter,
00951                             attrp, LDAP_DEREF_NEVER, ctrls, NULL,
00952                             NULL, LDAP_NO_LIMIT, 0, &result );
00953        if ( rc != LDAP_SUCCESS ) {
00954               if ( rc == LDAP_SERVER_DOWN && do_retry ) {
00955                      do_retry = 0;
00956                      if ( ldap_back_retry( &lc, op, &rs, LDAP_BACK_DONTSEND ) ) {
00957                             /* if the identity changed, there might be need to re-authz */
00958                             (void)ldap_back_controls_free( op, &rs, &ctrls );
00959                             goto retry;
00960                      }
00961               }
00962               goto cleanup;
00963        }
00964 
00965        e = ldap_first_entry( lc->lc_ld, result );
00966        if ( e == NULL ) {
00967               /* the entry exists, but it doesn't match the filter? */
00968               goto cleanup;
00969        }
00970 
00971        *ent = entry_alloc();
00972        if ( *ent == NULL ) {
00973               rc = LDAP_NO_MEMORY;
00974               goto cleanup;
00975        }
00976 
00977        rc = ldap_build_entry( op, e, *ent, &bdn );
00978 
00979        if ( rc != LDAP_SUCCESS ) {
00980               entry_free( *ent );
00981               *ent = NULL;
00982        }
00983 
00984 cleanup:
00985        (void)ldap_back_controls_free( op, &rs, &ctrls );
00986 
00987        if ( result ) {
00988               ldap_msgfree( result );
00989        }
00990 
00991        if ( filter ) {
00992               op->o_tmpfree( filter, op->o_tmpmemctx );
00993        }
00994 
00995        if ( lc != NULL ) {
00996               ldap_back_release_conn( li, lc );
00997        }
00998 
00999        return rc;
01000 }