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