]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/search.c
da09209d904af872197d5e4af7fc79d5666e1fb1
[openldap] / servers / slapd / back-ldap / search.c
1 /* search.c - ldap backend search function */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1999-2004 The OpenLDAP Foundation.
6  * Portions Copyright 1999-2003 Howard Chu.
7  * Portions Copyright 2000-2003 Pierangelo Masarati.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by the Howard Chu for inclusion
20  * in OpenLDAP Software and subsequently enhanced by Pierangelo
21  * Masarati.
22  */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27
28 #include <ac/socket.h>
29 #include <ac/string.h>
30 #include <ac/time.h>
31
32 #include "slap.h"
33 #include "back-ldap.h"
34 #undef ldap_debug       /* silence a warning in ldap-int.h */
35 #include "../../../libraries/libldap/ldap-int.h"
36
37 #include "lutil.h"
38
39 static int
40 ldap_build_entry( Operation *op, LDAPMessage *e, Entry *ent,
41          struct berval *bdn, int flags );
42 #define LDAP_BUILD_ENTRY_PRIVATE        0x01
43
44 static struct berval dummy = BER_BVNULL;
45
46 int
47 ldap_back_search(
48     Operation   *op,
49     SlapReply *rs )
50 {
51         struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private;
52         struct ldapconn *lc;
53         struct timeval  tv;
54         LDAPMessage             *res, *e;
55         int     rc = 0, msgid; 
56         struct berval match = BER_BVNULL;
57         char **mapped_attrs = NULL;
58         struct berval mbase;
59         struct berval mfilter = BER_BVNULL;
60         int dontfreetext = 0;
61         int freeconn = 0;
62         dncookie dc;
63         LDAPControl **ctrls = NULL;
64
65         lc = ldap_back_getconn(op, rs);
66         if ( !lc ) {
67                 return( -1 );
68         }
69
70         /*
71          * FIXME: in case of values return filter, we might want
72          * to map attrs and maybe rewrite value
73          */
74         if ( !ldap_back_dobind( lc, op, rs ) ) {
75                 return( -1 );
76         }
77
78         /* should we check return values? */
79         if ( op->ors_deref != -1 ) {
80                 ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&op->ors_deref );
81         }
82
83         if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
84                 tv.tv_sec = op->ors_tlimit;
85                 tv.tv_usec = 0;
86
87         } else {
88                 tv.tv_sec = 0;
89         }
90
91         /*
92          * Rewrite the search base, if required
93          */
94         dc.rwmap = &li->rwmap;
95 #ifdef ENABLE_REWRITE
96         dc.conn = op->o_conn;
97         dc.rs = rs;
98         dc.ctx = "searchBase";
99 #else
100         dc.tofrom = 1;
101         dc.normalized = 0;
102 #endif
103         if ( ldap_back_dn_massage( &dc, &op->o_req_ndn, &mbase ) ) {
104                 send_ldap_result( op, rs );
105                 return -1;
106         }
107
108         rc = ldap_back_filter_map_rewrite( &dc, op->ors_filter,
109                         &mfilter, BACKLDAP_MAP );
110
111         switch ( rc ) {
112         case LDAP_SUCCESS:
113                 break;
114
115         case LDAP_COMPARE_FALSE:
116                 rs->sr_err = LDAP_SUCCESS;
117                 rs->sr_text = NULL;
118                 rc = 0;
119                 goto finish;
120
121         default:
122                 rs->sr_err = LDAP_OTHER;
123                 rs->sr_text = "Rewrite error";
124                 dontfreetext = 1;
125                 rc = -1;
126                 goto finish;
127         }
128
129         rs->sr_err = ldap_back_map_attrs( &li->rwmap.rwm_at,
130                         op->ors_attrs,
131                         BACKLDAP_MAP, &mapped_attrs );
132         if ( rs->sr_err != LDAP_SUCCESS ) {
133                 rc = -1;
134                 goto finish;
135         }
136
137         ctrls = op->o_ctrls;
138 #ifdef LDAP_BACK_PROXY_AUTHZ
139         rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
140         if ( rc != LDAP_SUCCESS ) {
141                 dontfreetext = 1;
142                 goto finish;
143         }
144 #endif /* LDAP_BACK_PROXY_AUTHZ */
145         
146         rs->sr_err = ldap_search_ext( lc->ld, mbase.bv_val,
147                         op->ors_scope, mfilter.bv_val,
148                         mapped_attrs, op->ors_attrsonly,
149                         ctrls, NULL,
150                         tv.tv_sec ? &tv : NULL, op->ors_slimit,
151                         &msgid );
152
153         if ( rs->sr_err != LDAP_SUCCESS ) {
154 fail:;
155                 rc = ldap_back_op_result( lc, op, rs, msgid, 0 );
156                 if ( freeconn ) {
157                         ldap_back_freeconn( op, lc );
158                         lc = NULL;
159                 }
160                 goto finish;
161         }
162
163         /* We pull apart the ber result, stuff it into a slapd entry, and
164          * let send_search_entry stuff it back into ber format. Slow & ugly,
165          * but this is necessary for version matching, and for ACL processing.
166          */
167
168         for ( rc = 0; rc != -1; rc = ldap_result( lc->ld, msgid, 0, &tv, &res ) )
169         {
170                 /* check for abandon */
171                 if ( op->o_abandon ) {
172                         ldap_abandon( lc->ld, msgid );
173                         rc = 0;
174                         goto finish;
175                 }
176
177                 if ( rc == 0 ) {
178                         tv.tv_sec = 0;
179                         tv.tv_usec = 100000;
180                         ldap_pvt_thread_yield();
181
182                 } else if ( rc == LDAP_RES_SEARCH_ENTRY ) {
183                         Entry ent = {0};
184                         struct berval bdn;
185                         int abort = 0;
186                         e = ldap_first_entry( lc->ld, res );
187                         rc = ldap_build_entry( op, e, &ent, &bdn,
188                                         LDAP_BUILD_ENTRY_PRIVATE );
189                        if ( rc == LDAP_SUCCESS ) {
190                                 rs->sr_entry = &ent;
191                                 rs->sr_attrs = op->ors_attrs;
192                                 rs->sr_operational_attrs = NULL;
193                                 rs->sr_flags = 0;
194                                 abort = send_search_entry( op, rs );
195                                 while (ent.e_attrs) {
196                                         Attribute *a;
197                                         BerVarray v;
198
199                                         a = ent.e_attrs;
200                                         ent.e_attrs = a->a_next;
201
202                                         v = a->a_vals;
203                                         if ( a->a_vals != &dummy ) {
204                                                 ber_bvarray_free(a->a_vals);
205                                         }
206                                         if ( a->a_nvals != v ) {
207                                                 ber_bvarray_free(a->a_nvals);
208                                         }
209                                         ch_free(a);
210                                 }
211                                 
212                                 if ( ent.e_dn && ( ent.e_dn != bdn.bv_val ) )
213                                         free( ent.e_dn );
214                                 if ( ent.e_ndn )
215                                         free( ent.e_ndn );
216                         }
217                         ldap_msgfree( res );
218                         if ( abort ) {
219                                 ldap_abandon( lc->ld, msgid );
220                                 goto finish;
221                         }
222
223                 } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
224                         char            **references = NULL;
225                         int             cnt;
226
227                         rc = ldap_parse_reference( lc->ld, res,
228                                         &references, &rs->sr_ctrls, 1 );
229
230                         if ( rc != LDAP_SUCCESS ) {
231                                 continue;
232                         }
233
234                         if ( references == NULL ) {
235                                 continue;
236                         }
237
238                         for ( cnt = 0; references[ cnt ]; cnt++ )
239                                 /* NO OP */ ;
240                                 
241                         rs->sr_ref = ch_calloc( cnt + 1, sizeof( struct berval ) );
242
243                         for ( cnt = 0; references[ cnt ]; cnt++ ) {
244                                 ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
245                         }
246
247                         /* ignore return value by now */
248                         ( void )send_search_reference( op, rs );
249
250                         /* cleanup */
251                         if ( references ) {
252                                 ldap_value_free( references );
253                                 ch_free( rs->sr_ref );
254                                 rs->sr_ref = NULL;
255                         }
256
257                         if ( rs->sr_ctrls ) {
258                                 ldap_controls_free( rs->sr_ctrls );
259                                 rs->sr_ctrls = NULL;
260                         }
261
262                 } else {
263                         rc = ldap_parse_result( lc->ld, res, &rs->sr_err,
264                                         &match.bv_val, (char **)&rs->sr_text,
265                                         NULL, NULL, 1 );
266                         if (rc != LDAP_SUCCESS ) {
267                                 rs->sr_err = rc;
268                         }
269                         rs->sr_err = slap_map_api2result( rs );
270                         rc = 0;
271                         break;
272                 }
273         }
274
275         if ( rc == -1 ) {
276                 /* FIXME: invalidate the connection? */
277                 rs->sr_err = LDAP_SERVER_DOWN;
278                 freeconn = 1;
279                 goto fail;
280         }
281
282         /*
283          * Rewrite the matched portion of the search base, if required
284          */
285         if ( match.bv_val && *match.bv_val ) {
286                 struct berval mdn;
287
288 #ifdef ENABLE_REWRITE
289                 dc.ctx = "matchedDN";
290 #else
291                 dc.tofrom = 0;
292                 dc.normalized = 0;
293 #endif
294                 match.bv_len = strlen( match.bv_val );
295                 ldap_back_dn_massage( &dc, &match, &mdn );
296                 rs->sr_matched = mdn.bv_val;
297         }
298         if ( rs->sr_v2ref ) {
299                 rs->sr_err = LDAP_REFERRAL;
300         }
301
302 finish:;
303         send_ldap_result( op, rs );
304
305 #ifdef LDAP_BACK_PROXY_AUTHZ
306         if ( ctrls && ctrls != op->o_ctrls ) {
307                 free( ctrls[ 0 ] );
308                 free( ctrls );
309         }
310 #endif /* LDAP_BACK_PROXY_AUTHZ */
311
312         if ( match.bv_val ) {
313                 if ( rs->sr_matched != match.bv_val ) {
314                         free( (char *)rs->sr_matched );
315                 }
316                 rs->sr_matched = NULL;
317                 LDAP_FREE( match.bv_val );
318         }
319         if ( rs->sr_text ) {
320                 if ( !dontfreetext ) {
321                         LDAP_FREE( (char *)rs->sr_text );
322                 }
323                 rs->sr_text = NULL;
324         }
325         if ( mapped_attrs ) {
326                 ch_free( mapped_attrs );
327         }
328         if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
329                 ch_free( mfilter.bv_val );
330         }
331         if ( mbase.bv_val != op->o_req_ndn.bv_val ) {
332                 free( mbase.bv_val );
333         }
334         
335         return rc;
336 }
337
338 static int
339 ldap_build_entry(
340         Operation *op,
341         LDAPMessage *e,
342         Entry *ent,
343         struct berval *bdn,
344         int flags
345 )
346 {
347         struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private;
348         struct berval a, mapped;
349         BerElement ber = *e->lm_ber;
350         Attribute *attr, **attrp;
351         struct berval *bv;
352         const char *text;
353         int last;
354         int private = flags & LDAP_BUILD_ENTRY_PRIVATE;
355         dncookie dc;
356
357         /* safe assumptions ... */
358         assert( ent );
359         ent->e_bv.bv_val = NULL;
360
361         if ( ber_scanf( &ber, "{m{", bdn ) == LBER_ERROR ) {
362                 return LDAP_DECODING_ERROR;
363         }
364
365         /*
366          * Rewrite the dn of the result, if needed
367          */
368         dc.rwmap = &li->rwmap;
369 #ifdef ENABLE_REWRITE
370         dc.conn = op->o_conn;
371         dc.rs = NULL;
372         dc.ctx = "searchResult";
373 #else
374         dc.tofrom = 0;
375         dc.normalized = 0;
376 #endif
377         if ( ldap_back_dn_massage( &dc, bdn, &ent->e_name ) ) {
378                 return LDAP_OTHER;
379         }
380
381         /*
382          * Note: this may fail if the target host(s) schema differs
383          * from the one known to the meta, and a DN with unknown
384          * attributes is returned.
385          * 
386          * FIXME: should we log anything, or delegate to dnNormalize?
387          */
388         /* Note: if the distinguished values or the naming attributes
389          * change, should we massage them as well?
390          */
391         if ( dnNormalize( 0, NULL, NULL, &ent->e_name, &ent->e_nname,
392                 op->o_tmpmemctx ) != LDAP_SUCCESS )
393         {
394                 return LDAP_INVALID_DN_SYNTAX;
395         }
396
397         attrp = &ent->e_attrs;
398
399 #ifdef ENABLE_REWRITE
400         dc.ctx = "searchAttrDN";
401 #endif
402         while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
403                 int             i;
404                 slap_syntax_validate_func *validate =
405                         attr->a_desc->ad_type->sat_syntax->ssyn_validate;
406                 slap_syntax_transform_func *pretty =
407                         attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
408
409                 ldap_back_map( &li->rwmap.rwm_at, &a, &mapped, BACKLDAP_REMAP );
410                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) )
411                         continue;
412                 attr = (Attribute *)ch_malloc( sizeof( Attribute ) );
413                 if ( attr == NULL )
414                         continue;
415                 attr->a_flags = 0;
416                 attr->a_next = 0;
417                 attr->a_desc = NULL;
418                 if ( slap_bv2ad( &mapped, &attr->a_desc, &text ) != LDAP_SUCCESS ) {
419                         if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text ) 
420                                         != LDAP_SUCCESS )
421                         {
422 #ifdef NEW_LOGGING
423                                 LDAP_LOG( BACK_LDAP, DETAIL1, 
424                                         "slap_bv2undef_ad(%s):  %s\n", mapped.bv_val, text, 0 );
425 #else /* !NEW_LOGGING */
426                                 Debug( LDAP_DEBUG_ANY, 
427                                         "slap_bv2undef_ad(%s):  %s\n", mapped.bv_val, text, 0 );
428 #endif /* !NEW_LOGGING */
429                                 ch_free( attr );
430                                 continue;
431                         }
432                 }
433
434                 /* no subschemaSubentry */
435                 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) {
436
437                         /* 
438                          * We eat target's subschemaSubentry because
439                          * a search for this value is likely not
440                          * to resolve to the appropriate backend;
441                          * later, the local subschemaSubentry is
442                          * added.
443                          */
444                         ( void )ber_scanf( &ber, "x" /* [W] */ );
445
446                         ch_free(attr);
447                         continue;
448                 }
449                 
450                 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
451                                 || attr->a_vals == NULL )
452                 {
453                         /*
454                          * Note: attr->a_vals can be null when using
455                          * values result filter
456                          */
457                         if ( private ) {
458                                 attr->a_vals = &dummy;
459                         } else {
460                                 attr->a_vals = ch_malloc( sizeof( struct berval ) );
461                                 BER_BVZERO( &attr->a_vals[0] );
462                         }
463                         last = 0;
464
465                 } else {
466                         for ( last = 0; !BER_BVISNULL( &attr->a_vals[last] ); last++ );
467                 }
468
469                 if ( last == 0 ) {
470                         /* empty */
471                 } else if ( attr->a_desc == slap_schema.si_ad_objectClass
472                                 || attr->a_desc == slap_schema.si_ad_structuralObjectClass )
473                 {
474                         for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
475                                 ldap_back_map( &li->rwmap.rwm_oc, bv, &mapped,
476                                                 BACKLDAP_REMAP );
477                                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
478                                         LBER_FREE( bv->bv_val );
479                                         BER_BVZERO( bv );
480                                         if (--last < 0)
481                                                 break;
482                                         *bv = attr->a_vals[last];
483                                         BER_BVZERO( &attr->a_vals[last] );
484                                         bv--;
485
486                                 } else if ( mapped.bv_val != bv->bv_val ) {
487                                         /*
488                                          * FIXME: after LBER_FREEing
489                                          * the value is replaced by
490                                          * ch_alloc'ed memory
491                                          */
492                                         LBER_FREE( bv->bv_val );
493                                         ber_dupbv( bv, &mapped );
494                                 }
495                         }
496
497                 /*
498                  * It is necessary to try to rewrite attributes with
499                  * dn syntax because they might be used in ACLs as
500                  * members of groups; since ACLs are applied to the
501                  * rewritten stuff, no dn-based subject clause could
502                  * be used at the ldap backend side (see
503                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
504                  * The problem can be overcome by moving the dn-based
505                  * ACLs to the target directory server, and letting
506                  * everything pass thru the ldap backend.
507                  */
508                 } else if ( attr->a_desc->ad_type->sat_syntax ==
509                                 slap_schema.si_syn_distinguishedName )
510                 {
511                         ldap_dnattr_result_rewrite( &dc, attr->a_vals );
512                 }
513
514                 validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
515                 pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
516
517                 if ( !validate && !pretty ) {
518                         attr->a_nvals = NULL;
519                         attr_free( attr );
520                         goto next_attr;
521                 }
522
523                 for ( i = 0; i < last; i++ ) {
524                         struct berval   pval;
525                         int             rc;
526
527                         if ( pretty ) {
528                                 rc = pretty( attr->a_desc->ad_type->sat_syntax,
529                                         &attr->a_vals[i], &pval, NULL );
530                         } else {
531                                 rc = validate( attr->a_desc->ad_type->sat_syntax,
532                                         &attr->a_vals[i] );
533                         }
534
535                         if ( rc != LDAP_SUCCESS ) {
536                                 attr->a_nvals = NULL;
537                                 attr_free( attr );
538                                 goto next_attr;
539                         }
540
541                         if ( pretty ) {
542                                 LBER_FREE( attr->a_vals[i].bv_val );
543                                 attr->a_vals[i] = pval;
544                         }
545                 }
546
547                 if ( last && attr->a_desc->ad_type->sat_equality &&
548                                 attr->a_desc->ad_type->sat_equality->smr_normalize )
549                 {
550                         attr->a_nvals = ch_malloc( ( last + 1 )*sizeof( struct berval ) );
551                         for ( i = 0; i < last; i++ ) {
552                                 int             rc;
553
554                                 /*
555                                  * check that each value is valid per syntax
556                                  * and pretty if appropriate
557                                  */
558                                 rc = attr->a_desc->ad_type->sat_equality->smr_normalize(
559                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
560                                         attr->a_desc->ad_type->sat_syntax,
561                                         attr->a_desc->ad_type->sat_equality,
562                                         &attr->a_vals[i], &attr->a_nvals[i],
563                                         NULL /* op->o_tmpmemctx */ );
564
565                                 if ( rc != LDAP_SUCCESS ) {
566                                         BER_BVZERO( &attr->a_nvals[i] );
567                                         ch_free( attr );
568                                         goto next_attr;
569                                 }
570                         }
571                         BER_BVZERO( &attr->a_nvals[i] );
572
573                 } else {
574                         attr->a_nvals = attr->a_vals;
575                 }
576                 *attrp = attr;
577                 attrp = &attr->a_next;
578
579 next_attr:;
580         }
581
582         /* make sure it's free'able */
583         if ( !private && ent->e_name.bv_val == bdn->bv_val ) {
584                 ber_dupbv( &ent->e_name, bdn );
585         }
586         return LDAP_SUCCESS;
587 }
588
589 /* return 0 IFF we can retrieve the entry with ndn
590  */
591 int
592 ldap_back_entry_get(
593         Operation *op,
594         struct berval   *ndn,
595         ObjectClass *oc,
596         AttributeDescription *at,
597         int rw,
598         Entry **ent
599 )
600 {
601         struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private;    
602         struct ldapconn *lc;
603         int rc = 1, is_oc;
604         struct berval mapped = BER_BVNULL, bdn, mdn;
605         LDAPMessage     *result = NULL, *e = NULL;
606         char *gattr[3];
607         char *filter = NULL;
608         Connection *oconn;
609         SlapReply rs;
610         dncookie dc;
611
612         /* Tell getconn this is a privileged op */
613         is_oc = op->o_do_not_cache;
614         op->o_do_not_cache = 1;
615         lc = ldap_back_getconn(op, &rs);
616         oconn = op->o_conn;
617         op->o_conn = NULL;
618         if ( !lc || !ldap_back_dobind(lc, op, &rs) ) {
619                 op->o_do_not_cache = is_oc;
620                 op->o_conn = oconn;
621                 return 1;
622         }
623         op->o_do_not_cache = is_oc;
624         op->o_conn = oconn;
625
626         /*
627          * Rewrite the search base, if required
628          */
629         dc.rwmap = &li->rwmap;
630 #ifdef ENABLE_REWRITE
631         dc.conn = op->o_conn;
632         dc.rs = &rs;
633         dc.ctx = "searchBase";
634 #else
635         dc.tofrom = 1;
636         dc.normalized = 1;
637 #endif
638         if ( ldap_back_dn_massage( &dc, ndn, &mdn ) ) {
639                 return 1;
640         }
641
642         if ( at ) {
643                 ldap_back_map(&li->rwmap.rwm_at, &at->ad_cname, &mapped, BACKLDAP_MAP);
644                 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
645                         rc = 1;
646                         goto cleanup;
647                 }
648                 is_oc = ( strcasecmp( "objectclass", mapped.bv_val ) == 0 );
649                 if ( oc && !is_oc ) {
650                         gattr[0] = "objectclass";
651                         gattr[1] = mapped.bv_val;
652                         gattr[2] = NULL;
653
654                 } else {
655                         gattr[0] = mapped.bv_val;
656                         gattr[1] = NULL;
657                 }
658         }
659
660         if (oc) {
661                 char *ptr;
662                 ldap_back_map(&li->rwmap.rwm_oc, &oc->soc_cname, &mapped,
663                                                 BACKLDAP_MAP);
664                 filter = ch_malloc( STRLENOF( "(objectclass=)" ) + mapped.bv_len + 1 );
665                 ptr = lutil_strcopy( filter, "(objectclass=" );
666                 ptr = lutil_strcopy( ptr, mapped.bv_val );
667                 *ptr++ = ')';
668                 *ptr++ = '\0';
669         }
670
671         if ( ldap_search_ext_s( lc->ld, mdn.bv_val, LDAP_SCOPE_BASE, filter,
672                                 gattr, 0, NULL, NULL, LDAP_NO_LIMIT,
673                                 LDAP_NO_LIMIT, &result) != LDAP_SUCCESS )
674         {
675                 goto cleanup;
676         }
677
678         e = ldap_first_entry( lc->ld, result );
679         if ( e == NULL ) {
680                 goto cleanup;
681         }
682
683         *ent = ch_calloc( 1, sizeof( Entry ) );
684
685         rc = ldap_build_entry( op, e, *ent, &bdn, 0 );
686
687         if ( rc != LDAP_SUCCESS ) {
688                 ch_free( *ent );
689                 *ent = NULL;
690         }
691
692 cleanup:
693         if ( result ) {
694                 ldap_msgfree( result );
695         }
696
697         if ( filter ) {
698                 ch_free( filter );
699         }
700
701         if ( mdn.bv_val != ndn->bv_val ) {
702                 ch_free( mdn.bv_val );
703         }
704
705         return rc;
706 }
707