source: trunk/server/common/patches/389-sasl-io-4-bytes.patch @ 1739

Last change on this file since 1739 was 1706, checked in by geofft, 13 years ago
Backport harder
File size: 8.3 KB
  • ldap/servers/slapd/sasl_io.c

    commit 310c056b2f39c534701b1ee1d1ec4755d4192f70
    Author: Noriko Hosoi <nhosoi@redhat.com>
    Date:   Mon Oct 11 16:39:54 2010 -0700
    
        Bug 637852 - sasl_io_start_packet: failed - read only 3 bytes
        of sasl packet length on connection 4
        
        https://bugzilla.redhat.com/show_bug.cgi?id=637852
        
        Description: A SASL packet is made from the 4 byte length and
        the length size of payload.  When the first 4 bytes were not
        successfully received by one PR_Recv call, sasl_io_start_packet
        in sasl_io.c considered an error occurred and set PR_IO_ERROR,
        which terminates the SASL IO session.
        To give clients a chance to send the rest of the length in the
        next packet, this patch sets PR_WOULD_BLOCK_ERROR to the nspr
        error code and EWOULDBLOCK/EAGAIN to errno and once the succeeding
        packet comes in, it appends it to the previous incomplete length
        data and continues the SASL IO.
    
    diff --git a/ldap/servers/slapd/sasl_io.c b/ldap/servers/slapd/sasl_io.c
    index 4bf81cc..52d6506 100644
    a b sasl_io_start_packet(PRFileDesc *fd, PRIntn flags, PRIntervalTime timeout, PRInt 
    210210    size_t saslio_limit;
    211211    sasl_io_private *sp = sasl_get_io_private(fd);
    212212    Connection *c = sp->conn;
     213    PRInt32 amount = sizeof(buffer);
    213214
    214215    *err = 0;
    215216    debug_print_layers(fd);
     217    amount -= sp->encrypted_buffer_offset;
    216218    /* first we need the length bytes */
    217     ret = PR_Recv(fd->lower, buffer, sizeof(buffer), flags, timeout);
     219    ret = PR_Recv(fd->lower, buffer, amount, flags, timeout);
    218220    LDAPDebug( LDAP_DEBUG_CONNS,
    219221               "read sasl packet length returned %d on connection %" NSPRIu64 "\n", ret, c->c_connid, 0 );
    220222    if (ret <= 0) {
    sasl_io_start_packet(PRFileDesc *fd, PRIntn flags, PRIntervalTime timeout, PRInt 
    229231        return ret;
    230232    }
    231233    /*
    232      * NOTE: A better way to do this would be to read the bytes and add them to
    233      * sp->encrypted_buffer - if offset < 4, tell caller we didn't read enough
    234      * bytes yet - if offset >= 4, decode the length and proceed.  However, it
    235      * is highly unlikely that a request to read 4 bytes will return < 4 bytes,
    236      * perhaps only in error conditions, in which case the ret < 0 case above
    237      * will run
     234     * Read the bytes and add them to sp->encrypted_buffer
     235     * - if offset < 4, tell caller we didn't read enough bytes yet
     236     * - if offset >= 4, decode the length and proceed.
    238237     */
    239238    if (ret < sizeof(buffer)) {
    240         LDAPDebug( LDAP_DEBUG_ANY,
    241                    "sasl_io_start_packet: failed - read only %d bytes of sasl packet length on connection %" NSPRIu64 "\n", ret, c->c_connid, 0 );
    242             PR_SetError(PR_IO_ERROR, 0);
    243             return -1;       
     239        memcpy(sp->encrypted_buffer + sp->encrypted_buffer_offset, buffer, ret);
     240        sp->encrypted_buffer_offset += ret;
     241        if (sp->encrypted_buffer_offset < sizeof(buffer)) {
     242            LDAPDebug2Args( LDAP_DEBUG_CONNS,
     243                   "sasl_io_start_packet: read only %d bytes of sasl packet "
     244                   "length on connection %" NSPRIu64 "\n", ret, c->c_connid );
     245#if defined(EWOULDBLOCK)
     246            errno = EWOULDBLOCK;
     247#elif defined(EAGAIN)
     248            errno = EAGAIN;
     249#endif
     250            PR_SetError(PR_WOULD_BLOCK_ERROR, errno);
     251            return PR_FAILURE;
     252        }
     253    } else {
     254        memcpy(sp->encrypted_buffer, buffer, sizeof(buffer));
     255        sp->encrypted_buffer_offset = sizeof(buffer);
    244256    }
    245     if (ret == sizeof(buffer)) {
    246         /* Decode the length (could use ntohl here ??) */
    247         packet_length = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
    248         /* add length itself (for Cyrus SASL library) */
    249         packet_length += 4;
    250 
    251         LDAPDebug( LDAP_DEBUG_CONNS,
    252                    "read sasl packet length %ld on connection %" NSPRIu64 "\n", packet_length, c->c_connid, 0 );
     257    /* At this point, sp->encrypted_buffer_offset == sizeof(buffer) */
     258    /* Decode the length */
     259    packet_length = ntohl(*(uint32_t *)sp->encrypted_buffer);
     260    /* add length itself (for Cyrus SASL library) */
     261    packet_length += sizeof(uint32_t);
    253262
    254         /* Check if the packet length is larger than our max allowed.  A
    255          * setting of -1 means that we allow any size SASL IO packet. */
    256         saslio_limit = config_get_maxsasliosize();
    257         if(((long)saslio_limit != -1) && (packet_length > saslio_limit)) {
    258             LDAPDebug( LDAP_DEBUG_ANY,
     263    LDAPDebug2Args( LDAP_DEBUG_CONNS,
     264                    "read sasl packet length %ld on connection %" NSPRIu64 "\n",
     265                    packet_length, c->c_connid );
     266
     267    /* Check if the packet length is larger than our max allowed.  A
     268     * setting of -1 means that we allow any size SASL IO packet. */
     269    saslio_limit = config_get_maxsasliosize();
     270    if(((long)saslio_limit != -1) && (packet_length > saslio_limit)) {
     271        LDAPDebug2Args( LDAP_DEBUG_ANY,
    259272                "SASL encrypted packet length exceeds maximum allowed limit (length=%ld, limit=%ld)."
    260273                "  Change the nsslapd-maxsasliosize attribute in cn=config to increase limit.\n",
    261                  packet_length, config_get_maxsasliosize(), 0);
    262             PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
    263             *err = PR_BUFFER_OVERFLOW_ERROR;
    264             return -1;
    265         }
    266 
    267         sasl_io_resize_encrypted_buffer(sp, packet_length);
    268         /* Cyrus SASL implementation expects to have the length at the first
    269            4 bytes */
    270         memcpy(sp->encrypted_buffer, buffer, 4);
    271         sp->encrypted_buffer_count = packet_length;
    272         sp->encrypted_buffer_offset = 4;
     274                 packet_length, config_get_maxsasliosize() );
     275        PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
     276        *err = PR_BUFFER_OVERFLOW_ERROR;
     277        return -1;
    273278    }
    274279
     280    sasl_io_resize_encrypted_buffer(sp, packet_length);
     281    /* Cyrus SASL implementation expects to have the length at the first
     282       4 bytes */
     283    sp->encrypted_buffer_count = packet_length;
     284
    275285    return 1;
    276286}
    277287
    sasl_io_recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags, 
    345355        if (!sasl_io_finished_packet(sp)) {
    346356            LDAPDebug( LDAP_DEBUG_CONNS,
    347357                       "sasl_io_recv for connection %" NSPRIu64 " - not finished reading packet yet\n", c->c_connid, 0, 0 );
    348             PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
     358#if defined(EWOULDBLOCK)
     359            errno = EWOULDBLOCK;
     360#elif defined(EAGAIN)
     361            errno = EAGAIN;
     362#endif
     363            PR_SetError(PR_WOULD_BLOCK_ERROR, errno);
    349364            return PR_FAILURE;
    350365        }
    351366        /* We have the full encrypted buffer now - decrypt it */
    sasl_io_recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags, 
    356371                       "sasl_io_recv finished reading packet for connection %" NSPRIu64 "\n", c->c_connid );
    357372            /* Now decode it */
    358373            ret = sasl_decode(c->c_sasl_conn,sp->encrypted_buffer,sp->encrypted_buffer_count,&output_buffer,&output_length);
     374            /* even if decode fails, need re-initialize the encrypted_buffer */
     375            sp->encrypted_buffer_offset = 0;
     376            sp->encrypted_buffer_count = 0;
    359377            if (SASL_OK == ret) {
    360378                LDAPDebug2Args( LDAP_DEBUG_CONNS,
    361379                           "sasl_io_recv decoded packet length %d for connection %" NSPRIu64 "\n", output_length, c->c_connid );
    sasl_io_recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags, 
    364382                    memcpy(sp->decrypted_buffer,output_buffer,output_length);
    365383                    sp->decrypted_buffer_count = output_length;
    366384                    sp->decrypted_buffer_offset = 0;
    367                     sp->encrypted_buffer_offset = 0;
    368                     sp->encrypted_buffer_count = 0;
    369385                    bytes_in_buffer = output_length;
    370386                }
    371387            } else {
    sasl_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, 
    461477                            (sp->send_size - sp->send_offset) );
    462478            sp->send_offset += ret;
    463479            ret = PR_FAILURE;
    464             PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
     480#if defined(EWOULDBLOCK)
     481            errno = EWOULDBLOCK;
     482#elif defined(EAGAIN)
     483            errno = EAGAIN;
     484#endif
     485            PR_SetError(PR_WOULD_BLOCK_ERROR, errno);
    465486        }
    466487        /* else - ret is error - caller will handle */
    467488    } else {
Note: See TracBrowser for help on using the repository browser.