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