source:
trunk/server/common/patches/389-sasl-io-4-bytes.patch
@
1724
Last change on this file since 1724 was 1706, checked in by geofft, 14 years ago | |
---|---|
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 210 210 size_t saslio_limit; 211 211 sasl_io_private *sp = sasl_get_io_private(fd); 212 212 Connection *c = sp->conn; 213 PRInt32 amount = sizeof(buffer); 213 214 214 215 *err = 0; 215 216 debug_print_layers(fd); 217 amount -= sp->encrypted_buffer_offset; 216 218 /* 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); 218 220 LDAPDebug( LDAP_DEBUG_CONNS, 219 221 "read sasl packet length returned %d on connection %" NSPRIu64 "\n", ret, c->c_connid, 0 ); 220 222 if (ret <= 0) { … … sasl_io_start_packet(PRFileDesc *fd, PRIntn flags, PRIntervalTime timeout, PRInt 229 231 return ret; 230 232 } 231 233 /* 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. 238 237 */ 239 238 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); 244 256 } 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); 253 262 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, 259 272 "SASL encrypted packet length exceeds maximum allowed limit (length=%ld, limit=%ld)." 260 273 " 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; 273 278 } 274 279 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 275 285 return 1; 276 286 } 277 287 … … sasl_io_recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags, 345 355 if (!sasl_io_finished_packet(sp)) { 346 356 LDAPDebug( LDAP_DEBUG_CONNS, 347 357 "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); 349 364 return PR_FAILURE; 350 365 } 351 366 /* We have the full encrypted buffer now - decrypt it */ … … sasl_io_recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags, 356 371 "sasl_io_recv finished reading packet for connection %" NSPRIu64 "\n", c->c_connid ); 357 372 /* Now decode it */ 358 373 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; 359 377 if (SASL_OK == ret) { 360 378 LDAPDebug2Args( LDAP_DEBUG_CONNS, 361 379 "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, 364 382 memcpy(sp->decrypted_buffer,output_buffer,output_length); 365 383 sp->decrypted_buffer_count = output_length; 366 384 sp->decrypted_buffer_offset = 0; 367 sp->encrypted_buffer_offset = 0;368 sp->encrypted_buffer_count = 0;369 385 bytes_in_buffer = output_length; 370 386 } 371 387 } else { … … sasl_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, 461 477 (sp->send_size - sp->send_offset) ); 462 478 sp->send_offset += ret; 463 479 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); 465 486 } 466 487 /* else - ret is error - caller will handle */ 467 488 } else {
Note: See TracBrowser
for help on using the repository browser.