]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/search.c
cc27f17afe5aac9e4c2b92452c0ca4d705d4d8d8
[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-2015 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 ) {
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 ) {
558                 if ( dont_retry == 0 ) {
559                         if ( do_retry ) {
560                                 do_retry = 0;
561                                 if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) {
562                                         goto retry;
563                                 }
564                         }
565
566                         rs->sr_err = LDAP_SERVER_DOWN;
567                         rs->sr_err = slap_map_api2result( rs );
568                         goto finish;
569
570                 } else if ( LDAP_BACK_ONERR_STOP( li ) ) {
571                         /* if onerr == STOP */
572                         rs->sr_err = LDAP_SERVER_DOWN;
573                         rs->sr_err = slap_map_api2result( rs );
574                         goto finish;
575                 }
576         }
577
578         /*
579          * Rewrite the matched portion of the search base, if required
580          */
581         if ( !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) {
582                 struct berval   pmatch;
583
584                 if ( dnPretty( NULL, &match, &pmatch, op->o_tmpmemctx ) != LDAP_SUCCESS ) {
585                         pmatch.bv_val = match.bv_val;
586                         match.bv_val = NULL;
587                 }
588                 rs->sr_matched = pmatch.bv_val;
589                 rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
590         }
591
592 finish:;
593         if ( !BER_BVISNULL( &match ) ) {
594                 ber_memfree( match.bv_val );
595         }
596
597         if ( rs->sr_v2ref ) {
598                 rs->sr_err = LDAP_REFERRAL;
599         }
600
601         if ( LDAP_BACK_QUARANTINE( li ) ) {
602                 ldap_back_quarantine( op, rs );
603         }
604
605         if ( filter.bv_val != op->ors_filterstr.bv_val ) {
606                 op->o_tmpfree( filter.bv_val, op->o_tmpmemctx );
607         }
608
609 #if 0
610         /* let send_ldap_result play cleanup handlers (ITS#4645) */
611         if ( rc != SLAPD_ABANDON )
612 #endif
613         {
614                 send_ldap_result( op, rs );
615         }
616
617         (void)ldap_back_controls_free( op, rs, &ctrls );
618
619         if ( rs->sr_ctrls ) {
620                 ldap_controls_free( rs->sr_ctrls );
621                 rs->sr_ctrls = NULL;
622         }
623
624         if ( rs->sr_text ) {
625                 if ( freetext ) {
626                         ber_memfree( (char *)rs->sr_text );
627                 }
628                 rs->sr_text = NULL;
629         }
630
631         if ( rs->sr_ref ) {
632                 op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
633                 rs->sr_ref = NULL;
634         }
635
636         if ( references ) {
637                 ber_memvfree( (void **)references );
638         }
639
640         if ( attrs ) {
641                 op->o_tmpfree( attrs, op->o_tmpmemctx );
642         }
643
644         if ( lc != NULL ) {
645                 ldap_back_release_conn( li, lc );
646         }
647
648         if ( rs->sr_err == LDAP_UNAVAILABLE &&
649                 /* if we originally bound and wanted rebind-as-user, must drop
650                  * the connection now because we just discarded the credentials.
651                  * ITS#7464, #8142
652                  */
653                 LDAP_BACK_SAVECRED( li ) && SLAP_IS_AUTHZ_BACKEND( op ) )
654                 rs->sr_err = SLAPD_DISCONNECT;
655         return rs->sr_err;
656 }
657
658 static int
659 ldap_build_entry(
660                 Operation       *op,
661                 LDAPMessage     *e,
662                 Entry           *ent,
663                 struct berval   *bdn )
664 {
665         struct berval   a;
666         BerElement      ber = *ldap_get_message_ber( e );
667         Attribute       *attr, **attrp;
668         const char      *text;
669         int             last;
670         char *lastb;
671         ber_len_t len;
672
673         /* safe assumptions ... */
674         assert( ent != NULL );
675         BER_BVZERO( &ent->e_bv );
676
677         if ( ber_scanf( &ber, "{m", bdn ) == LBER_ERROR ) {
678                 return LDAP_DECODING_ERROR;
679         }
680
681         /*
682          * Note: this may fail if the target host(s) schema differs
683          * from the one known to the meta, and a DN with unknown
684          * attributes is returned.
685          * 
686          * FIXME: should we log anything, or delegate to dnNormalize?
687          */
688         /* Note: if the distinguished values or the naming attributes
689          * change, should we massage them as well?
690          */
691         if ( dnPrettyNormal( NULL, bdn, &ent->e_name, &ent->e_nname,
692                 op->o_tmpmemctx ) != LDAP_SUCCESS )
693         {
694                 return LDAP_INVALID_DN_SYNTAX;
695         }
696
697         ent->e_attrs = NULL;
698         if ( ber_first_element( &ber, &len, &lastb ) != LBER_SEQUENCE ) {
699                 return LDAP_SUCCESS;
700         }
701
702         attrp = &ent->e_attrs;
703         while ( ber_next_element( &ber, &len, lastb ) == LBER_SEQUENCE &&
704                 ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
705                 int                             i;
706                 slap_syntax_validate_func       *validate;
707                 slap_syntax_transform_func      *pretty;
708
709                 attr = attr_alloc( NULL );
710                 if ( attr == NULL ) {
711                         return LDAP_OTHER;
712                 }
713                 if ( slap_bv2ad( &a, &attr->a_desc, &text ) 
714                                 != LDAP_SUCCESS )
715                 {
716                         if ( slap_bv2undef_ad( &a, &attr->a_desc, &text,
717                                 SLAP_AD_PROXIED ) != LDAP_SUCCESS )
718                         {
719                                 Debug( LDAP_DEBUG_ANY, 
720                                         "%s ldap_build_entry: "
721                                         "slap_bv2undef_ad(%s): %s\n",
722                                         op->o_log_prefix, a.bv_val, text );
723
724                                 ( void )ber_scanf( &ber, "x" /* [W] */ );
725                                 attr_free( attr );
726                                 continue;
727                         }
728                 }
729
730                 /* no subschemaSubentry */
731                 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
732                         || attr->a_desc == slap_schema.si_ad_entryDN )
733                 {
734
735                         /* 
736                          * We eat target's subschemaSubentry because
737                          * a search for this value is likely not
738                          * to resolve to the appropriate backend;
739                          * later, the local subschemaSubentry is
740                          * added.
741                          *
742                          * We also eat entryDN because the frontend
743                          * will reattach it without checking if already
744                          * present...
745                          */
746                         ( void )ber_scanf( &ber, "x" /* [W] */ );
747                         attr_free( attr );
748                         continue;
749                 }
750                 
751                 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
752                                 || attr->a_vals == NULL )
753                 {
754                         /*
755                          * Note: attr->a_vals can be null when using
756                          * values result filter
757                          */
758                         attr->a_vals = (struct berval *)&slap_dummy_bv;
759                 }
760
761                 validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
762                 pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
763
764                 if ( !validate && !pretty ) {
765                         attr->a_nvals = NULL;
766                         attr_free( attr );
767                         goto next_attr;
768                 }
769
770                 for ( i = 0; !BER_BVISNULL( &attr->a_vals[i] ); i++ ) ;
771                 last = i;
772
773                 /*
774                  * check that each value is valid per syntax
775                  * and pretty if appropriate
776                  */
777                 for ( i = 0; i<last; i++ ) {
778                         struct berval   pval;
779                         int             rc;
780
781                         if ( pretty ) {
782                                 rc = ordered_value_pretty( attr->a_desc,
783                                         &attr->a_vals[i], &pval, NULL );
784
785                         } else {
786                                 rc = ordered_value_validate( attr->a_desc,
787                                         &attr->a_vals[i], 0 );
788                         }
789
790                         if ( rc != LDAP_SUCCESS ) {
791                                 ObjectClass *oc;
792
793                                 /* check if, by chance, it's an undefined objectClass */
794                                 if ( attr->a_desc == slap_schema.si_ad_objectClass &&
795                                                 ( oc = oc_bvfind_undef( &attr->a_vals[i] ) ) != NULL )
796                                 {
797                                         ber_dupbv( &pval, &oc->soc_cname );
798                                         rc = LDAP_SUCCESS;
799
800                                 } else {
801                                         ber_memfree( attr->a_vals[i].bv_val );
802                                         if ( --last == i ) {
803                                                 BER_BVZERO( &attr->a_vals[i] );
804                                                 break;
805                                         }
806                                         attr->a_vals[i] = attr->a_vals[last];
807                                         BER_BVZERO( &attr->a_vals[last] );
808                                         i--;
809                                 }
810                         }
811
812                         if ( rc == LDAP_SUCCESS && pretty ) {
813                                 ber_memfree( attr->a_vals[i].bv_val );
814                                 attr->a_vals[i] = pval;
815                         }
816                 }
817                 attr->a_numvals = last = i;
818                 if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
819                         attr->a_nvals = NULL;
820                         attr_free( attr );
821                         goto next_attr;
822                 }
823
824                 if ( last && attr->a_desc->ad_type->sat_equality &&
825                                 attr->a_desc->ad_type->sat_equality->smr_normalize )
826                 {
827                         attr->a_nvals = ch_malloc( ( last + 1 )*sizeof( struct berval ) );
828                         for ( i = 0; i < last; i++ ) {
829                                 int             rc;
830
831                                 rc = ordered_value_normalize(
832                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
833                                         attr->a_desc,
834                                         attr->a_desc->ad_type->sat_equality,
835                                         &attr->a_vals[i], &attr->a_nvals[i],
836                                         NULL );
837
838                                 if ( rc != LDAP_SUCCESS ) {
839                                         ber_memfree( attr->a_vals[i].bv_val );
840                                         if ( --last == i ) {
841                                                 BER_BVZERO( &attr->a_vals[i] );
842                                                 break;
843                                         }
844                                         attr->a_vals[i] = attr->a_vals[last];
845                                         BER_BVZERO( &attr->a_vals[last] );
846                                         i--;
847                                 }
848                         }
849                         BER_BVZERO( &attr->a_nvals[i] );
850                         if ( last == 0 ) {
851                                 attr_free( attr );
852                                 goto next_attr;
853                         }
854
855                 } else {
856                         attr->a_nvals = attr->a_vals;
857                 }
858
859                 attr->a_numvals = last;
860
861                 /* Handle sorted vals, strip dups but keep the attr */
862                 if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
863                         while ( attr->a_numvals > 1 ) {
864                                 int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx );
865                                 if ( rc != LDAP_TYPE_OR_VALUE_EXISTS )
866                                         break;
867
868                                 /* Strip duplicate values */
869                                 if ( attr->a_nvals != attr->a_vals )
870                                         ber_memfree( attr->a_nvals[i].bv_val );
871                                 ber_memfree( attr->a_vals[i].bv_val );
872                                 attr->a_numvals--;
873
874                                 assert( i >= 0 );
875                                 if ( (unsigned)i < attr->a_numvals ) {
876                                         attr->a_vals[i] = attr->a_vals[attr->a_numvals];
877                                         if ( attr->a_nvals != attr->a_vals )
878                                                 attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];
879                                 }
880                                 BER_BVZERO(&attr->a_vals[attr->a_numvals]);
881                                 if ( attr->a_nvals != attr->a_vals )
882                                         BER_BVZERO(&attr->a_nvals[attr->a_numvals]);
883                         }
884                         attr->a_flags |= SLAP_ATTR_SORTED_VALS;
885                 }
886
887                 *attrp = attr;
888                 attrp = &attr->a_next;
889
890 next_attr:;
891         }
892
893         return LDAP_SUCCESS;
894 }
895
896 /* return 0 IFF we can retrieve the entry with ndn
897  */
898 int
899 ldap_back_entry_get(
900                 Operation               *op,
901                 struct berval           *ndn,
902                 ObjectClass             *oc,
903                 AttributeDescription    *at,
904                 int                     rw,
905                 Entry                   **ent )
906 {
907         ldapinfo_t      *li = (ldapinfo_t *) op->o_bd->be_private;
908
909         ldapconn_t      *lc = NULL;
910         int             rc;
911         struct berval   bdn;
912         LDAPMessage     *result = NULL,
913                         *e = NULL;
914         char            *attr[3], **attrp = NULL;
915         char            *filter = NULL;
916         SlapReply       rs;
917         int             do_retry = 1;
918         LDAPControl     **ctrls = NULL;
919         Operation op2 = *op;
920
921         *ent = NULL;
922
923         /* Tell getconn this is a privileged op */
924         op2.o_do_not_cache = 1;
925         /* use rootdn to be doubly explicit this is privileged */
926         op2.o_dn = op->o_bd->be_rootdn;
927         op2.o_ndn = op->o_bd->be_rootndn;
928         /* ldap_back_entry_get() is an entry lookup, so it does not need
929          * to know what the entry is being looked up for */
930         op2.o_tag = LDAP_REQ_SEARCH;
931         op2.o_ctrls = NULL;
932         rc = ldap_back_dobind( &lc, &op2, &rs, LDAP_BACK_DONTSEND );
933         if ( !rc ) {
934                 return rs.sr_err;
935         }
936
937         if ( at ) {
938                 attrp = attr;
939                 if ( oc && at != slap_schema.si_ad_objectClass ) {
940                         attr[0] = slap_schema.si_ad_objectClass->ad_cname.bv_val;
941                         attr[1] = at->ad_cname.bv_val;
942                         attr[2] = NULL;
943
944                 } else {
945                         attr[0] = at->ad_cname.bv_val;
946                         attr[1] = NULL;
947                 }
948         }
949
950         if ( oc ) {
951                 char    *ptr;
952
953                 filter = op->o_tmpalloc( STRLENOF( "(objectClass=" ")" ) 
954                                 + oc->soc_cname.bv_len + 1, op->o_tmpmemctx );
955                 ptr = lutil_strcopy( filter, "(objectClass=" );
956                 ptr = lutil_strcopy( ptr, oc->soc_cname.bv_val );
957                 *ptr++ = ')';
958                 *ptr++ = '\0';
959         }
960
961 retry:
962         ctrls = NULL;
963         rc = ldap_back_controls_add( &op2, &rs, lc, &ctrls );
964         if ( rc != LDAP_SUCCESS ) {
965                 goto cleanup;
966         }
967
968         /* TODO: timeout? */
969         rc = ldap_pvt_search_s( lc->lc_ld, ndn->bv_val, LDAP_SCOPE_BASE, filter,
970                                 attrp, LDAP_DEREF_NEVER, ctrls, NULL,
971                                 NULL, LDAP_NO_LIMIT, 0, &result );
972         if ( rc != LDAP_SUCCESS ) {
973                 if ( rc == LDAP_SERVER_DOWN && do_retry ) {
974                         do_retry = 0;
975                         if ( ldap_back_retry( &lc, &op2, &rs, LDAP_BACK_DONTSEND ) ) {
976                                 /* if the identity changed, there might be need to re-authz */
977                                 (void)ldap_back_controls_free( &op2, &rs, &ctrls );
978                                 goto retry;
979                         }
980                 }
981                 goto cleanup;
982         }
983
984         e = ldap_first_entry( lc->lc_ld, result );
985         if ( e == NULL ) {
986                 /* the entry exists, but it doesn't match the filter? */
987                 goto cleanup;
988         }
989
990         *ent = entry_alloc();
991         if ( *ent == NULL ) {
992                 rc = LDAP_NO_MEMORY;
993                 goto cleanup;
994         }
995
996         rc = ldap_build_entry( op, e, *ent, &bdn );
997
998         if ( rc != LDAP_SUCCESS ) {
999                 entry_free( *ent );
1000                 *ent = NULL;
1001         }
1002
1003 cleanup:
1004         (void)ldap_back_controls_free( &op2, &rs, &ctrls );
1005
1006         if ( result ) {
1007                 ldap_msgfree( result );
1008         }
1009
1010         if ( filter ) {
1011                 op->o_tmpfree( filter, op->o_tmpmemctx );
1012         }
1013
1014         if ( lc != NULL ) {
1015                 ldap_back_release_conn( li, lc );
1016         }
1017
1018         return rc;
1019 }