From: Ondřej Kuzník Date: Thu, 26 Sep 2024 11:27:05 +0000 (+0100) Subject: ITS#10229 Adjust ldap_result behaviour with LDAP_MSG_RECEIVED X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2ba10ad59cf4b7c74d8dfe0dd4b32b8977e15080;p=thirdparty%2Fopenldap.git ITS#10229 Adjust ldap_result behaviour with LDAP_MSG_RECEIVED --- diff --git a/libraries/libldap/error.c b/libraries/libldap/error.c index 297553d1cc..bb38688721 100644 --- a/libraries/libldap/error.c +++ b/libraries/libldap/error.c @@ -261,6 +261,25 @@ ldap_parse_result( LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); /* Find the result, last msg in chain... */ lm = r->lm_chain_tail; + if ( r->lm_msgid != lm->lm_msgid ) { + /* + * ITS#10229: Returned with LDAP_MSG_ALL+LDAP_MSG_RECEIVED. People who + * do that aren't expected to call ldap_parse_result not least because + * they have no idea what the msgid of the result would be. Just do our + * best. + * + * We could also return LDAP_NO_RESULTS_RETURNED if there isn't a + * result for r's operation. + */ + lm = r; + for ( lm = r; lm; lm = lm->lm_chain ) { + if ( lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY && + lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE && + lm->lm_msgtype != LDAP_RES_INTERMEDIATE ) + break; + } + } + /* FIXME: either this is not possible (assert?) * or it should be handled */ if ( lm != NULL ) { diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index e9ac9f32b3..148f81cd8c 100644 --- a/libraries/libldap/result.c +++ b/libraries/libldap/result.c @@ -146,8 +146,32 @@ chkResponseList( "ldap_chkResponseList ld %p msgid %d all %d\n", (void *)ld, msgid, all ); + lm = ld->ld_responses; + if ( lm && msgid == LDAP_RES_ANY && all == LDAP_MSG_RECEIVED ) { + /* + * ITS#10229: asked to return all messages received so far, + * draft-ietf-ldapext-ldap-c-api which defines LDAP_MSG_RECEIVED lets + * us mix different msgids in what we return + * + * We have two choices in *how* we return the messages: + * - we link all chains together + * - we keep the chains intact and use lm_next + * + * The former will make life harder for ldap_parse_result finding a + * result message, the latter affects routines that iterate over + * messages. This take does the former. + */ + ld->ld_responses = NULL; + while ( lm->lm_next ) { + lm->lm_chain_tail->lm_chain = lm->lm_next; + lm->lm_chain_tail = lm->lm_next->lm_chain_tail; + lm->lm_next = lm->lm_next->lm_next; + } + return lm; + } + lastlm = &ld->ld_responses; - for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) { + for ( ; lm != NULL; lm = nextlm ) { nextlm = lm->lm_next; ++cnt; @@ -393,6 +417,37 @@ wait4msg( LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); } + if ( all == LDAP_MSG_RECEIVED ) { + /* + * ITS#10229: we looped over all ready connections accumulating + * messages in ld_responses, check if we have something to return + * right now. + */ + LDAPMessage **lp, *lm = ld->ld_responses; + + if ( lm && msgid == LDAP_RES_ANY ) { + *result = lm; + + ld->ld_responses = NULL; + while ( lm->lm_next ) { + lm->lm_chain_tail->lm_chain = lm->lm_next; + lm->lm_chain_tail = lm->lm_next->lm_chain_tail; + lm->lm_next = lm->lm_next->lm_next; + } + rc = lm->lm_msgtype; + break; + } + + for ( lp = &ld->ld_responses; lm; lp = &lm->lm_next, lm = *lp ) { + if ( msgid == lm->lm_msgid ) break; + } + if ( lm ) { + *lp = lm->lm_next; + *result = lm; + rc = lm->lm_msgtype; + } + } + if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) { struct timeval curr_time_tv = { 0 }, delta_time_tv = { 0 }; @@ -1102,7 +1157,10 @@ nextresp2: /* is this the one we're looking for? */ if ( msgid == LDAP_RES_ANY || id == msgid ) { - if ( all == LDAP_MSG_ONE + if ( msgid == LDAP_RES_ANY && all == LDAP_MSG_RECEIVED ) { + /* ITS#10229: We want to keep going so long as there's anything to + * read. */ + } else if ( all == LDAP_MSG_ONE || ( newmsg->lm_msgtype != LDAP_RES_SEARCH_RESULT && newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY && newmsg->lm_msgtype != LDAP_RES_INTERMEDIATE