1 /*
2 * Copyright 1998-2003 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 #pragma ident "%Z%%M% %I% %E% SMI"
7
8 /*
9 * Copyright (c) 1990 Regents of the University of Michigan.
10 * All rights reserved.
11 *
12 * result.c - wait for an ldap result
13 */
14
15 #ifndef lint
16 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
17 #endif
18
19 #include <stdio.h>
20 #include <string.h>
21 #ifdef MACOS
22 #include <stdlib.h>
23 #include <time.h>
24 #include "macos.h"
25 #else /* MACOS */
26 #if defined( DOS ) || defined( _WIN32 )
27 #include <time.h>
28 #include "msdos.h"
29 #ifdef PCNFS
30 #include <tklib.h>
31 #include <tk_errno.h>
32 #include <bios.h>
33 #endif /* PCNFS */
34 #ifdef NCSA
35 #include "externs.h"
36 #endif /* NCSA */
37 #else /* DOS */
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <errno.h>
42 #ifdef _AIX
43 #include <sys/select.h>
44 #endif /* _AIX */
45 #include "portable.h"
46 #endif /* DOS */
47 #endif /* MACOS */
48 #ifdef VMS
49 #include "ucx_select.h"
50 #endif
51 #include "lber.h"
52 #include "ldap.h"
53 #include "ldap-private.h"
54 #include "ldap-int.h"
55
56 #ifdef USE_SYSCONF
57 #include <unistd.h>
58 #endif /* USE_SYSCONF */
59
60 #ifdef NEEDPROTOS
61 static int ldap_abandoned( LDAP *ld, int msgid );
62 static int ldap_mark_abandoned( LDAP *ld, int msgid );
63 static int wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
64 LDAPMessage **result );
65 static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
66 LDAPMessage **result );
67 static int build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr );
68 static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
69 #ifdef CLDAP
70 static int ldap_select1( LDAP *ld, struct timeval *timeout );
71 #endif
72 static int Ref_AddToRequest(LDAPRequest *lr, char **refs);
73 static void Ref_FreeAll(LDAPRequest *lr);
74 #else /* NEEDPROTOS */
75 static int ldap_abandoned();
76 static int ldap_mark_abandoned();
77 static int wait4msg();
78 static int read1msg();
79 static int build_result_ber();
80 static void merge_error_info();
81 #ifdef CLDAP
82 static int ldap_select1();
83 #endif
84 #endif /* NEEDPROTOS */
85
86 #if !defined( MACOS ) && !defined( DOS )
87 extern int errno;
88 #endif
89
90 /*
91 * ldap_result - wait for an ldap result response to a message from the
92 * ldap server. If msgid is -1, any message will be accepted, otherwise
93 * ldap_result will wait for a response with msgid.
94 * If all is LDAP_MSG_ONE the first message with id msgid will be accepted.
95 * If all is LDAP_MSG_RECEIVED, the received messages with the id msgid will
96 * be accepted.
97 * Otherwise, ldap_result will wait for all responses with id msgid and
98 * then return a pointer to the entire list of messages. This is only
99 * useful for search responses, which can be of 3 message types (zero or
100 * more entries, zero or more references, one or more results). The type
101 * of the first message* received is returned.
102 * When waiting, any messages that have been abandoned are discarded.
103 *
104 * Example:
105 * ldap_result( s, msgid, all, timeout, result )
106 */
107 int
ldap_result(LDAP * ld,int msgid,int all,struct timeval * timeout,LDAPMessage ** result)108 ldap_result( LDAP *ld, int msgid, int all, struct timeval *timeout,
109 LDAPMessage **result )
110 {
111 LDAPMessage *lm, *lastlm, *nextlm;
112 int rv;
113
114 /*
115 * First, look through the list of responses we have received on
116 * this association and see if the response we're interested in
117 * is there. If it is, return it. If not, call wait4msg() to
118 * wait until it arrives or timeout occurs.
119 */
120
121 #ifdef _REENTRANT
122 LOCK_RESPONSE(ld);
123 LOCK_LDAP(ld);
124 #endif
125 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 223, "ldap_result\n"), 0, 0, 0 );
126
127 *result = NULLMSG;
128 lastlm = NULLMSG;
129
130 /* look in the received responses */
131 for ( lm = ld->ld_responses; lm != NULLMSG; lm = nextlm ) {
132 nextlm = lm->lm_next;
133
134 /* if the msg has been abandonned, free it */
135 if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
136 ldap_mark_abandoned( ld, lm->lm_msgid );
137
138 if ( lastlm == NULLMSG ) {
139 ld->ld_responses = lm->lm_next;
140 } else {
141 lastlm->lm_next = nextlm;
142 }
143
144 ldap_msgfree( lm );
145
146 continue;
147 }
148
149 if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
150 LDAPMessage *tmp;
151
152 /* If return ONE or RECEIVED message(s) or not a search result, return lm */
153 if ( all == LDAP_MSG_ONE || all == LDAP_MSG_RECEIVED
154 || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
155 && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY
156 && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) )
157 break;
158
159 /* Search in the set of messages if one is a search result */
160 for ( tmp = lm; tmp != NULLMSG; tmp = tmp->lm_chain ) {
161 if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
162 break;
163 }
164 /* No, well wait for the result message */
165 if ( tmp == NULLMSG ) {
166 #ifdef _REENTRANT
167 UNLOCK_LDAP(ld);
168 #endif
169 rv = wait4msg( ld, msgid, all, timeout, result );
170 #ifdef _REENTRANT
171 UNLOCK_RESPONSE(ld);
172 #endif
173 return( rv );
174 }
175 /* Here we have the Search result pointed by tmp */
176 break;
177 }
178 /* Check next response */
179 lastlm = lm;
180 }
181
182 /* No response matching found : Wait for one */
183 if ( lm == NULLMSG ) {
184 #ifdef _REENTRANT
185 UNLOCK_LDAP(ld);
186 #endif
187 rv = wait4msg( ld, msgid, all, timeout, result );
188 #ifdef _REENTRANT
189 UNLOCK_RESPONSE(ld);
190 #endif
191 return( rv );
192 }
193
194 /* lm points to the message (chain) to return */
195
196 /* Remove message to return from ld_responses list */
197 if ( lastlm == NULLMSG ) {
198 if (all == LDAP_MSG_ONE && lm->lm_chain != NULLMSG){
199 ld->ld_responses = lm->lm_chain;
200 } else {
201 ld->ld_responses = lm->lm_next;
202 }
203 } else {
204 if (all == LDAP_MSG_ONE && lm->lm_chain != NULLMSG) {
205 lastlm->lm_next = lm->lm_chain;
206 } else {
207 lastlm->lm_next = lm->lm_next;
208 }
209 }
210
211 if ( all == LDAP_MSG_ONE )
212 lm->lm_chain = NULLMSG;
213 /* Otherwise return the whole chain */
214 /* No reponses attached */
215 lm->lm_next = NULLMSG;
216
217 *result = lm;
218 ld->ld_errno = LDAP_SUCCESS;
219 rv = lm->lm_msgtype;
220 #ifdef _REENTRANT
221 UNLOCK_LDAP(ld);
222 UNLOCK_RESPONSE(ld);
223 #endif
224 return( rv );
225 }
226
227 static int
wait4msg(LDAP * ld,int msgid,int all,struct timeval * timeout,LDAPMessage ** result)228 wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
229 LDAPMessage **result )
230 {
231 int rc;
232 struct timeval tv, *tvp;
233 time_t start_time, tmp_time;
234 LDAPConn *lc, *nextlc;
235
236 #ifdef LDAP_DEBUG
237 if ( timeout == NULL ) {
238 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 224, "wait4msg (infinite timeout)\n"),
239 0, 0, 0 );
240 } else {
241 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 225, "wait4msg (timeout %1$ld sec, %2$ld usec)\n"),
242 timeout->tv_sec, timeout->tv_usec, 0 );
243 }
244 #endif /* LDAP_DEBUG */
245
246 if ( timeout == NULL ) {
247 tvp = NULL;
248 } else {
249 tv = *timeout;
250 tvp = &tv;
251 start_time = time( NULL );
252 }
253
254 rc = -2;
255 while ( rc == -2 ) {
256 #ifdef LDAP_DEBUG
257 if ( ldap_debug & LDAP_DEBUG_TRACE ) {
258 dump_connection( ld, ld->ld_conns, 1 );
259 dump_requests_and_responses( ld );
260 }
261 #endif /* LDAP_DEBUG */
262 for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
263 if ( lc->lconn_sb->sb_ber.ber_ptr <
264 lc->lconn_sb->sb_ber.ber_end ) {
265 /* A Message is available, decode and process it */
266 rc = read1msg( ld, msgid, all, lc->lconn_sb,
267 lc, result );
268 break;
269 }
270 }
271 /* There was no message available : Wait for one */
272 if ( lc == NULL ) {
273 rc = do_ldap_select( ld, tvp );
274
275
276 #if defined( LDAP_DEBUG ) && !defined( MACOS ) && !defined( DOS )
277 if ( rc == -1 ) {
278 Debug( LDAP_DEBUG_TRACE,
279 catgets(slapdcat, 1, 226, "do_ldap_select returned -1: errno %d\n"),
280 errno, 0, 0 );
281 }
282 #endif
283
284 #if !defined( MACOS ) && !defined( DOS )
285 if ( rc == 0 || ( rc == -1 && (ld->ld_restart || errno != EINTR ))) {
286 #else
287 if ( rc == -1 || rc == 0 ) {
288 #endif
289 ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
290 LDAP_TIMEOUT);
291 if ( rc == -1 ) {
292 #ifdef _REENTRANT
293 LOCK_LDAP(ld);
294 #endif
295 nsldapi_connection_lost_nolock( ld, NULL);
296 #ifdef _REENTRANT
297 UNLOCK_LDAP(ld);
298 #endif
299 }
300 return( rc );
301 }
302
303 if ( rc == -1 ) {
304 rc = -2; /* select interrupted: Continue the loop */
305 } else {
306 rc = -2;
307 for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
308 lc = nextlc ) {
309 nextlc = lc->lconn_next;
310 if ( lc->lconn_status == LDAP_CONNST_CONNECTED) {
311 /* Check on each connection. */
312 long is_ready = is_read_ready( ld, lc->lconn_sb );
313
314 if (is_ready > 0) {
315 /* A Message is available, decode and process it */
316 rc = read1msg( ld, msgid, all,
317 lc->lconn_sb, lc, result );
318 } else if ( is_ready < 0){
319 /* Error in the select : what to do in here ? */
320 /* So far : */
321 rc = -1;
322 }
323 }
324 }
325 }
326 }
327
328 if ( rc == -2 && tvp != NULL ) {
329 tmp_time = time( NULL );
330 if (( tv.tv_sec -= ( tmp_time - start_time )) <= 0 ) {
331 /* At this point if all == LDAP_MSG_RECEIVED, we must
332 return all available messages for the msgid */
333 if (all == LDAP_MSG_RECEIVED) {
334 /* Search in responses if some have the correct id */
335 /* if yes return the chain */
336 /* Otherwise return timeout */
337 break;
338 }
339
340 rc = 0; /* timed out */
341 ld->ld_errno = LDAP_TIMEOUT;
342 break;
343 }
344
345 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 227, "wait4msg: %ld secs to go\n"),
346 tv.tv_sec, 0, 0 );
347 start_time = tmp_time;
348 }
349 }
350
351 return( rc );
352 }
353
354
355 static int
356 read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
357 LDAPConn *lc,
358 LDAPMessage **result )
359 {
360 BerElement ber;
361 LDAPMessage *new, *L_res, *l, *prev, *tmp;
362 int id;
363 unsigned int tag, atag, len;
364 int foundit = 0;
365 LDAPRequest *lr, *lrparent;
366 LDAPRef *theReferences;
367 BerElement tmpber;
368 int rc, refer_cnt, hadref, simple_request, samereq = 0, total_count;
369 int retcode;
370 int theErrCode = LDAP_SUCCESS;
371 unsigned int lderr;
372 char *msgtypestr;
373 char ** theRefs = NULL;
374 char * theOid = NULL;
375 char *lddn, *lderrmsg;
376
377 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 228, "read1msg\n"), 0, 0, 0 );
378
379 read_from_sb:
380 lderr = LDAP_SUCCESS; /* Be optimistic */
381
382 ber_zero_init( &ber, 0 );
383 set_ber_options( ld, &ber );
384
385 /* get the next message */
386 if ( (tag = ber_get_next( sb, &len, &ber ))
387 != LDAP_TAG_MESSAGE ) {
388 ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
389 LDAP_LOCAL_ERROR);
390 if ( tag == LBER_DEFAULT ) {
391 #ifdef _REENTRANT
392 LOCK_LDAP(ld);
393 #endif
394 nsldapi_connection_lost_nolock( ld, sb );
395 #ifdef _REENTRANT
396 UNLOCK_LDAP(ld);
397 #endif
398 }
399 return( -1 );
400 }
401
402 /* message id */
403 if ( ber_get_int( &ber, &id ) == LBER_ERROR ) {
404 ld->ld_errno = LDAP_DECODING_ERROR;
405 return( -1 );
406 }
407
408 /* if it's been abandoned, toss it */
409 if ( ldap_abandoned( ld, (int)id ) ) {
410 free( ber.ber_buf ); /* gack! */
411 return( -2 ); /* continue looking */
412 }
413
414 /* the message type */
415 if ( (tag = ber_peek_tag( &ber, &len )) == LBER_ERROR ) {
416 ld->ld_errno = LDAP_DECODING_ERROR;
417 return( -1 );
418 }
419
420 /* KE
421 * Treat unsolicited notification if we got one!
422 * id==0
423 * tag==LDAP_RES_EXTENDED
424 *
425 * resultCode== protocolError
426 * strongAuthRequired
427 * unavailable
428 * tag==LDAP_TAG_EXT_RESPNAME
429 * response name (oid)==1.3.6.1.1.4.1.1466.20036
430 * no response field
431 *
432 * Example:
433 * --------
434 * Ber format: {iaata}
435 * which means: returnCode dn errorMessage LDAP_TAG_EXT_RESPNAME "1.3.6.1.1.4.1.1466.20036"
436 */
437 if ( (id==0) && (tag==LDAP_RES_EXTENDED) )
438 {
439 tmpber = ber;
440 if (ber_scanf( &ber, "{iaa", &lderr, &lddn, &lderrmsg) != LBER_ERROR)
441 {
442 if (ber_peek_tag ( &ber, &atag) == LDAP_TAG_EXT_RESPNAME)
443 {
444 if ( ber_get_stringa( &ber, &theOid) == LBER_ERROR )
445 {
446 ld->ld_errno = LDAP_DECODING_ERROR;
447 return(-1);
448 }
449 }
450 else
451 {
452 ld->ld_errno = LDAP_DECODING_ERROR;
453 return(-1);
454 }
455
456 if (ber_peek_tag ( &ber, &atag) == LDAP_TAG_EXT_RESPONSE)
457 {
458 /* this field must be absent */
459 ld->ld_errno = LDAP_DECODING_ERROR;
460 return(-1);
461 }
462 if ( ber_scanf(&ber, "}")== LBER_ERROR)
463 {
464 ld->ld_errno = LDAP_DECODING_ERROR;
465 return(-1);
466 }
467
468 /* make a new ldap message to return the result */
469 if ( (new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) )) == NULL )
470 {
471 ld->ld_errno = LDAP_NO_MEMORY;
472 return(-1);
473 }
474 new->lm_msgid = 0;
475 new->lm_msgtype = tag;
476 new->lm_ber = ber_dup( &tmpber );
477
478 if ( (strncmp(theOid, "1.3.6.1.1.4.1.1466.20036", 24)==0) &&
479 (lderr==LDAP_PROTOCOL_ERROR) ||
480 (lderr==LDAP_STRONG_AUTH_REQUIRED) ||
481 (lderr==LDAP_UNAVAILABLE) )
482 {
483 /* make a new ldap message to return the result */
484 if ( (L_res = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) )) == NULL )
485 {
486 ld->ld_errno = LDAP_NO_MEMORY;
487 return(-1);
488 }
489 L_res->lm_msgid = 0;
490 L_res->lm_msgtype = tag;
491 L_res->lm_ber = ber_dup( &tmpber );
492 *result = L_res;
493
494 /* It is a notice of disconnection
495 * Return immediatly with an error code to stop
496 * reading any new message and to prevent the use
497 */
498 ld->ld_errno = LDAP_SERVER_DOWN;
499 ldap_insert_notif(ld, new); /* in head */
500 return(-1);
501 }
502 else
503 {
504 /* This is another notification
505 * Keep on the processing of received messages
506 */
507 ldap_add_notif(ld, new); /* in tail */
508 goto read_from_sb;
509 }
510 }
511 else
512 {
513 Debug(LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1673, "Error while decoding Extended Response message"), NULL, NULL, NULL);
514 ld->ld_errno = LDAP_DECODING_ERROR;
515 return(-1);
516 }
517 }
518 else if (( lr = find_request_by_msgid( ld, id )) == NULL )
519 {
520 Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, 229, "no request for response with msgid %ld (tossing)\n"), id, 0, 0 );
521 free( ber.ber_buf ); /* gack! */
522 return( -2 ); /* continue looking */
523 }
524
525 if (tag == LDAP_RES_SEARCH_ENTRY)
526 msgtypestr = catgets(slapdcat, 1, 1281, "search entry");
527 else if (tag == LDAP_RES_SEARCH_REFERENCE)
528 msgtypestr = catgets(slapdcat, 1, 1282, "search reference");
529 else
530 msgtypestr = catgets(slapdcat, 1, 1283, "result");
531
532 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 230, "got %1$s msgid %2$ld, original id %3$d\n"),
533 msgtypestr, id, lr->lr_origid );
534
535 id = lr->lr_origid;
536
537 /* REFERRALS HANDLING*/
538 refer_cnt = 0;
539 simple_request = 0;
540 hadref = 0;
541 rc = -2; /* default is to keep looking (no response found) */
542 lr->lr_res_msgtype = tag;
543
544 if ( tag != LDAP_RES_SEARCH_ENTRY ) { /* If it's not an entry, ie it's a result or a reference */
545 if ( ld->ld_version >= LDAP_VERSION2 &&
546 ( lr->lr_parent != NULL ||
547 ld->ld_follow_referral /* || ClientControl to follow referral present */ )) {
548 tmpber = ber;
549 if (tag == LDAP_RES_SEARCH_REFERENCE){
550 /* LDAP V3 reference. Decode it */
551 Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, -1, "LDAP search reference received. Will follow it later\n"),
552 0, 0,0);
553 if (ber_scanf(&tmpber, "{v}", &theRefs) == LBER_ERROR){
554 Debug ( LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1284, "Error while decoding Search Reference Result message\n"),
555 NULL, NULL, NULL);
556 rc = -1;
557 theRefs = NULL;
558 } else {
559 /* Store the referrals in request. We will follow them when the result arrives */
560 Ref_AddToRequest(lr, theRefs);
561 theRefs = NULL;
562 free( ber.ber_buf ); /* gack! */
563 ber.ber_buf = NULL;
564 return (rc);
565 }
566 } else {
567 if (ber_scanf( &tmpber, "{iaa", &lderr, &lr->lr_res_matched, &lr->lr_res_error) != LBER_ERROR){
568 if (lderr == LDAP_PARTIAL_RESULTS){
569 Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, -1, "LDAPv2 partial error received\n"), 0, 0,0);
570 /* Ldapv2 referrals */
571 theRefs = ldap_errormsg2referrals(lr->lr_res_error);
572 ber_scanf(&tmpber, "}");
573 } else if (lderr == LDAP_REFERRAL ){
574 /* We have some referrals, decode them */
575 Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, -1, "LDAPv3 referral error received\n"), 0, 0,0);
576 if (ber_peek_tag ( &tmpber, &atag) == LDAP_TAG_REFERRAL){
577 if (ber_scanf(&tmpber, "{v}}", &theRefs) == LBER_ERROR){
578 Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1285, "Error while decoding referrals in msg\n"),
579 NULL, NULL, NULL );
580 rc = -1; /* ??? */
581 theRefs = NULL;
582 }
583 } /* else error there should be at least one ref */
584 } else if (((lderr == LDAP_NO_SUCH_OBJECT) ||
585 (lderr == LDAP_BUSY) ||
586 (lderr == LDAP_UNAVAILABLE) ||
587 (lderr == LDAP_SERVER_DOWN) ||
588 (lderr == LDAP_CONNECT_ERROR)) &&
589 (lr->lr_parent != NULL) && /* its subrequest */
590 (lr->lr_ref_tofollow != NULL)) { /* And it has some other referral to try */
591 samereq = 1;
592 theRefs = lr->lr_ref_tofollow;
593 lr->lr_ref_tofollow = NULL;
594 lrparent = lr->lr_parent;
595 /* delete lr */
596 free_request(ld, lr);
597 /* lr now points on parent request */
598 lr = lrparent;
599 /* Follow referrals */
600 } else {
601 /* Here we have a simple result */
602 hadref = lr->lr_outrefcnt;
603 }
604 } else {
605 Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1286, "Error while decoding result for request %$1d\n"),
606 lr->lr_origid, NULL, NULL);
607 rc = -1; /* ??? */
608 }
609 }
610
611 total_count = 0;
612 if (tag != LDAP_RES_SEARCH_REFERENCE && lr->lr_references) {
613 /* Some search references pending... Let's try to chase them */
614 hadref = 1;
615 theReferences = lr->lr_references;
616
617 Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, -1, "Now following the search references received\n"),
618 0, 0,0);
619
620 while (theReferences != NULL){
621 if ((retcode = chase_referrals(ld, lr, theReferences->lref_refs , &refer_cnt, 0)) != LDAP_SUCCESS) {
622 /* think about what to do */
623 Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, -1, "Error while chasing referral (%1$d)\n"),
624 retcode, NULL, NULL);
625 theErrCode = LDAP_REFERRAL;
626 }
627 if (refer_cnt >= 0)
628 total_count += refer_cnt;
629 theReferences = theReferences->lref_next;
630 }
631 Ref_FreeAll(lr);
632 if (theErrCode != LDAP_SUCCESS) {
633 if (ld->ld_error != NULL && *ld->ld_error) {
634 if (lr->lr_res_error)
635 free(lr->lr_res_error);
636 lr->lr_res_error = strdup(ld->ld_error);
637 }
638 }
639 lr->lr_res_errno = theErrCode;
640 }
641 /* if theRefs != NULL we have some referrals to chase, do it */
642 if (theRefs){
643 hadref = 1;
644 if ((retcode = chase_referrals(ld, lr, theRefs, &refer_cnt, samereq)) != LDAP_SUCCESS){
645 /* think about what to do */
646 Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, -1, "Error while chasing referral (%1$d)\n"),
647 retcode, NULL, NULL);
648 }
649
650 if (refer_cnt >= 0)
651 total_count += refer_cnt;
652
653 ldap_value_free(theRefs);
654 if (samereq){ /* Just tried another referral for same request */
655 free(ber.ber_buf);
656 ber.ber_buf = NULL;
657 rc = -2;
658 /* continue */
659 }
660 if (retcode != LDAP_SUCCESS) {
661 if (ld->ld_version == LDAP_VERSION2){
662 if (lr->lr_res_error)
663 free(lr->lr_res_error);
664 lr->lr_res_error = ldap_referral2error_msg(lr->lr_ref_unfollowed);
665 } else if (ld->ld_error != NULL && *ld->ld_error) {
666 if (lr->lr_res_error)
667 free(lr->lr_res_error);
668 lr->lr_res_error = strdup(ld->ld_error);
669 }
670 }
671 lr->lr_res_errno = ld->ld_errno;
672
673 } else if (theErrCode == LDAP_SUCCESS) {
674 /* no referral have been chased */
675 lr->lr_res_errno = (lderr == LDAP_PARTIAL_RESULTS || lderr == LDAP_REFERRAL) ? LDAP_SUCCESS : lderr;
676 }
677
678 Debug( LDAP_DEBUG_TRACE,
679 catgets(slapdcat, 1, 231, "new result: res_errno: %1$d, res_error: <%2$s>, res_matched: <%3$s>\n"),
680 lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
681 lr->lr_res_matched ? lr->lr_res_matched : "" );
682 }
683
684
685 Debug( LDAP_DEBUG_TRACE,
686 catgets(slapdcat, 1, 232, "read1msg: %1$d new referrals\n"), total_count, 0, 0 );
687
688 if ( refer_cnt != 0 ) { /* chasing referrals */
689 free( ber.ber_buf ); /* gack! */
690 ber.ber_buf = NULL;
691 if ( refer_cnt < 0 ) {
692 return( -1 ); /* fatal error */
693 }
694 lr->lr_status = LDAP_REQST_CHASINGREFS;
695 } else if (tag == LDAP_RES_SEARCH_REFERENCE && !ld->ld_follow_referral) {
696 /* We had a ref and we don't follow referral : Do nothing there ?! */
697 Debug( LDAP_DEBUG_TRACE,
698 catgets(slapdcat, 1, -1, "read1msg: returning search reference\n"), 0, 0, 0 );
699
700 } else {
701 /* No referral chasing */
702 if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
703 /* request without any referrals */
704 simple_request = ( hadref ? 0 : 1 );
705 } else {
706 /* request with referrals or child request */
707 free( ber.ber_buf ); /* gack! */
708 ber.ber_buf = NULL;
709 }
710
711
712 while ( lr->lr_parent != NULL ) {
713 merge_error_info( ld, lr->lr_parent, lr );
714 lr = lr->lr_parent;
715 if ( --lr->lr_outrefcnt > 0 ) {
716 break; /* not completedly done yet */
717 }
718 }
719
720 if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) { /* The main request has no more outstanding refs */
721 id = lr->lr_msgid;
722 tag = lr->lr_res_msgtype;
723 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 233, "request %1$ld done\n"),
724 id, 0, 0 );
725 Debug( LDAP_DEBUG_TRACE,
726 catgets(slapdcat, 1, 234, "res_errno: %1$d, res_error: <%2$s>, res_matched: <%3$s>\n"),
727 lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
728 lr->lr_res_matched ? lr->lr_res_matched : "" );
729 if ( !simple_request ) { /* We have to rebuild the result */
730 if ( ber.ber_buf != NULL ) {
731 free( ber.ber_buf ); /* gack! */
732 ber.ber_buf = NULL;
733 }
734 if ( build_result_ber( ld, &ber, lr )
735 == LBER_ERROR ) {
736 ld->ld_errno = LDAP_NO_MEMORY;
737 rc = -1; /* fatal error */
738 }
739 }
740
741 free_request( ld, lr );
742 }
743
744 if ( lc != NULL ) {
745 free_connection( ld, lc, 0, 1 );
746 }
747 }
748 }
749
750 if ( ber.ber_buf == NULL ) { /* If the buffer has been freed, return */
751 return( rc );
752 }
753 /* End of REFERRALS */
754
755 /* make a new ldap message */
756 if ( (new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) ))
757 == NULL ) {
758 ld->ld_errno = LDAP_NO_MEMORY;
759 return( -1 );
760 }
761 new->lm_msgid = (int)id;
762 new->lm_msgtype = tag;
763 new->lm_ber = ber_dup( &ber );
764
765 #ifndef NO_CACHE
766 if ( ld->ld_cache != NULL ) {
767 add_result_to_cache( ld, new );
768 }
769 #endif /* NO_CACHE */
770
771 /* is this the one we're looking for? */
772 if ( msgid == LDAP_RES_ANY || id == msgid ) {
773 if ( all == LDAP_MSG_ONE /* all apply only to search, so if not a search,return the val */
774 || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
775 && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY
776 && new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) ) {
777 *result = new;
778 ld->ld_errno = LDAP_SUCCESS;
779 return( tag );
780 } else if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
781 foundit = 1; /* return the chain later */
782 }
783 }
784
785 /*
786 * if not, we must add it to the list of responses. if
787 * the msgid is already there, it must be part of an existing
788 * search response.
789 */
790
791 prev = NULLMSG;
792 for ( l = ld->ld_responses; l != NULLMSG; l = l->lm_next ) {
793 if ( l->lm_msgid == new->lm_msgid )
794 break;
795 prev = l;
796 }
797
798 /* not part of an existing search response */
799 if ( l == NULLMSG ) {
800 if ( foundit ) { /* it a search result anyway, so return it */
801 *result = new;
802 ld->ld_errno = LDAP_SUCCESS;
803 return( tag );
804 }
805
806 new->lm_next = ld->ld_responses;
807 ld->ld_responses = new;
808 return( -2 ); /* continue looking */
809 }
810
811 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 235, "adding response id %1$d type %2$d:\n"),
812 new->lm_msgid, new->lm_msgtype, 0 );
813
814 /* part of a search response - add to end of list of entries or references */
815 for ( tmp = l; tmp->lm_chain != NULLMSG &&
816 (tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ||
817 tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE);
818 tmp = tmp->lm_chain )
819 ; /* NULL */
820 tmp->lm_chain = new;
821
822 /* return the whole chain if that's what we were looking for */
823 if ( foundit ) {
824 if ( prev == NULLMSG )
825 ld->ld_responses = l->lm_next;
826 else
827 prev->lm_next = l->lm_next;
828 *result = l;
829 ld->ld_errno = LDAP_SUCCESS;
830 return( l->lm_msgtype ); /* Patch 16 : was return(tag) */
831 }
832
833 return( -2 ); /* continue looking */
834 }
835
836
837 static int
838 build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr )
839 {
840 unsigned int len;
841 int along;
842
843 Debug (LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1287, "=> building_ber_error msgid %ld\n"), lr->lr_msgid, 0,0);
844 ber_zero_init( ber, 0 );
845 set_ber_options( ld, ber );
846 if (ld->ld_version == LDAP_VERSION3){
847 if ( ber_printf( ber, "{it{ess",
848 lr->lr_msgid,
849 lr->lr_res_msgtype,
850 lr->lr_res_errno,
851 lr->lr_res_matched ? lr->lr_res_matched : "",
852 lr->lr_res_error ? lr->lr_res_error : "" ) == LBER_ERROR){
853 return (LBER_ERROR);
854 }
855 if (lr->lr_res_errno == LDAP_REFERRAL &&
856 ber_printf(ber, "t{v}", LDAP_TAG_REFERRAL, lr->lr_ref_unfollowed) == LBER_ERROR){
857 return (LBER_ERROR);
858 }
859 if (ber_printf(ber, "}}") == LBER_ERROR){
860 return (LBER_ERROR);
861 }
862 } else {
863 if ( ber_printf( ber, "{it{ess}}",
864 lr->lr_msgid,
865 lr->lr_res_msgtype,
866 lr->lr_res_errno,
867 lr->lr_res_matched ? lr->lr_res_matched : "",
868 lr->lr_res_error ? lr->lr_res_error : "" ) == LBER_ERROR ) {
869 return( LBER_ERROR );
870 }
871 }
872
873 ber_reset( ber, 1 );
874 if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
875 return( LBER_ERROR );
876 }
877
878 if ( ber_get_int( ber, &along ) == LBER_ERROR ) {
879 return( LBER_ERROR );
880 }
881
882 return( ber_peek_tag( ber, &len ));
883 }
884
885
886 static void
887 merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
888 {
889 int i, j;
890 /*
891 * Merge error information in "lr" with "parentr" error code and string.
892 */
893 if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
894 parentr->lr_res_errno = lr->lr_res_errno;
895 if ( lr->lr_res_error != NULL ) {
896 (void)append_referral( ld, &parentr->lr_res_error,
897 lr->lr_res_error );
898 }
899 } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
900 parentr->lr_res_errno == LDAP_SUCCESS ) {
901 parentr->lr_res_errno = lr->lr_res_errno;
902 if ( parentr->lr_res_error != NULL ) {
903 free( parentr->lr_res_error );
904 }
905 parentr->lr_res_error = lr->lr_res_error;
906 lr->lr_res_error = NULL;
907 if ( NAME_ERROR( lr->lr_res_errno )) {
908 if ( parentr->lr_res_matched != NULL ) {
909 free( parentr->lr_res_matched );
910 }
911 parentr->lr_res_matched = lr->lr_res_matched;
912 lr->lr_res_matched = NULL;
913 }
914 if (lr->lr_ref_unfollowed != NULL){
915 for (i=0;lr->lr_ref_unfollowed[i] != NULL; i++);
916 j = 0;
917 if (parentr->lr_ref_unfollowed != NULL){
918 for (j=0;parentr->lr_ref_unfollowed[j]!= NULL ;j++);
919 j++;
920 }
921 parentr->lr_ref_unfollowed = (char **)realloc (parentr->lr_ref_unfollowed, (j+i+1) * sizeof(char *));
922 if (parentr->lr_ref_unfollowed != NULL){
923 for (i = 0; lr->lr_ref_unfollowed[i] != NULL; i++){
924 parentr->lr_ref_unfollowed[j+i] = lr->lr_ref_unfollowed[i];
925 lr->lr_ref_unfollowed[i] = NULL;
926 }
927 parentr->lr_ref_unfollowed[i+j+1] = NULL;
928 } else {
929 if (parentr->lr_res_errno == LDAP_SUCCESS)
930 parentr->lr_res_errno = LDAP_NO_MEMORY;
931 }
932 }
933 }
934
935 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 236, "merged parent (id %1$d) error info: "),
936 parentr->lr_msgid, 0, 0 );
937 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 237, "result errno %1$d, error <%2$s>, matched <%3$s>\n"),
938 parentr->lr_res_errno,
939 parentr->lr_res_error ? parentr->lr_res_error : "",
940 parentr->lr_res_matched ? parentr->lr_res_matched : "" );
941 }
942
943 #ifdef CLDAP
944 #if !defined( MACOS ) && !defined( DOS ) && !defined( _WIN32 )
945 static int
946 ldap_select1( LDAP *ld, struct timeval *timeout )
947 {
948 fd_set readfds;
949 static int tblsize;
950
951 if ( tblsize == 0 ) {
952 #ifdef USE_SYSCONF
953 tblsize = (int) sysconf( _SC_OPEN_MAX );
954 #else /* USE_SYSCONF */
955 tblsize = getdtablesize();
956 #endif /* USE_SYSCONF */
957 }
958
959 FD_ZERO( &readfds );
960 FD_SET( ld->ld_sb.sb_sd, &readfds );
961
962 return( select( tblsize, &readfds, 0, 0, timeout ) );
963 }
964 #endif /* !MACOS */
965
966
967 #ifdef MACOS
968 static int
969 ldap_select1( LDAP *ld, struct timeval *timeout )
970 {
971 return( tcpselect( ld->ld_sb.sb_sd, timeout ));
972 }
973 #endif /* MACOS */
974
975
976 #if ( defined( DOS ) && defined( WINSOCK )) || defined( _WIN32 )
977 static int
978 ldap_select1( LDAP *ld, struct timeval *timeout )
979 {
980 fd_set readfds;
981 int rc;
982
983 FD_ZERO( &readfds );
984 FD_SET( ld->ld_sb.sb_sd, &readfds );
985
986 rc = select( 1, &readfds, 0, 0, timeout );
987 return( rc == SOCKET_ERROR ? -1 : rc );
988 }
989 #endif /* WINSOCK || _WIN32 */
990
991
992 #ifdef DOS
993 #ifdef PCNFS
994 static int
995 ldap_select1( LDAP *ld, struct timeval *timeout )
996 {
997 fd_set readfds;
998 int res;
999
1000 FD_ZERO( &readfds );
1001 FD_SET( ld->ld_sb.sb_sd, &readfds );
1002
1003 res = select( FD_SETSIZE, &readfds, NULL, NULL, timeout );
1004 if ( res == -1 && errno == EINTR) {
1005 /* We've been CTRL-C'ed at this point. It'd be nice to
1006 carry on but PC-NFS currently won't let us! */
1007 printf("\n*** CTRL-C ***\n");
1008 exit(-1);
1009 }
1010 return( res );
1011 }
1012 #endif /* PCNFS */
1013
1014 #ifdef NCSA
1015 static int
1016 ldap_select1( LDAP *ld, struct timeval *timeout )
1017 {
1018 int rc;
1019 clock_t endtime;
1020
1021 if ( timeout != NULL ) {
1022 endtime = timeout->tv_sec * CLK_TCK +
1023 timeout->tv_usec * CLK_TCK / 1000000 + clock();
1024 }
1025
1026 do {
1027 Stask();
1028 rc = netqlen( ld->ld_sb.sb_sd );
1029 } while ( rc <= 0 && ( timeout == NULL || clock() < endtime ));
1030
1031 return( rc > 0 ? 1 : 0 );
1032 }
1033 #endif /* NCSA */
1034 #endif /* DOS */
1035 #endif /* CLDAP */
1036
1037
1038 int
1039 ldap_msgfree( LDAPMessage *lm )
1040 {
1041 LDAPMessage *next;
1042 int type = 0;
1043
1044 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 238, "ldap_msgfree\n"), 0, 0, 0 );
1045
1046 for ( ; lm != NULLMSG; lm = next ) {
1047 next = lm->lm_chain;
1048 type = lm->lm_msgtype;
1049 if (lm->lm_ber)
1050 ber_free( lm->lm_ber, 1 );
1051 free( (char *) lm );
1052 }
1053
1054 return( type );
1055 }
1056
1057 /*
1058 * ldap_msgdelete - delete a message. It returns:
1059 * 0 if the entire message was deleted
1060 * -1 if the message was not found, or only part of it was found
1061 */
1062 int
1063 ldap_msgdelete( LDAP *ld, int msgid )
1064 {
1065 LDAPMessage *lm, *prev;
1066
1067 #ifdef _REENTRANT
1068 LOCK_LDAP(ld);
1069 LOCK_RESPONSE(ld);
1070 #endif
1071 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 239, "ldap_msgdelete\n"), 0, 0, 0 );
1072
1073 prev = NULLMSG;
1074 for ( lm = ld->ld_responses; lm != NULLMSG; lm = lm->lm_next ) {
1075 if ( lm->lm_msgid == msgid )
1076 break;
1077 prev = lm;
1078 }
1079
1080 if ( lm == NULLMSG ) {
1081 #ifdef _REENTRANT
1082 UNLOCK_LDAP(ld);
1083 UNLOCK_RESPONSE(ld);
1084 #endif
1085 return( -1 );
1086 }
1087
1088 if ( prev == NULLMSG )
1089 ld->ld_responses = lm->lm_next;
1090 else
1091 prev->lm_next = lm->lm_next;
1092
1093 if ( ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY ) {
1094 #ifdef _REENTRANT
1095 UNLOCK_LDAP(ld);
1096 UNLOCK_RESPONSE(ld);
1097 #endif
1098 return( -1 );
1099 }
1100
1101 #ifdef _REENTRANT
1102 UNLOCK_LDAP(ld);
1103 UNLOCK_RESPONSE(ld);
1104 #endif
1105 return( 0 );
1106 }
1107
1108
1109 /*
1110 * return 1 if message msgid is waiting to be abandoned, 0 otherwise
1111 */
1112 static int
1113 ldap_abandoned( LDAP *ld, int msgid )
1114 {
1115 int i;
1116
1117 if ( ld == NULL ) return(1);
1118 if ( ld->ld_abandoned == NULL )
1119 return( 0 );
1120
1121 for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
1122 if ( ld->ld_abandoned[i] == msgid )
1123 return( 1 );
1124
1125 return( 0 );
1126 }
1127
1128
1129 static int
1130 ldap_mark_abandoned( LDAP *ld, int msgid )
1131 {
1132 int i;
1133
1134 if ( ld->ld_abandoned == NULL )
1135 return( -1 );
1136
1137 for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
1138 if ( ld->ld_abandoned[i] == msgid )
1139 break;
1140
1141 if ( ld->ld_abandoned[i] == -1 )
1142 return( -1 );
1143
1144 for ( ; ld->ld_abandoned[i] != -1; i++ ) {
1145 ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
1146 }
1147
1148 return( 0 );
1149 }
1150
1151
1152 #ifdef CLDAP
1153 int
1154 cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber )
1155 {
1156 int rc;
1157 unsigned int tag, len;
1158
1159 #ifdef _REENTRANT
1160 LOCK_LDAP(ld);
1161 #endif
1162 if ( ld->ld_sb.sb_ber.ber_ptr >= ld->ld_sb.sb_ber.ber_end ) {
1163 rc = ldap_select1( ld, timeout );
1164 if ( rc == -1 || rc == 0 ) {
1165 ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
1166 LDAP_TIMEOUT);
1167 #ifdef _REENTRANT
1168 UNLOCK_LDAP(ld);
1169 #endif
1170 return( rc );
1171 }
1172 }
1173
1174 /* get the next message */
1175 if ( (tag = ber_get_next( &ld->ld_sb, &len, ber ))
1176 != LDAP_TAG_MESSAGE ) {
1177 ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
1178 LDAP_LOCAL_ERROR);
1179 #ifdef _REENTRANT
1180 UNLOCK_LDAP(ld);
1181 #endif
1182 return( -1 );
1183 }
1184
1185 #ifdef _REENTRANT
1186 UNLOCK_LDAP(ld);
1187 #endif
1188 return( tag );
1189 }
1190 #endif /* CLDAP */
1191
1192 /* ldapv3 API extensions */
1193
1194 int ldap_msgtype(LDAPMessage *res)
1195 {
1196 if (res == NULL)
1197 return (LDAP_RES_ANY);
1198 return (res->lm_msgtype);
1199 }
1200
1201
1202 int ldap_msgid(LDAPMessage *res)
1203 {
1204 if (res == NULL)
1205 return (LDAP_RES_ANY);
1206 return (res->lm_msgid);
1207 }
1208
1209 int ldap_parse_result(LDAP *ld, LDAPMessage *res, int *errcodep, char **matcheddnp,
1210 char **errmsgp, char ***referralsp, LDAPControl ***serverctrlsp,
1211 int freeit)
1212 {
1213 LDAPMessage *lm;
1214 BerElement ber;
1215 unsigned int alen;
1216 int along;
1217 unsigned int tag;
1218 int i;
1219 size_t rc;
1220 char * acharp = NULL, * a2ndcharp = NULL;
1221 char ** arefs = NULL;
1222
1223 Debug( LDAP_DEBUG_TRACE, "ldap_parse_result\n", 0, 0, 0 );
1224
1225 if (res == NULLMSG)
1226 return (LDAP_PARAM_ERROR);
1227
1228 if (matcheddnp && *matcheddnp){
1229 free(*matcheddnp);
1230 *matcheddnp = NULL;
1231 }
1232 if (errmsgp && *errmsgp){
1233 free(*errmsgp);
1234 *errmsgp = NULL;
1235 }
1236 if (referralsp && *referralsp){
1237 free_strarray(*referralsp);
1238 *referralsp = NULL;
1239 }
1240
1241 if (serverctrlsp && *serverctrlsp){
1242 ldap_controls_free(*serverctrlsp);
1243 *serverctrlsp = NULL;
1244 }
1245
1246 for (lm = res; lm->lm_chain != NULL; lm = lm->lm_chain)
1247
1248 if ( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY
1249 && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE)
1250 break;
1251
1252 ber = *(lm->lm_ber);
1253
1254 #ifdef _REENTRANT
1255 LOCK_LDAP(ld);
1256 #endif
1257 if (ld->ld_version == LDAP_VERSION3) {
1258 rc = ber_scanf( &ber, "{iaa", &along, &acharp, &a2ndcharp);
1259 if (rc == LBER_ERROR){
1260 if (freeit)
1261 ldap_msgfree( res );
1262 #ifdef _REENTRANT
1263 UNLOCK_LDAP(ld);
1264 #endif
1265 return (LDAP_DECODING_ERROR);
1266 }
1267 if (matcheddnp) {
1268 *matcheddnp = acharp;
1269 } else {
1270 ldap_memfree(acharp);
1271 }
1272 if (errmsgp) {
1273 *errmsgp = a2ndcharp;
1274 } else {
1275 ldap_memfree(a2ndcharp);
1276 }
1277
1278 if (errcodep) {
1279 *errcodep = along;
1280 }
1281
1282 if (along == LDAP_REFERRAL){
1283 if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_REFERRAL) {
1284 rc = ber_scanf(&ber, "{v}", &arefs);
1285 if (rc == LBER_ERROR){
1286 /* try to free other stuff */
1287 if (freeit)
1288 ldap_msgfree( res );
1289 #ifdef _REENTRANT
1290 UNLOCK_LDAP(ld);
1291 #endif
1292 return (LDAP_DECODING_ERROR);
1293 }
1294 if (referralsp) {
1295 *referralsp = arefs;
1296 } else {
1297 for (i = 0; arefs[i] != NULL; i++)
1298 ldap_memfree(arefs[i]);
1299 ldap_memfree((char *)arefs);
1300 }
1301 } else {
1302 /* referral errcode without URL is forbiden */
1303 if (freeit)
1304 ldap_msgfree( res );
1305 #ifdef _REENTRANT
1306 UNLOCK_LDAP(ld);
1307 #endif
1308 return (LDAP_DECODING_ERROR);
1309 }
1310 }
1311 rc = ber_scanf(&ber, "}");
1312 if (rc == LBER_ERROR){
1313 if (freeit)
1314 ldap_msgfree( res );
1315 #ifdef _REENTRANT
1316 UNLOCK_LDAP(ld);
1317 #endif
1318 return (LDAP_DECODING_ERROR);
1319 }
1320 /* It's the end of the result but the PDU may have controls */
1321 if (serverctrlsp && (ber_peek_tag(&ber, &alen) == LDAP_TAG_CONTROL_LIST)) {
1322 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 392, "Controls found in result\n"), 0, 0, 0 );
1323 *serverctrlsp = ldap_controls_decode(&ber,
1324 (int *)&rc);
1325 if (*serverctrlsp == NULL) {
1326 if (freeit)
1327 ldap_msgfree( res );
1328 #ifdef _REENTRANT
1329 UNLOCK_LDAP(ld);
1330 #endif
1331 return (LDAP_DECODING_ERROR);
1332 }
1333 } else {
1334 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 393, "NO controls found in result\n"), 0, 0, 0 );
1335 }
1336 }
1337 else if (ld->ld_version == LDAP_VERSION2) {
1338 rc = ber_scanf( &ber, "{iaa}", &along, &acharp,
1339 &a2ndcharp );
1340 if (rc == LBER_ERROR){
1341 if (freeit)
1342 ldap_msgfree( res );
1343 #ifdef _REENTRANT
1344 UNLOCK_LDAP(ld);
1345 #endif
1346 return (LDAP_DECODING_ERROR);
1347 }
1348 if (matcheddnp) {
1349 *matcheddnp = acharp;
1350 } else {
1351 ldap_memfree(acharp);
1352 }
1353 if (errmsgp) {
1354 *errmsgp = a2ndcharp;
1355 } else {
1356 ldap_memfree(a2ndcharp);
1357 }
1358 if (errcodep) {
1359 *errcodep = along;
1360 }
1361 }
1362 else {
1363 rc = ber_scanf( &ber, "{ia}", &along, &a2ndcharp );
1364 if (rc == LBER_ERROR){
1365 if (freeit)
1366 ldap_msgfree( res );
1367 #ifdef _REENTRANT
1368 UNLOCK_LDAP(ld);
1369 #endif
1370 return (LDAP_DECODING_ERROR);
1371 }
1372
1373 if (errmsgp) {
1374 *errmsgp = a2ndcharp;
1375 } else {
1376 ldap_memfree(a2ndcharp);
1377 }
1378 if (errcodep) {
1379 *errcodep = along;
1380 }
1381 }
1382
1383 if ( freeit )
1384 ldap_msgfree(res);
1385
1386 #ifdef _REENTRANT
1387 UNLOCK_LDAP(ld);
1388 #endif
1389 return (LDAP_SUCCESS);
1390 }
1391
1392 int ldap_parse_sasl_bind_result(LDAP *ld, LDAPMessage *res, struct berval **servercredp, int freeit)
1393 {
1394 LDAPMessage *lm;
1395 BerElement ber;
1396 int along;
1397 unsigned int tag;
1398 int i;
1399 size_t rc;
1400 char * acharp = NULL, *a2ndcharp = NULL;
1401 char ** arefs = NULL;
1402 struct berval * creds = NULL;
1403
1404 Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
1405
1406 if (res == NULLMSG)
1407 return (LDAP_PARAM_ERROR);
1408
1409 #ifdef _REENTRANT
1410 LOCK_LDAP(ld);
1411 #endif
1412 if ((res->lm_msgtype != LDAP_RES_BIND) || (ld->ld_version != LDAP_VERSION3)){
1413 ld->ld_errno = LDAP_PARAM_ERROR;
1414 #ifdef _REENTRANT
1415 UNLOCK_LDAP(ld);
1416 #endif
1417 return (LDAP_PARAM_ERROR);
1418 }
1419 #ifdef _REENTRANT
1420 UNLOCK_LDAP(ld);
1421 #endif
1422
1423 ber = *(res->lm_ber);
1424 rc = ber_scanf( &ber, "{iaa", &along, &acharp, &a2ndcharp);
1425 if (rc == LBER_ERROR){
1426 if (freeit)
1427 ldap_msgfree( res );
1428 #ifdef _REENTRANT
1429 LOCK_LDAP(ld);
1430 #endif
1431 ld->ld_errno = LDAP_DECODING_ERROR;
1432 #ifdef _REENTRANT
1433 UNLOCK_LDAP(ld);
1434 #endif
1435 return (LDAP_DECODING_ERROR);
1436 }
1437 ldap_memfree(acharp);
1438 ldap_memfree(a2ndcharp);
1439 if (along == LDAP_SUCCESS || along == LDAP_SASL_BIND_INPROGRESS){
1440 /* Decode the serverSaslCreds if any */
1441 if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_SASLCREDS) {
1442 rc = ber_get_stringal( &ber, &creds);
1443 if (rc == LBER_ERROR ){
1444 if (freeit)
1445 ldap_msgfree(res);
1446 #ifdef _REENTRANT
1447 LOCK_LDAP(ld);
1448 #endif
1449 ld->ld_errno = LDAP_DECODING_ERROR;
1450 #ifdef _REENTRANT
1451 UNLOCK_LDAP(ld);
1452 #endif
1453 return (LDAP_DECODING_ERROR);
1454 }
1455 if (servercredp) {
1456 *servercredp = creds;
1457 } else {
1458 ber_bvfree( creds );
1459 }
1460 }
1461 } else if (along == LDAP_REFERRAL) {
1462 if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_REFERRAL){
1463 rc = ber_scanf(&ber, "{v}", &arefs);
1464 if (rc == LBER_ERROR){
1465 /* try to free other stuff */
1466 if (freeit)
1467 ldap_msgfree( res );
1468 #ifdef _REENTRANT
1469 LOCK_LDAP(ld);
1470 #endif
1471 ld->ld_errno = LDAP_DECODING_ERROR;
1472 #ifdef _REENTRANT
1473 UNLOCK_LDAP(ld);
1474 #endif
1475 return (LDAP_DECODING_ERROR);
1476 }
1477 for (i = 0; arefs[i] != NULL; i++)
1478 ldap_memfree(arefs[i]);
1479 ldap_memfree((char *)arefs);
1480 } else {
1481 /* There should be at least one ref */
1482 if (freeit)
1483 ldap_msgfree( res );
1484 #ifdef _REENTRANT
1485 LOCK_LDAP(ld);
1486 #endif
1487 ld->ld_errno = LDAP_DECODING_ERROR;
1488 #ifdef _REENTRANT
1489 UNLOCK_LDAP(ld);
1490 #endif
1491 return (LDAP_DECODING_ERROR);
1492 }
1493 }
1494
1495 rc = ber_scanf(&ber, "}");
1496 if (rc == LBER_ERROR){
1497 if (freeit)
1498 ldap_msgfree( res );
1499 #ifdef _REENTRANT
1500 LOCK_LDAP(ld);
1501 #endif
1502 ld->ld_errno = LDAP_DECODING_ERROR;
1503 #ifdef _REENTRANT
1504 UNLOCK_LDAP(ld);
1505 #endif
1506 return (LDAP_DECODING_ERROR);
1507 }
1508
1509 if ( freeit )
1510 ldap_msgfree(res);
1511 #ifdef _REENTRANT
1512 LOCK_LDAP(ld);
1513 #endif
1514 ld->ld_errno = along;
1515 #ifdef _REENTRANT
1516 UNLOCK_LDAP(ld);
1517 #endif
1518 return (along);
1519 }
1520
1521 int ldap_parse_extended_result(LDAP *ld, LDAPMessage *res, char **resultoidp,
1522 struct berval **resultdata, int freeit)
1523 {
1524 LDAPMessage *lm;
1525 BerElement ber;
1526 int along;
1527 unsigned int tag;
1528 int i;
1529 size_t rc;
1530 char * acharp = NULL, *a2ndcharp = NULL, *anoid = NULL;
1531 char **arefs = NULL;
1532 struct berval * aresp = NULL;
1533
1534 Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
1535
1536 if ( res == NULLMSG )
1537 return (LDAP_PARAM_ERROR);
1538
1539 #ifdef _REENTRANT
1540 LOCK_LDAP(ld);
1541 #endif
1542 if ((res->lm_msgtype != LDAP_RES_EXTENDED) || (ld->ld_version != LDAP_VERSION3))
1543 {
1544 if ( res->lm_msgid != 0 )
1545 #ifdef _REENTRANT
1546 UNLOCK_LDAP(ld);
1547 #endif
1548 return (LDAP_PARAM_ERROR);
1549 }
1550 #ifdef _REENTRANT
1551 UNLOCK_LDAP(ld);
1552 #endif
1553
1554 ber = *(res->lm_ber);
1555 rc = ber_scanf( &ber, "{iaa", &along, &acharp, &a2ndcharp);
1556 if (rc == LBER_ERROR){
1557 if (freeit)
1558 ldap_msgfree( res );
1559 return (LDAP_DECODING_ERROR);
1560 }
1561 ldap_memfree(acharp);
1562 ldap_memfree(a2ndcharp);
1563
1564 if (along == LDAP_REFERRAL) {
1565 if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_REFERRAL){
1566 rc = ber_scanf(&ber, "{v}", &arefs);
1567 if (rc == LBER_ERROR){
1568 /* try to free other stuff */
1569 if (freeit)
1570 ldap_msgfree( res );
1571 return (LDAP_DECODING_ERROR);
1572 }
1573 for (i = 0; arefs[i] != NULL; i++)
1574 ldap_memfree(arefs[i]);
1575 ldap_memfree((char *)arefs);
1576 } else {
1577 /* There should be at least one ref */
1578 if (freeit)
1579 ldap_msgfree( res );
1580 return (LDAP_DECODING_ERROR);
1581 }
1582 }
1583
1584 if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_EXT_RESPNAME) {
1585 rc = ber_get_stringa( &ber, &anoid);
1586 if (rc == LBER_ERROR ){
1587 if (freeit)
1588 ldap_msgfree(res);
1589 return (LDAP_DECODING_ERROR);
1590 }
1591 if (resultoidp) {
1592 *resultoidp = anoid;
1593 } else {
1594 ldap_memfree( anoid );
1595 }
1596 }
1597 if (ber_peek_tag ( &ber, &tag) == LDAP_TAG_EXT_RESPONSE) {
1598 rc = ber_get_stringal( &ber, &aresp);
1599 if (rc == LBER_ERROR ){
1600 if (freeit)
1601 ldap_msgfree(res);
1602 return (LDAP_DECODING_ERROR);
1603 }
1604 if (resultdata) {
1605 *resultdata = aresp;
1606 } else {
1607 ber_bvfree( aresp );
1608 }
1609 }
1610
1611 rc = ber_scanf(&ber, "}");
1612 if (rc == LBER_ERROR){
1613 if (freeit)
1614 ldap_msgfree( res );
1615 return (LDAP_DECODING_ERROR);
1616 }
1617
1618 if ( freeit )
1619 ldap_msgfree(res);
1620
1621 return (along);
1622 }
1623
1624
1625 static int Ref_AddToRequest(LDAPRequest *lr, char **refs) {
1626 int count;
1627 LDAPRef *lref;
1628 LDAPRef *newRef;
1629
1630 if ((newRef = (LDAPRef *)calloc(1, sizeof (LDAPRef))) == NULL){
1631 return LDAP_NO_MEMORY;
1632 }
1633 newRef->lref_refs = refs;
1634 newRef->lref_next = NULL;
1635 lref = lr->lr_references;
1636 if (lref == NULL){
1637 lr->lr_references = newRef;
1638 } else {
1639 while (lref->lref_next != NULL)
1640 lref = lref->lref_next;
1641 lref->lref_next = newRef;
1642 }
1643 return LDAP_SUCCESS;
1644 }
1645
1646 static void Ref_FreeAll(LDAPRequest *lr)
1647 {
1648 LDAPRef *lref, *next;
1649 lref = lr->lr_references;
1650 while (lref != NULL){
1651 next = lref->lref_next;
1652 ldap_value_free(lref->lref_refs);
1653 free (lref);
1654 lref = next;
1655 }
1656 lr->lr_references = NULL;
1657 }
1658