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