[Date Prev][Date Next] [Chronological] [Thread] [Top]

ldapsearch w/ SASL sends duplicate entries (ITS#3139)



Full_Name: Mark Adamson
Version: 2.2.4
OS: Solaris and Linux
URL: 
Submission from: (NULL) (128.2.122.36)


When doing large searches to OpenLDAP with SASL encryption, I noticed that
a few entries would be returned twice in the results. Rerunning the search
would return duplicates of different entries each time; it was a random 
selection of entries that got repeated.
  I found that the slapd server is in fact sending the BER buffer twice.
Other clues and extra debugging statements led me to sb_sasl_write() in
libraries/liblber/cyrus.c.  That function flushes any old data, encrypts
the new BER packet, and sends it. If the write() lower down returns -1 the
calling functions mark the connection for a retry later and the thread yields.
  Unfortunately, when the write is retried, the encrypted packet is still in 
the sockbuf's buffer, which is flushed as old data, and the BER packet is
encrypted again and resent.

  If the write in sb_sasl_write() fails completely, the buffer has to be
cleared so that when the function is called again (to send the same BER
packet) the existing buffer is not viewed as "old data" that needs to first
be flushed to the network.  A fix that I found works is:


      ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
-     if ( ret <= 0 )
+     if ( ret <= 0 ) {
+ #if SASL_VERSION_MAJOR >= 2
+         ber_pvt_sb_buf_init( &p->buf_out );
+ #else
+         ber_pvt_sb_buf_destroy( &p->buf_out );
+ #endif
          return ret;
+      }
       return len;
  }


My only concern is if this leaks the buf_out.buf_base memory block
that was allocated in the sasl_encode(). This would be for SASL V2 only.
Another possible fix would be to set

   p->buf_out.buf_ptr = p->buf_out.buf_end 

if the "ret <= 0" so that when the function is called again, the 
"Are there anything left in the buffer?" check at the beginning of
the function will skip.