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