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