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