mirror of https://github.com/wolfSSL/wolfssh.git
Add a state, with buffer, for the receiving of SFTP init message, so that partial read don't cause issues. Activated for the server only at the moment.
parent
87caf4ad04
commit
975b145a0c
|
@ -63,6 +63,7 @@ enum WS_SFTP_STATE_ID {
|
||||||
STATE_ID_RECV = 0x10000,
|
STATE_ID_RECV = 0x10000,
|
||||||
STATE_ID_CHMOD = 0x20000,
|
STATE_ID_CHMOD = 0x20000,
|
||||||
STATE_ID_SETATR = 0x40000,
|
STATE_ID_SETATR = 0x40000,
|
||||||
|
STATE_ID_RECV_INIT = 0x80000,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum WS_SFTP_CHMOD_STATE_ID {
|
enum WS_SFTP_CHMOD_STATE_ID {
|
||||||
|
@ -239,6 +240,11 @@ typedef struct WS_SFTP_LS_STATE {
|
||||||
} WS_SFTP_LS_STATE;
|
} WS_SFTP_LS_STATE;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct WS_SFTP_RECV_INIT_STATE {
|
||||||
|
WS_SFTP_BUFFER buffer;
|
||||||
|
word32 extSz;
|
||||||
|
} WS_SFTP_RECV_INIT_STATE;
|
||||||
|
|
||||||
enum WS_SFTP_GET_STATE_ID {
|
enum WS_SFTP_GET_STATE_ID {
|
||||||
STATE_GET_INIT,
|
STATE_GET_INIT,
|
||||||
STATE_GET_LSTAT,
|
STATE_GET_LSTAT,
|
||||||
|
@ -762,6 +768,14 @@ static void wolfSSH_SFTP_ClearState(WOLFSSH* ssh, enum WS_SFTP_STATE_ID state)
|
||||||
ssh->setatrState = NULL;
|
ssh->setatrState = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state & STATE_ID_RECV_INIT) {
|
||||||
|
if (ssh->recvInitState) {
|
||||||
|
wolfSSH_SFTP_buffer_free(ssh, &ssh->recvInitState->buffer);
|
||||||
|
WFREE(ssh->recvInitState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
|
||||||
|
ssh->recvInitState = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,31 +1001,55 @@ static int SFTP_GetAttributes_Handle(WOLFSSH* ssh, byte* handle, int handleSz,
|
||||||
* returns WS_SUCCESS on success
|
* returns WS_SUCCESS on success
|
||||||
*/
|
*/
|
||||||
static int SFTP_ServerRecvInit(WOLFSSH* ssh) {
|
static int SFTP_ServerRecvInit(WOLFSSH* ssh) {
|
||||||
int len;
|
enum {
|
||||||
|
RECV_INIT_SIZE = LENGTH_SZ + MSG_ID_SZ + UINT32_SZ
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret;
|
||||||
byte id;
|
byte id;
|
||||||
word32 sz = 0;
|
word32 sz = 0;
|
||||||
word32 version = 0;
|
word32 version = 0;
|
||||||
byte buf[LENGTH_SZ + MSG_ID_SZ + UINT32_SZ];
|
WS_SFTP_RECV_INIT_STATE *state;
|
||||||
|
|
||||||
if ((len = wolfSSH_stream_read(ssh, buf, sizeof(buf))) != sizeof(buf)) {
|
state = ssh->recvInitState;
|
||||||
return len;
|
if (state == NULL) {
|
||||||
|
state = (WS_SFTP_RECV_INIT_STATE*)WMALLOC(sizeof(WS_SFTP_RECV_INIT_STATE),
|
||||||
|
ssh->ctx->heap, DYNTYPE_SFTP_STATE);
|
||||||
|
if (state == NULL) {
|
||||||
|
ssh->error = WS_MEMORY_E;
|
||||||
|
return WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
WMEMSET(state, 0, sizeof(WS_SFTP_RECV_INIT_STATE));
|
||||||
|
ssh->recvInitState = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SFTP_GetSz(buf, &sz,
|
switch (ssh->sftpState) {
|
||||||
|
case SFTP_BEGIN:
|
||||||
|
ret = wolfSSH_SFTP_buffer_read(ssh, &state->buffer, RECV_INIT_SIZE);
|
||||||
|
if (ret < 0) {
|
||||||
|
return WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < WOLFSSH_SFTP_HEADER) {
|
||||||
|
WLOG(WS_LOG_SFTP, "Unable to read SFTP INIT message");
|
||||||
|
return WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SFTP_GetSz(state->buffer.data, &sz,
|
||||||
MSG_ID_SZ + UINT32_SZ, WOLFSSH_MAX_SFTP_RECV) != WS_SUCCESS) {
|
MSG_ID_SZ + UINT32_SZ, WOLFSSH_MAX_SFTP_RECV) != WS_SUCCESS) {
|
||||||
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
|
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
|
||||||
return WS_BUFFER_E;
|
return WS_BUFFER_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compare versions supported */
|
/* compare versions supported */
|
||||||
id = buf[LENGTH_SZ];
|
id = state->buffer.data[LENGTH_SZ];
|
||||||
if (id != WOLFSSH_FTP_INIT) {
|
if (id != WOLFSSH_FTP_INIT) {
|
||||||
WLOG(WS_LOG_SFTP, "Unexpected SFTP type received");
|
WLOG(WS_LOG_SFTP, "Unexpected SFTP type received");
|
||||||
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
|
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
|
||||||
return WS_BUFFER_E;
|
return WS_BUFFER_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
ato32(buf + LENGTH_SZ + MSG_ID_SZ, &version);
|
ato32(state->buffer.data + LENGTH_SZ + MSG_ID_SZ, &version);
|
||||||
/* versions greater than WOLFSSH_SFTP_VERSION should fall back to ours
|
/* versions greater than WOLFSSH_SFTP_VERSION should fall back to ours
|
||||||
* versions less than WOLFSSH_SFTP_VERSION we should bail out on or
|
* versions less than WOLFSSH_SFTP_VERSION we should bail out on or
|
||||||
* implement a fall back */
|
* implement a fall back */
|
||||||
|
@ -1021,15 +1059,27 @@ static int SFTP_ServerRecvInit(WOLFSSH* ssh) {
|
||||||
return WS_VERSION_E;
|
return WS_VERSION_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wolfSSH_SFTP_buffer_free(ssh, &state->buffer);
|
||||||
|
|
||||||
|
state->extSz = sz - MSG_ID_SZ - UINT32_SZ;
|
||||||
|
ssh->sftpState = SFTP_EXT;
|
||||||
|
NO_BREAK;
|
||||||
|
|
||||||
|
case SFTP_EXT:
|
||||||
/* silently ignore extensions if not supported */
|
/* silently ignore extensions if not supported */
|
||||||
sz = sz - MSG_ID_SZ - UINT32_SZ;
|
if (state->extSz > 0) {
|
||||||
if (sz > 0) {
|
ret = wolfSSH_SFTP_buffer_read(ssh, &state->buffer, (int)state->extSz);
|
||||||
byte* data = (byte*)WMALLOC(sz, NULL, DYNTYPE_BUFFER);
|
if (ret < 0) {
|
||||||
if (data == NULL) return WS_MEMORY_E;
|
return WS_FATAL_ERROR;
|
||||||
len = wolfSSH_stream_read(ssh, data, sz);
|
}
|
||||||
WFREE(data, NULL, DYNTYPE_BUFFER);
|
|
||||||
if (len != (int)sz)
|
if (ret < (int)state->extSz) {
|
||||||
return len;
|
WLOG(WS_LOG_SFTP, "Unable to read SFTP INIT extensions");
|
||||||
|
return WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
wolfSSH_SFTP_buffer_free(ssh, &state->buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh->reqId++;
|
ssh->reqId++;
|
||||||
|
@ -1063,7 +1113,7 @@ static int SFTP_ServerSendInit(WOLFSSH* ssh) {
|
||||||
*/
|
*/
|
||||||
int wolfSSH_SFTP_accept(WOLFSSH* ssh)
|
int wolfSSH_SFTP_accept(WOLFSSH* ssh)
|
||||||
{
|
{
|
||||||
int ret = WS_SFTP_COMPLETE;
|
int ret = WS_FATAL_ERROR;
|
||||||
|
|
||||||
if (ssh == NULL) {
|
if (ssh == NULL) {
|
||||||
return WS_BAD_ARGUMENT;
|
return WS_BAD_ARGUMENT;
|
||||||
|
@ -1090,18 +1140,25 @@ int wolfSSH_SFTP_accept(WOLFSSH* ssh)
|
||||||
|
|
||||||
switch (ssh->sftpState) {
|
switch (ssh->sftpState) {
|
||||||
case SFTP_BEGIN:
|
case SFTP_BEGIN:
|
||||||
if (SFTP_ServerRecvInit(ssh) != WS_SUCCESS) {
|
case SFTP_EXT:
|
||||||
return WS_FATAL_ERROR;
|
ret = SFTP_ServerRecvInit(ssh);
|
||||||
|
if (ret != WS_SUCCESS) {
|
||||||
|
if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE)
|
||||||
|
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
ssh->sftpState = SFTP_RECV;
|
ssh->sftpState = SFTP_RECV;
|
||||||
NO_BREAK;
|
NO_BREAK;
|
||||||
|
|
||||||
case SFTP_RECV:
|
case SFTP_RECV:
|
||||||
if (SFTP_ServerSendInit(ssh) != WS_SUCCESS) {
|
ret = SFTP_ServerSendInit(ssh);
|
||||||
return WS_FATAL_ERROR;
|
if (ret != WS_SUCCESS) {
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
ssh->sftpState = SFTP_DONE;
|
ssh->sftpState = SFTP_DONE;
|
||||||
WLOG(WS_LOG_SFTP, "SFTP connection established");
|
WLOG(WS_LOG_SFTP, "SFTP connection established");
|
||||||
|
wolfSSH_SFTP_ClearState(ssh, STATE_ID_RECV_INIT);
|
||||||
|
ret = WS_SFTP_COMPLETE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -578,6 +578,7 @@ typedef struct SFTP_OFST {
|
||||||
char to[WOLFSSH_MAX_FILENAME];
|
char to[WOLFSSH_MAX_FILENAME];
|
||||||
} SFTP_OFST;
|
} SFTP_OFST;
|
||||||
|
|
||||||
|
struct WS_SFTP_RECV_INIT_STATE;
|
||||||
struct WS_SFTP_GET_STATE;
|
struct WS_SFTP_GET_STATE;
|
||||||
struct WS_SFTP_PUT_STATE;
|
struct WS_SFTP_PUT_STATE;
|
||||||
struct WS_SFTP_LSTAT_STATE;
|
struct WS_SFTP_LSTAT_STATE;
|
||||||
|
@ -754,6 +755,7 @@ struct WOLFSSH {
|
||||||
#ifdef WOLFSSH_STOREHANDLE
|
#ifdef WOLFSSH_STOREHANDLE
|
||||||
WS_HANDLE_LIST* handleList;
|
WS_HANDLE_LIST* handleList;
|
||||||
#endif
|
#endif
|
||||||
|
struct WS_SFTP_RECV_INIT_STATE* recvInitState;
|
||||||
struct WS_SFTP_RECV_STATE* recvState;
|
struct WS_SFTP_RECV_STATE* recvState;
|
||||||
struct WS_SFTP_RMDIR_STATE* rmdirState;
|
struct WS_SFTP_RMDIR_STATE* rmdirState;
|
||||||
struct WS_SFTP_MKDIR_STATE* mkdirState;
|
struct WS_SFTP_MKDIR_STATE* mkdirState;
|
||||||
|
|
Loading…
Reference in New Issue