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