mirror of
https://github.com/moparisthebest/curl
synced 2024-11-12 04:25:08 -05:00
schannel: Added special shutdown check for Windows 2000 Professional
Windows 2000 Professional: Schannel returns SEC_E_OK instead of SEC_I_CONTEXT_EXPIRED. If the length of the output buffer is zero and the first byte of the encrypted packet is 0x15, the application can safely assume that the message was a close_notify message and change the return value to SEC_I_CONTEXT_EXPIRED. Connection shutdown does not mean that there is no data to read Correctly handle incomplete message and ask curl to re-read Fixed buffer for decrypted being to small Re-structured read condition to be more effective Removed obsolete verbose messages Changed memory reduction method to keep a minimum buffer of size 4096
This commit is contained in:
parent
ec9e9f38b1
commit
15ca80c831
@ -255,19 +255,20 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
|
|||||||
read = sread(conn->sock[sockindex],
|
read = sread(conn->sock[sockindex],
|
||||||
connssl->encdata_buffer + connssl->encdata_offset,
|
connssl->encdata_buffer + connssl->encdata_offset,
|
||||||
connssl->encdata_length - connssl->encdata_offset);
|
connssl->encdata_length - connssl->encdata_offset);
|
||||||
if(read < 0 && connssl->connecting_state != ssl_connect_2_writing) {
|
if(read > 0) {
|
||||||
|
/* increase encrypted data buffer offset */
|
||||||
|
connssl->encdata_offset += read;
|
||||||
|
}
|
||||||
|
else if(connssl->connecting_state != ssl_connect_2_writing) {
|
||||||
|
if(read < 0) {
|
||||||
connssl->connecting_state = ssl_connect_2_reading;
|
connssl->connecting_state = ssl_connect_2_reading;
|
||||||
infof(data, "schannel: failed to receive handshake, waiting for more: %d\n",
|
infof(data, "schannel: failed to receive handshake, need more data\n");
|
||||||
read);
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
else if(read == 0 && connssl->connecting_state != ssl_connect_2_writing) {
|
else if(read == 0) {
|
||||||
failf(data, "schannel: failed to receive handshake, connection failed\n");
|
failf(data, "schannel: failed to receive handshake, connection failed\n");
|
||||||
return CURLE_SSL_CONNECT_ERROR;
|
return CURLE_SSL_CONNECT_ERROR;
|
||||||
}
|
}
|
||||||
else if(read > 0) {
|
|
||||||
/* increase encrypted data buffer offset */
|
|
||||||
connssl->encdata_offset += read;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
infof(data, "schannel: encrypted data buffer %d/%d\n",
|
infof(data, "schannel: encrypted data buffer %d/%d\n",
|
||||||
@ -643,7 +644,6 @@ schannel_send(struct connectdata *conn, int sockindex,
|
|||||||
static ssize_t
|
static ssize_t
|
||||||
schannel_recv(struct connectdata *conn, int sockindex,
|
schannel_recv(struct connectdata *conn, int sockindex,
|
||||||
char *buf, size_t len, CURLcode *err) {
|
char *buf, size_t len, CURLcode *err) {
|
||||||
int i = 0;
|
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
ssize_t read = 0, ret = -1;
|
ssize_t read = 0, ret = -1;
|
||||||
CURLcode retcode;
|
CURLcode retcode;
|
||||||
@ -668,7 +668,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* increase buffers in order to fit the requested amount of data */
|
/* increase buffer in order to fit the requested amount of data */
|
||||||
while(connssl->encdata_length - connssl->encdata_offset < 2048 ||
|
while(connssl->encdata_length - connssl->encdata_offset < 2048 ||
|
||||||
connssl->encdata_length < len) {
|
connssl->encdata_length < len) {
|
||||||
/* increase internal encrypted data buffer */
|
/* increase internal encrypted data buffer */
|
||||||
@ -680,16 +680,6 @@ schannel_recv(struct connectdata *conn, int sockindex,
|
|||||||
*err = CURLE_OUT_OF_MEMORY;
|
*err = CURLE_OUT_OF_MEMORY;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* increase internal decrypted data buffer */
|
|
||||||
connssl->decdata_length += 2048;
|
|
||||||
connssl->decdata_buffer = realloc(connssl->decdata_buffer,
|
|
||||||
connssl->decdata_length);
|
|
||||||
if(connssl->decdata_buffer == NULL) {
|
|
||||||
failf(data, "schannel: unable to re-allocate memory");
|
|
||||||
*err = CURLE_OUT_OF_MEMORY;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read encrypted data from socket */
|
/* read encrypted data from socket */
|
||||||
@ -744,17 +734,38 @@ schannel_recv(struct connectdata *conn, int sockindex,
|
|||||||
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */
|
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */
|
||||||
sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
|
sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
|
||||||
&inbuf_desc, 0, NULL);
|
&inbuf_desc, 0, NULL);
|
||||||
infof(data, "schannel: DecryptMessage %d\n", sspi_status);
|
|
||||||
|
/* check if we need more data */
|
||||||
|
if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
|
||||||
|
infof(data, "schannel: failed to decrypt data, need more data\n");
|
||||||
|
*err = CURLE_AGAIN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* check if everything went fine (server may want to renegotiate context) */
|
/* check if everything went fine (server may want to renegotiate context) */
|
||||||
if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE) {
|
if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
|
||||||
|
sspi_status == SEC_I_CONTEXT_EXPIRED) {
|
||||||
/* check for successfully decrypted data */
|
/* check for successfully decrypted data */
|
||||||
if(inbuf[1].BufferType == SECBUFFER_DATA) {
|
if(inbuf[1].BufferType == SECBUFFER_DATA) {
|
||||||
infof(data, "schannel: decrypted data length: %d\n", inbuf[1].cbBuffer);
|
infof(data, "schannel: decrypted data length: %d\n", inbuf[1].cbBuffer);
|
||||||
|
|
||||||
|
/* increase buffer in order to fit the received amount of data */
|
||||||
|
size = inbuf[1].cbBuffer > 2048 ? inbuf[1].cbBuffer : 2048;
|
||||||
|
while(connssl->decdata_length - connssl->decdata_offset < size ||
|
||||||
|
connssl->decdata_length < len) {
|
||||||
|
/* increase internal decrypted data buffer */
|
||||||
|
connssl->decdata_length += size;
|
||||||
|
connssl->decdata_buffer = realloc(connssl->decdata_buffer,
|
||||||
|
connssl->decdata_length);
|
||||||
|
if(connssl->decdata_buffer == NULL) {
|
||||||
|
failf(data, "schannel: unable to re-allocate memory");
|
||||||
|
*err = CURLE_OUT_OF_MEMORY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* copy decrypted data to internal buffer */
|
/* copy decrypted data to internal buffer */
|
||||||
size = connssl->decdata_length - connssl->decdata_offset;
|
size = inbuf[1].cbBuffer;
|
||||||
size = size < inbuf[1].cbBuffer ? size : inbuf[1].cbBuffer;
|
|
||||||
if(size > 0) {
|
if(size > 0) {
|
||||||
memcpy(connssl->decdata_buffer + connssl->decdata_offset,
|
memcpy(connssl->decdata_buffer + connssl->decdata_offset,
|
||||||
inbuf[1].pvBuffer, size);
|
inbuf[1].pvBuffer, size);
|
||||||
@ -819,37 +830,34 @@ schannel_recv(struct connectdata *conn, int sockindex,
|
|||||||
|
|
||||||
/* reduce internal buffer length to reduce memory usage */
|
/* reduce internal buffer length to reduce memory usage */
|
||||||
if(connssl->encdata_length > 4096) {
|
if(connssl->encdata_length > 4096) {
|
||||||
connssl->encdata_length = connssl->encdata_offset > 0 ?
|
connssl->encdata_length = connssl->encdata_offset > 4096 ?
|
||||||
connssl->encdata_offset + 2048 : 4096;
|
connssl->encdata_offset : 4096;
|
||||||
connssl->encdata_buffer = realloc(connssl->encdata_buffer,
|
connssl->encdata_buffer = realloc(connssl->encdata_buffer,
|
||||||
connssl->encdata_length);
|
connssl->encdata_length);
|
||||||
}
|
}
|
||||||
if(connssl->decdata_length > 4096) {
|
if(connssl->decdata_length > 4096) {
|
||||||
connssl->decdata_length = connssl->decdata_offset > 0 ?
|
connssl->decdata_length = connssl->decdata_offset > 4096 ?
|
||||||
connssl->decdata_offset + 2048 : 4096;
|
connssl->decdata_offset : 4096;
|
||||||
connssl->decdata_buffer = realloc(connssl->decdata_buffer,
|
connssl->decdata_buffer = realloc(connssl->decdata_buffer,
|
||||||
connssl->decdata_length);
|
connssl->decdata_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if the server closed the connection */
|
/* check if the server closed the connection */
|
||||||
if(ret <= 0 && sspi_status == SEC_I_CONTEXT_EXPIRED) {
|
if(ret <= 0 && ( /* special check for Windows 2000 Professional */
|
||||||
|
sspi_status == SEC_I_CONTEXT_EXPIRED || (sspi_status == SEC_E_OK &&
|
||||||
|
connssl->encdata_offset > 0 && connssl->encdata_buffer[0] == 0x15))) {
|
||||||
infof(data, "schannel: server closed the connection\n");
|
infof(data, "schannel: server closed the connection\n");
|
||||||
*err = CURLE_OK;
|
*err = CURLE_OK;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if something went wrong and we need to return an error */
|
/* check if something went wrong and we need to return an error */
|
||||||
if(ret < 0) {
|
if(ret < 0 && sspi_status != SEC_E_OK) {
|
||||||
if(sspi_status == SEC_E_INCOMPLETE_MESSAGE)
|
infof(data, "schannel: failed to read data from server\n");
|
||||||
*err = CURLE_AGAIN;
|
|
||||||
else if(sspi_status != SEC_E_OK)
|
|
||||||
*err = CURLE_RECV_ERROR;
|
*err = CURLE_RECV_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* everything went fine */
|
|
||||||
infof(data, "schannel: read returns %d with error code %d\n", ret, *err);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user