home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ldapsdk.zip / libraries / libldap / result.c < prev    next >
C/C++ Source or Header  |  2001-03-15  |  25KB  |  954 lines

  1. /* $OpenLDAP: pkg/ldap/libraries/libldap/result.c,v 1.36.2.12 2001/03/15 03:20:03 kurt Exp $ */
  2. /*
  3.  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
  4.  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  5.  */
  6. /*  Portions
  7.  *  Copyright (c) 1990 Regents of the University of Michigan.
  8.  *  All rights reserved.
  9.  */
  10. /*---
  11.  * This notice applies to changes, created by or for Novell, Inc.,
  12.  * to preexisting works for which notices appear elsewhere in this file.
  13.  *
  14.  * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
  15.  *
  16.  * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
  17.  * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
  18.  * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
  19.  * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
  20.  * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
  21.  * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
  22.  * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
  23.  * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 
  24.  *---
  25.  * Modification to OpenLDAP source by Novell, Inc.
  26.  * April 2000 sfs Add code to process V3 referrals and search results
  27.  *
  28.  *  result.c - wait for an ldap result
  29.  */
  30.  
  31. /*
  32.  * LDAPv3 (RFC2251)
  33.  *    LDAPResult ::= SEQUENCE {
  34.  *        resultCode        ENUMERATED { ... },
  35.  *        matchedDN        LDAPDN,
  36.  *        errorMessage    LDAPString,
  37.  *        referral        Referral OPTIONAL
  38.  *    }
  39.  *    Referral ::= SEQUENCE OF LDAPURL    (one or more)
  40.  *    LDAPURL ::= LDAPString                (limited to URL chars)
  41.  */
  42.  
  43. #include "portable.h"
  44.  
  45. #include <stdio.h>
  46.  
  47. #include <ac/stdlib.h>
  48.  
  49. #include <ac/errno.h>
  50. #include <ac/socket.h>
  51. #include <ac/string.h>
  52. #include <ac/time.h>
  53. #include <ac/unistd.h>
  54.  
  55. #include "ldap-int.h"
  56.  
  57.  
  58. static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
  59. static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid ));
  60. static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout,
  61.     LDAPMessage **result ));
  62. static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid,
  63.     int all, Sockbuf *sb, LDAPConn *lc, LDAPMessage **result ));
  64. static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr ));
  65. static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ));
  66. static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all));
  67.  
  68.  
  69. /*
  70.  * ldap_result - wait for an ldap result response to a message from the
  71.  * ldap server.  If msgid is LDAP_RES_ANY (-1), any message will be
  72.  * accepted.  If msgid is LDAP_RES_UNSOLICITED (0), any unsolicited
  73.  * message is accepted.  Otherwise ldap_result will wait for a response
  74.  * with msgid.  If all is LDAP_MSG_ONE (0) the first message with id
  75.  * msgid will be accepted, otherwise, ldap_result will wait for all
  76.  * responses with id msgid and then return a pointer to the entire list
  77.  * of messages.  In general, this is only useful for search responses,
  78.  * which can be of three message types (zero or more entries, zero or
  79.  * search references, followed by an ldap result).  An extension to
  80.  * LDAPv3 allows partial extended responses to be returned in response
  81.  * to any request.  The type of the first message received is returned.
  82.  * When waiting, any messages that have been abandoned are discarded.
  83.  *
  84.  * Example:
  85.  *    ldap_result( s, msgid, all, timeout, result )
  86.  */
  87. int
  88. ldap_result(
  89.     LDAP *ld,
  90.     int msgid,
  91.     int all,
  92.     struct timeval *timeout,
  93.     LDAPMessage **result )
  94. {
  95.     LDAPMessage    *lm;
  96.  
  97.     assert( ld != NULL );
  98.     assert( result != NULL );
  99.  
  100.     Debug( LDAP_DEBUG_TRACE, "ldap_result msgid %d\n", msgid, 0, 0 );
  101.  
  102.     if( ld == NULL ) {
  103.         return -1;
  104.     }
  105.  
  106.     if( result == NULL ) {
  107.         ld->ld_errno = LDAP_PARAM_ERROR;
  108.         return -1;
  109.     }
  110.  
  111.     lm = chkResponseList(ld, msgid, all);
  112.  
  113.     if ( lm == NULL ) {
  114.         return( wait4msg( ld, msgid, all, timeout, result ) );
  115.     }
  116.  
  117.     *result = lm;
  118.     ld->ld_errno = LDAP_SUCCESS;
  119.     return( lm->lm_msgtype );
  120. }
  121.  
  122. static LDAPMessage *
  123. chkResponseList(
  124.     LDAP *ld,
  125.     int msgid,
  126.     int all)
  127. {
  128.     LDAPMessage    *lm, *lastlm, *nextlm;
  129.     /*
  130.      * Look through the list of responses we have received on
  131.      * this association and see if the response we're interested in
  132.      * is there.  If it is, return it.  If not, call wait4msg() to
  133.      * wait until it arrives or timeout occurs.
  134.      */
  135.  
  136.     Debug( LDAP_DEBUG_TRACE,
  137.         "ldap_chkResponseList for msgid=%d, all=%d\n",
  138.         msgid, all, 0 );
  139.     lastlm = NULL;
  140.     for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) {
  141.         nextlm = lm->lm_next;
  142.  
  143.         if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
  144.             Debug( LDAP_DEBUG_TRACE,
  145.                 "ldap_chkResponseList msg abandoned, msgid %d\n",
  146.                 msgid, 0, 0 );
  147.             ldap_mark_abandoned( ld, lm->lm_msgid );
  148.  
  149.             if ( lastlm == NULL ) {
  150.                 /* Remove first entry in list */
  151.                 ld->ld_responses = lm->lm_next;
  152.             } else {
  153.                 lastlm->lm_next = nextlm;
  154.             }
  155.  
  156.             ldap_msgfree( lm );
  157.  
  158.             continue;
  159.         }
  160.  
  161.         if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
  162.             LDAPMessage    *tmp;
  163.  
  164.             if ( all == LDAP_MSG_ONE || msgid == LDAP_RES_UNSOLICITED ) {
  165.                 break;
  166.             }
  167.  
  168.             for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
  169.                 if ( tmp->lm_msgtype != LDAP_RES_SEARCH_ENTRY
  170.                     && tmp->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
  171.                     && tmp->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL )
  172.                 {
  173.                     break;
  174.                 }
  175.             }
  176.  
  177.             if ( tmp == NULL ) {
  178.                 lm = NULL;
  179.             }
  180.  
  181.             break;
  182.         }
  183.         lastlm = lm;
  184.     }
  185.  
  186.     if ( lm != NULL ) {
  187.         /* Found an entry, remove it from the list */
  188.         if ( lastlm == NULL ) {
  189.             ld->ld_responses = (all == LDAP_MSG_ONE && lm->lm_chain != NULL
  190.                 ? lm->lm_chain : lm->lm_next);
  191.         } else {
  192.             lastlm->lm_next = (all == LDAP_MSG_ONE && lm->lm_chain != NULL
  193.                 ? lm->lm_chain : lm->lm_next);
  194.         }
  195.         if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) {
  196.             lm->lm_chain->lm_next = lm->lm_next;
  197.             lm->lm_chain = NULL;
  198.         }
  199.         lm->lm_next = NULL;
  200.     }
  201.  
  202. #ifdef LDAP_DEBUG
  203.     if( lm == NULL) {
  204.         Debug( LDAP_DEBUG_TRACE,
  205.             "ldap_chkResponseList returns NULL\n", 0, 0, 0);
  206.     } else {
  207.         Debug( LDAP_DEBUG_TRACE,
  208.             "ldap_chkResponseList returns msgid %d, type 0x%02lu\n",
  209.             lm->lm_msgid, (unsigned long) lm->lm_msgtype, 0);
  210.     }
  211. #endif
  212.     return lm;
  213. }
  214.  
  215. static int
  216. wait4msg(
  217.     LDAP *ld,
  218.     ber_int_t msgid,
  219.     int all,
  220.     struct timeval *timeout,
  221.     LDAPMessage **result )
  222. {
  223.     int        rc;
  224.     struct timeval    tv, *tvp;
  225.     time_t        start_time = 0;
  226.     time_t        tmp_time;
  227.     LDAPConn    *lc, *nextlc;
  228.  
  229.     assert( ld != NULL );
  230.     assert( result != NULL );
  231.  
  232. #ifdef LDAP_DEBUG
  233.     if ( timeout == NULL ) {
  234.         Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout), msgid %d\n",
  235.             msgid, 0, 0 );
  236.     } else {
  237.         Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec), msgid %d\n",
  238.                (long) timeout->tv_sec, (long) timeout->tv_usec, msgid );
  239.     }
  240. #endif /* LDAP_DEBUG */
  241.  
  242.     if ( timeout == NULL ) {
  243.         tvp = NULL;
  244.     } else {
  245.         tv = *timeout;
  246.         tvp = &tv;
  247.         start_time = time( NULL );
  248.     }
  249.             
  250.     rc = -2;
  251.     while ( rc == -2 ) {
  252. #ifdef LDAP_DEBUG
  253.         Debug( LDAP_DEBUG_TRACE, "wait4msg continue, msgid %d, all %d\n",
  254.             msgid, all, 0 );
  255.         if ( ldap_debug & LDAP_DEBUG_TRACE ) {
  256.             ldap_dump_connection( ld, ld->ld_conns, 1 );
  257.             ldap_dump_requests_and_responses( ld );
  258.         }
  259. #endif /* LDAP_DEBUG */
  260.  
  261.         if( (*result = chkResponseList(ld, msgid, all)) != NULL ) {
  262.             rc = (*result)->lm_msgtype;
  263.         } else {
  264.  
  265.             for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
  266.                 if ( ber_sockbuf_ctrl( lc->lconn_sb,
  267.                         LBER_SB_OPT_DATA_READY, NULL ) ) {
  268.                         rc = try_read1msg( ld, msgid, all, lc->lconn_sb,
  269.                             lc, result );
  270.                     break;
  271.                 }
  272.             }
  273.  
  274.             if ( lc == NULL ) {
  275.                 rc = do_ldap_select( ld, tvp );
  276.  
  277.  
  278. #ifdef LDAP_DEBUG
  279.                 if ( rc == -1 ) {
  280.                     Debug( LDAP_DEBUG_TRACE,
  281.                         "do_ldap_select returned -1: errno %d\n",
  282.                         errno, 0, 0 );
  283.                 }
  284. #endif
  285.  
  286.                 if ( rc == 0 || ( rc == -1 && (
  287.                     !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)
  288.                     || errno != EINTR )))
  289.                 {
  290.                     ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
  291.                         LDAP_TIMEOUT);
  292.                     return( rc );
  293.                 }
  294.  
  295.                 if ( rc == -1 ) {
  296.                     rc = -2;    /* select interrupted: loop */
  297.                 } else {
  298.                     rc = -2;
  299.                     for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
  300.                         lc = nextlc ) {
  301.                         nextlc = lc->lconn_next;
  302.                         if ( lc->lconn_status ==
  303.                             LDAP_CONNST_CONNECTED &&
  304.                             ldap_is_read_ready( ld,
  305.                             lc->lconn_sb )) {
  306.                             rc = try_read1msg( ld, msgid, all,
  307.                                 lc->lconn_sb, lc, result );
  308.                         }
  309.                     }
  310.                 }
  311.             }
  312.         }
  313.  
  314.         if ( rc == -2 && tvp != NULL ) {
  315.             tmp_time = time( NULL );
  316.             if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
  317.                 rc = 0;    /* timed out */
  318.                 ld->ld_errno = LDAP_TIMEOUT;
  319.                 break;
  320.             }
  321.  
  322.             Debug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
  323.                    (long) tv.tv_sec, 0, 0 );
  324.             start_time = tmp_time;
  325.         }
  326.     }
  327.  
  328.     return( rc );
  329. }
  330.  
  331.  
  332. static ber_tag_t
  333. try_read1msg(
  334.     LDAP *ld,
  335.     ber_int_t msgid,
  336.     int all,
  337.     Sockbuf *sb,
  338.     LDAPConn *lc,
  339.     LDAPMessage **result )
  340. {
  341.     BerElement    *ber;
  342.     LDAPMessage    *new, *l, *prev, *tmp;
  343.     ber_int_t    id;
  344.     ber_tag_t    tag;
  345.     ber_len_t    len;
  346.     int        foundit = 0;
  347.     LDAPRequest    *lr, *tmplr;
  348.     BerElement    tmpber;
  349.     int        rc, refer_cnt, hadref, simple_request;
  350.     ber_int_t    lderr;
  351.     /*
  352.      * v3ref = flag for V3 referral / search reference
  353.      * 0 = not a ref, 1 = sucessfully chased ref, -1 = pass ref to application
  354.      */
  355.     int     v3ref;
  356.  
  357.     assert( ld != NULL );
  358.     assert( lc != NULL );
  359.     
  360.     Debug( LDAP_DEBUG_TRACE, "read1msg: msgid %d, all %d\n", msgid, all, 0 );
  361.  
  362.     if ( lc->lconn_ber == NULL ) {
  363.         lc->lconn_ber = ldap_alloc_ber_with_options(ld);
  364.  
  365.         if( lc->lconn_ber == NULL ) {
  366.             return -1;
  367.         }
  368.     }
  369.  
  370.     ber = lc->lconn_ber;
  371.     assert( BER_VALID (ber) );
  372.  
  373.     /* get the next message */
  374.     errno = 0;
  375.     if ( (tag = ber_get_next( sb, &len, ber ))
  376.         != LDAP_TAG_MESSAGE ) {
  377.         if ( tag == LBER_DEFAULT) {
  378. #ifdef LDAP_DEBUG           
  379.             Debug( LDAP_DEBUG_CONNS,
  380.                   "ber_get_next failed.\n", 0, 0, 0 );
  381. #endif           
  382. #ifdef EWOULDBLOCK            
  383.             if (errno==EWOULDBLOCK) return -2;
  384. #endif
  385. #ifdef EAGAIN
  386.             if (errno == EAGAIN) return -2;
  387. #endif
  388.             ld->ld_errno = LDAP_SERVER_DOWN;
  389.             return -1;
  390.         }
  391.         ld->ld_errno = LDAP_LOCAL_ERROR;
  392.         return -1;
  393.     }
  394.  
  395.     /*
  396.      * We read a complete message.
  397.      * The connection should no longer need this ber.
  398.      */
  399.     lc->lconn_ber = NULL;
  400.  
  401.     /* message id */
  402.     if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
  403.         ber_free( ber, 1 );
  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, id ) ) {
  410.         ber_free( ber, 1 );
  411.         Debug( LDAP_DEBUG_ANY, "abandoned\n", 0, 0, 0);
  412.         return( -2 );    /* continue looking */
  413.     }
  414.  
  415.     if (( lr = ldap_find_request_by_msgid( ld, id )) == NULL ) {
  416.         Debug( LDAP_DEBUG_ANY,
  417.             "no request for response with msgid %ld (tossing)\n",
  418.             (long) id, 0, 0 );
  419.         ber_free( ber, 1 );
  420.         return( -2 );    /* continue looking */
  421.     }
  422.  
  423.     /* the message type */
  424.     if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
  425.         ld->ld_errno = LDAP_DECODING_ERROR;
  426.         ber_free( ber, 1 );
  427.         return( -1 );
  428.     }
  429.  
  430.     Debug( LDAP_DEBUG_TRACE,
  431.         "ldap_read: message type %s msgid %ld, original id %ld\n",
  432.         ldap_int_msgtype2str( tag ),
  433.         (long) lr->lr_msgid, (long) lr->lr_origid );
  434.  
  435.     id = lr->lr_origid;
  436.     refer_cnt = 0;
  437.     hadref = simple_request = 0;
  438.     rc = -2;    /* default is to keep looking (no response found) */
  439.     lr->lr_res_msgtype = tag;
  440.  
  441.     /*
  442.      * This code figures out if we are going to chase a
  443.      * referral / search reference, or pass it back to the application
  444.      */
  445.     v3ref = 0;    /* Assume not a V3 search reference or referral */
  446.     if( (tag != LDAP_RES_SEARCH_ENTRY) && (ld->ld_version > LDAP_VERSION2) ) {
  447.         BerElement    tmpber = *ber;     /* struct copy */
  448.         char **refs = NULL;
  449.  
  450.         if( tag == LDAP_RES_SEARCH_REFERENCE) {
  451.             /* This is a V3 search reference */
  452.             /* Assume we do not chase the reference, but pass it to application */
  453.             v3ref = -1;
  454.             if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
  455.                     (lr->lr_parent != NULL) )
  456.             {
  457.                 /* Get the referral list */
  458.                 if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) {
  459.                     rc = LDAP_DECODING_ERROR;
  460.                 } else {
  461.                     /* Note: refs arrary is freed by ldap_chase_v3referrals */
  462.                     refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
  463.                         1, &lr->lr_res_error, &hadref );
  464.                     if ( refer_cnt > 0 ) {    /* sucessfully chased reference */
  465.                         /* If haven't got end search, set chasing referrals */
  466.                         if( lr->lr_status != LDAP_REQST_COMPLETED) {
  467.                             lr->lr_status = LDAP_REQST_CHASINGREFS;
  468.                             Debug( LDAP_DEBUG_TRACE,
  469.                                 "read1msg:  search ref chased, mark request chasing refs, id = %d\n",
  470.                                 lr->lr_msgid, 0, 0);
  471.                         }
  472.                         v3ref = 1;    /* We sucessfully chased the reference */
  473.                     }
  474.                 }
  475.             }
  476.         } else {
  477.             /* Check for V3 referral */
  478.             ber_len_t len;
  479.             if ( ber_scanf( &tmpber, "{iaa",/*}*/ &lderr,
  480.                     &lr->lr_res_matched, &lr->lr_res_error )
  481.                     != LBER_ERROR ) {
  482.                 /* Check if V3 referral */
  483.                 if( ber_peek_tag( &tmpber, &len) == LDAP_TAG_REFERRAL ) {
  484.                     /* We have a V3 referral, assume we cannot chase it */
  485.                     v3ref = -1;
  486.                     if( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS)
  487.                              || (lr->lr_parent != NULL) )
  488.                     {
  489.                         v3ref = -1;  /* Assume referral not chased and return it to app */
  490.                         /* Get the referral list */
  491.                         if( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) {
  492.                             rc = LDAP_DECODING_ERROR;
  493.                             lr->lr_status = LDAP_REQST_COMPLETED;
  494.                             Debug( LDAP_DEBUG_TRACE,
  495.                                 "read1msg: referral decode error, mark request completed, id = %d\n",
  496.                                     lr->lr_msgid, 0, 0);
  497.                         } else {
  498.                             /* Chase the referral 
  499.                              * Note: refs arrary is freed by ldap_chase_v3referrals
  500.                              */
  501.                             refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
  502.                                 0, &lr->lr_res_error, &hadref );
  503.                             lr->lr_status = LDAP_REQST_COMPLETED;
  504.                             Debug( LDAP_DEBUG_TRACE,
  505.                                 "read1msg:  referral chased, mark request completed, id = %d\n",
  506.                                 lr->lr_msgid, 0, 0);
  507.                             if( refer_cnt > 0) {
  508.                                 v3ref = 1;  /* Referral successfully chased */
  509.                             }
  510.                         }
  511.                     }
  512.                 }
  513.  
  514.                 if( lr->lr_res_matched != NULL ) {
  515.                     LDAP_FREE( lr->lr_res_matched );
  516.                     lr->lr_res_matched = NULL;
  517.                 }
  518.                 if( lr->lr_res_error != NULL ) {
  519.                     LDAP_FREE( lr->lr_res_error );
  520.                     lr->lr_res_error = NULL;
  521.                 }
  522.             }
  523.         }
  524.     }
  525.  
  526.     /* All results that just return a status, i.e. don't return data
  527.      * go through the following code.  This code also chases V2 referrals
  528.      * and checks if all referrals have been chased.
  529.      */
  530.     if ( (tag != LDAP_RES_SEARCH_ENTRY) && (v3ref > -1) ) {
  531.         /* For a v3 search referral/reference, only come here if already chased it */
  532.         if ( ld->ld_version >= LDAP_VERSION2 &&
  533.             ( lr->lr_parent != NULL ||
  534.             LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ) )
  535.         {
  536.             tmpber = *ber;    /* struct copy */
  537.             if ( v3ref == 1 ) {
  538.                 ; /* V3 search reference or V3 referral sucessfully chased */
  539.             } else if ( ber_scanf( &tmpber, "{iaa}", &lderr,
  540.                 &lr->lr_res_matched, &lr->lr_res_error )
  541.                 != LBER_ERROR ) {
  542.                 if ( lderr != LDAP_SUCCESS ) {
  543.                     /* referrals are in error string */
  544.                     refer_cnt = ldap_chase_referrals( ld, lr,
  545.                         &lr->lr_res_error, -1, &hadref );
  546.                     lr->lr_status = LDAP_REQST_COMPLETED;
  547.                     Debug( LDAP_DEBUG_TRACE,
  548.                         "read1msg:  V2 referral chased, mark request completed, id = %d\n", lr->lr_msgid, 0, 0);
  549.                 }
  550.  
  551.                 /* save errno, message, and matched string */
  552.                 if ( !hadref || lr->lr_res_error == NULL ) {
  553.                     lr->lr_res_errno = ( lderr ==
  554.                     LDAP_PARTIAL_RESULTS ) ? LDAP_SUCCESS
  555.                     : lderr;
  556.                 } else if ( ld->ld_errno != LDAP_SUCCESS ) {
  557.                     lr->lr_res_errno = ld->ld_errno;
  558.                 } else {
  559.                     lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
  560.                 }
  561. Debug( LDAP_DEBUG_TRACE,
  562.     "new result:  res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
  563.     lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
  564.     lr->lr_res_matched ? lr->lr_res_matched : "" );
  565.             }
  566.         }
  567.  
  568.         Debug( LDAP_DEBUG_TRACE,
  569.             "read1msg:  %d new referrals\n", refer_cnt, 0, 0 );
  570.  
  571.         if ( refer_cnt != 0 ) {    /* chasing referrals */
  572.             ber_free( ber, 1 );
  573.             ber = NULL;
  574.             if ( refer_cnt < 0 ) {
  575.                 return( -1 );    /* fatal error */
  576.             }
  577.             lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */
  578.         } else {
  579.             if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
  580.                 /* request without any referrals */
  581.                 simple_request = ( hadref ? 0 : 1 );
  582.             } else {
  583.                 /* request with referrals or child request */
  584.                 ber_free( ber, 1 );
  585.                 ber = NULL;
  586.             }
  587.  
  588.             lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */
  589.             Debug( LDAP_DEBUG_TRACE,
  590.                 "read1msg:  mark request completed, id = %d\n", lr->lr_msgid, 0, 0);
  591.             while ( lr->lr_parent != NULL ) {
  592.                 merge_error_info( ld, lr->lr_parent, lr );
  593.  
  594.                 lr = lr->lr_parent;
  595.                 if ( --lr->lr_outrefcnt > 0 ) {
  596.                     break;    /* not completely done yet */
  597.                 }
  598.             }
  599.  
  600.             /* Check if all requests are finished, lr is now parent */
  601.             for(tmplr=lr ; tmplr != NULL; tmplr=tmplr->lr_refnext) {
  602.                 if( tmplr->lr_status != LDAP_REQST_COMPLETED) {
  603.                     break;
  604.                 }
  605.             }
  606.  
  607.             /* This is the parent request if the request has referrals */
  608.             if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL && tmplr == NULL ) {
  609.                 id = lr->lr_msgid;
  610.                 tag = lr->lr_res_msgtype;
  611.                 Debug( LDAP_DEBUG_ANY, "request %ld done\n",
  612.                     (long) id, 0, 0 );
  613. Debug( LDAP_DEBUG_TRACE,
  614. "res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
  615. lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
  616. lr->lr_res_matched ? lr->lr_res_matched : "" );
  617.                 if ( !simple_request ) {
  618.                     ber_free( ber, 1 );
  619.                     ber = NULL;
  620.                     if ( build_result_ber( ld, &ber, lr )
  621.                         == LBER_ERROR ) {
  622.                         rc = -1; /* fatal error */
  623.                     }
  624.                 }
  625.  
  626.                 ldap_free_request( ld, lr );
  627.             }
  628.  
  629.             if ( lc != NULL ) {
  630.                 ldap_free_connection( ld, lc, 0, 1 );
  631.             }
  632.         }
  633.     }
  634.  
  635.     if ( ber == NULL ) {
  636.         return( rc );
  637.     }
  638.  
  639.     /* make a new ldap message */
  640.     if ( (new = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) ))
  641.         == NULL ) {
  642.         ld->ld_errno = LDAP_NO_MEMORY;
  643.         return( -1 );
  644.     }
  645.     new->lm_msgid = (int)id;
  646.     new->lm_msgtype = tag;
  647.     new->lm_ber = ber;
  648.  
  649. #ifndef LDAP_NOCACHE
  650.         if ( ld->ld_cache != NULL ) {
  651.             ldap_add_result_to_cache( ld, new );
  652.         }
  653. #endif /* LDAP_NOCACHE */
  654.  
  655.     /* is this the one we're looking for? */
  656.     if ( msgid == LDAP_RES_ANY || id == msgid ) {
  657.         if ( all == LDAP_MSG_ONE
  658.             || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
  659.             && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY
  660.             && new->lm_msgtype != LDAP_RES_SEARCH_REFERENCE) ) {
  661.             *result = new;
  662.             ld->ld_errno = LDAP_SUCCESS;
  663.             return( tag );
  664.         } else if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
  665.             foundit = 1;    /* return the chain later */
  666.         }
  667.     }
  668.  
  669.     /* 
  670.      * if not, we must add it to the list of responses.  if
  671.      * the msgid is already there, it must be part of an existing
  672.      * search response.
  673.      */
  674.  
  675.     prev = NULL;
  676.     for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
  677.         if ( l->lm_msgid == new->lm_msgid )
  678.             break;
  679.         prev = l;
  680.     }
  681.  
  682.     /* not part of an existing search response */
  683.     if ( l == NULL ) {
  684.         if ( foundit ) {
  685.             *result = new;
  686.             ld->ld_errno = LDAP_SUCCESS;
  687.             return( tag );
  688.         }
  689.  
  690.         new->lm_next = ld->ld_responses;
  691.         ld->ld_responses = new;
  692.         return( -2 );    /* continue looking */
  693.     }
  694.  
  695.     Debug( LDAP_DEBUG_TRACE, "adding response id %ld type %ld:\n",
  696.         (long) new->lm_msgid, (long) new->lm_msgtype, 0 );
  697.  
  698.     /* part of a search response - add to end of list of entries */
  699.     for ( tmp = l; (tmp->lm_chain != NULL) &&
  700.             ((tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY) ||
  701.              (tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE) ||
  702.              (tmp->lm_chain->lm_msgtype == LDAP_RES_EXTENDED_PARTIAL ));
  703.         tmp = tmp->lm_chain )
  704.         ;    /* NULL */
  705.     tmp->lm_chain = new;
  706.  
  707.     /* return the whole chain if that's what we were looking for */
  708.     if ( foundit ) {
  709.         if ( prev == NULL )
  710.             ld->ld_responses = l->lm_next;
  711.         else
  712.             prev->lm_next = l->lm_next;
  713.         *result = l;
  714.         ld->ld_errno = LDAP_SUCCESS;
  715. #ifdef LDAP_WORLD_P16
  716.         /*
  717.          * XXX questionable fix; see text for [P16] on
  718.          * http://www.critical-angle.com/ldapworld/patch/
  719.          *
  720.          * inclusion of this patch causes searchs to hang on
  721.          * multiple platforms
  722.          */
  723.         return( l->lm_msgtype );
  724. #else    /* LDAP_WORLD_P16 */
  725.         return( tag );
  726. #endif    /* !LDAP_WORLD_P16 */
  727.     }
  728.  
  729.     return( -2 );    /* continue looking */
  730. }
  731.  
  732.  
  733. static ber_tag_t
  734. build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
  735. {
  736.     ber_len_t    len;
  737.     ber_int_t    tag;
  738.     ber_int_t    along;
  739.     BerElement *ber;
  740.  
  741.     *bp = NULL;
  742.     ber = ldap_alloc_ber_with_options( ld );
  743.  
  744.     if( ber == NULL ) {
  745.         ld->ld_errno = LDAP_NO_MEMORY;
  746.         return LBER_ERROR;
  747.     }
  748.  
  749.     if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
  750.         lr->lr_res_msgtype, lr->lr_res_errno,
  751.         lr->lr_res_matched ? lr->lr_res_matched : "",
  752.         lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) {
  753.  
  754.         ld->ld_errno = LDAP_ENCODING_ERROR;
  755.         ber_free(ber, 1);
  756.         return( LBER_ERROR );
  757.     }
  758.  
  759.     ber_reset( ber, 1 );
  760.  
  761.     if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
  762.         ld->ld_errno = LDAP_DECODING_ERROR;
  763.         ber_free(ber, 1);
  764.         return( LBER_ERROR );
  765.     }
  766.  
  767.     if ( ber_get_int( ber, &along ) == LBER_ERROR ) {
  768.         ld->ld_errno = LDAP_DECODING_ERROR;
  769.         ber_free(ber, 1);
  770.         return( LBER_ERROR );
  771.     }
  772.  
  773.     tag = ber_peek_tag( ber, &len );
  774.  
  775.     if ( tag == LBER_ERROR ) {
  776.         ld->ld_errno = LDAP_DECODING_ERROR;
  777.         ber_free(ber, 1);
  778.         return( LBER_ERROR );
  779.     }
  780.  
  781.     *bp = ber;
  782.     return tag;
  783. }
  784.  
  785.  
  786. static void
  787. merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
  788. {
  789. /*
  790.  * Merge error information in "lr" with "parentr" error code and string.
  791.  */
  792.     if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
  793.         parentr->lr_res_errno = lr->lr_res_errno;
  794.         if ( lr->lr_res_error != NULL ) {
  795.             (void)ldap_append_referral( ld, &parentr->lr_res_error,
  796.                 lr->lr_res_error );
  797.         }
  798.     } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
  799.         parentr->lr_res_errno == LDAP_SUCCESS ) {
  800.         parentr->lr_res_errno = lr->lr_res_errno;
  801.         if ( parentr->lr_res_error != NULL ) {
  802.             LDAP_FREE( parentr->lr_res_error );
  803.         }
  804.         parentr->lr_res_error = lr->lr_res_error;
  805.         lr->lr_res_error = NULL;
  806.         if ( LDAP_NAME_ERROR( lr->lr_res_errno )) {
  807.             if ( parentr->lr_res_matched != NULL ) {
  808.                 LDAP_FREE( parentr->lr_res_matched );
  809.             }
  810.             parentr->lr_res_matched = lr->lr_res_matched;
  811.             lr->lr_res_matched = NULL;
  812.         }
  813.     }
  814.  
  815.     Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
  816.         parentr->lr_msgid, 0, 0 );
  817.     Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n",
  818.         parentr->lr_res_errno, parentr->lr_res_error ?
  819.         parentr->lr_res_error : "", parentr->lr_res_matched ?
  820.         parentr->lr_res_matched : "" );
  821. }
  822.  
  823.  
  824.  
  825. int
  826. ldap_msgtype( LDAPMessage *lm )
  827. {
  828.     assert( lm != NULL );
  829.     return ( lm != NULL ) ? lm->lm_msgtype : -1;
  830. }
  831.  
  832.  
  833. int
  834. ldap_msgid( LDAPMessage *lm )
  835. {
  836.     assert( lm != NULL );
  837.  
  838.     return ( lm != NULL ) ? lm->lm_msgid : -1;
  839. }
  840.  
  841.  
  842. char * ldap_int_msgtype2str( ber_tag_t tag )
  843. {
  844.     switch( tag ) {
  845.     case LDAP_RES_ADD: return "add";
  846.     case LDAP_RES_BIND: return "bind";
  847.     case LDAP_RES_COMPARE: return "compare";
  848.     case LDAP_RES_DELETE: return "delete";
  849.     case LDAP_RES_EXTENDED: return "extended-result";
  850.     case LDAP_RES_EXTENDED_PARTIAL: return "extended-partial";
  851.     case LDAP_RES_MODIFY: return "modify";
  852.     case LDAP_RES_RENAME: return "rename";
  853.     case LDAP_RES_SEARCH_ENTRY: return "search-entry";
  854.     case LDAP_RES_SEARCH_REFERENCE: return "search-reference";
  855.     case LDAP_RES_SEARCH_RESULT: return "search-result";
  856.     }
  857.     return "unknown";
  858. }
  859.  
  860. int
  861. ldap_msgfree( LDAPMessage *lm )
  862. {
  863.     LDAPMessage    *next;
  864.     int        type = 0;
  865.  
  866.     Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
  867.  
  868.     for ( ; lm != NULL; lm = next ) {
  869.         next = lm->lm_chain;
  870.         type = lm->lm_msgtype;
  871.         ber_free( lm->lm_ber, 1 );
  872.         LDAP_FREE( (char *) lm );
  873.     }
  874.  
  875.     return( type );
  876. }
  877.  
  878. /*
  879.  * ldap_msgdelete - delete a message.  It returns:
  880.  *    0    if the entire message was deleted
  881.  *    -1    if the message was not found, or only part of it was found
  882.  */
  883. int
  884. ldap_msgdelete( LDAP *ld, int msgid )
  885. {
  886.     LDAPMessage    *lm, *prev;
  887.  
  888.     assert( ld != NULL );
  889.  
  890.     Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
  891.  
  892.     prev = NULL;
  893.     for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) {
  894.         if ( lm->lm_msgid == msgid )
  895.             break;
  896.         prev = lm;
  897.     }
  898.  
  899.     if ( lm == NULL )
  900.         return( -1 );
  901.  
  902.     if ( prev == NULL )
  903.         ld->ld_responses = lm->lm_next;
  904.     else
  905.         prev->lm_next = lm->lm_next;
  906.  
  907.     if ( ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY )
  908.         return( -1 );
  909.  
  910.     return( 0 );
  911. }
  912.  
  913.  
  914. /*
  915.  * return 1 if message msgid is waiting to be abandoned, 0 otherwise
  916.  */
  917. static int
  918. ldap_abandoned( LDAP *ld, ber_int_t msgid )
  919. {
  920.     int    i;
  921.  
  922.     if ( ld->ld_abandoned == NULL )
  923.         return( 0 );
  924.  
  925.     for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
  926.         if ( ld->ld_abandoned[i] == msgid )
  927.             return( 1 );
  928.  
  929.     return( 0 );
  930. }
  931.  
  932.  
  933. static int
  934. ldap_mark_abandoned( LDAP *ld, ber_int_t msgid )
  935. {
  936.     int    i;
  937.  
  938.     if ( ld->ld_abandoned == NULL )
  939.         return( -1 );
  940.  
  941.     for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
  942.         if ( ld->ld_abandoned[i] == msgid )
  943.             break;
  944.  
  945.     if ( ld->ld_abandoned[i] == -1 )
  946.         return( -1 );
  947.  
  948.     for ( ; ld->ld_abandoned[i] != -1; i++ ) {
  949.         ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
  950.     }
  951.  
  952.     return( 0 );
  953. }
  954.