From 68e6d8308ba4c5042cff03336f23b237442846c5 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Thu, 13 Sep 2018 09:49:29 -0600 Subject: [PATCH] add function to check for window adjustment and fix SCP file buffer offset close file on SCP write fail, and add ioctl for Nucleus window adjustment check with SFTP and handle multiple adjustment packets fix for setting return value with Nucleus ioctl --- src/ssh.c | 35 +++++++++++++++++++++++++++++++++++ src/wolfscp.c | 27 +++++++++++++++++++++------ src/wolfsftp.c | 3 ++- wolfssh/port.h | 23 +++++++++++++++++++++++ wolfssh/ssh.h | 1 + 5 files changed, 82 insertions(+), 7 deletions(-) diff --git a/src/ssh.c b/src/ssh.c index 1b4deec..cc0afd4 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1252,3 +1252,38 @@ WOLFSSH_CHANNEL* wolfSSH_ChannelNext(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel) nextChannel == NULL ? "none" : "NEXT!"); return nextChannel; } + + +/* Protocols that have loops over wolfSSH_stream_send without doing any reads + * will run into the issue of not checking for a peer window adjustment packet. + * This function allows for checking for a peer window adjustment packet without + * requiring a read buffer and call to wolfSSH_stream_read. + * + * Data that is read and is not related to packet headers is stored in the + * WOLFSSH input buffer and can be gotten with a call to wolfSSH_stream_read. If + * more data is stored then MAX_PACKET_SZ then no more window adjustment packets + * are searched for. + */ +void wolfSSH_CheckPeerWindow(WOLFSSH* ssh) +{ + int bytes = 0; + Buffer* inputBuffer; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_CheckPeerWindow()"); + + if (ssh == NULL) + return; + + inputBuffer = &ssh->channelList->inputBuffer; + WIOCTL(wolfSSH_get_fd(ssh), FIONREAD, &bytes); + while (bytes > 0) { /* there is something to read off the wire */ + if (inputBuffer->length - inputBuffer->idx > MAX_PACKET_SZ) { + WLOG(WS_LOG_DEBUG, "Application data to be read"); + break; /* too much application data! */ + } + if (DoReceive(ssh) < 0) { + WLOG(WS_LOG_ERROR, "Error trying to read potential window adjust"); + } + WIOCTL(wolfSSH_get_fd(ssh), FIONREAD, &bytes); + } +} diff --git a/src/wolfscp.c b/src/wolfscp.c index 9b0b0b0..67d78e1 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -383,7 +383,8 @@ int DoScpSource(WOLFSSH* ssh) WOLFSSH_SCP_NEW_REQUEST, NULL, NULL, 0, NULL, NULL, NULL, 0, NULL, NULL, 0, wolfSSH_GetScpSendCtx(ssh)); - if (ssh->scpConfirm == WS_SCP_ABORT) { + if (ssh->scpConfirm == WS_SCP_ABORT || + ssh->scpConfirm == WS_EOF) { ssh->scpState = SCP_RECEIVE_CONFIRMATION_WITH_RECEIPT; ssh->scpNextState = SCP_DONE; } else { @@ -456,7 +457,8 @@ int DoScpSource(WOLFSSH* ssh) ssh->scpFileName, ssh->scpFileNameSz, &(ssh->scpMTime), &(ssh->scpATime), &(ssh->scpFileMode), ssh->scpFileOffset, &(ssh->scpFileSz), - ssh->scpFileBuffer, ssh->scpFileBufferSz, + ssh->scpFileBuffer + ssh->scpBufferedSz, + ssh->scpFileBufferSz - ssh->scpBufferedSz, wolfSSH_GetScpSendCtx(ssh)); if (ssh->scpConfirm == WS_SCP_ENTER_DIR) { @@ -483,7 +485,7 @@ int DoScpSource(WOLFSSH* ssh) } else if (ssh->scpConfirm >= 0) { /* transfer buffered file data */ - ssh->scpBufferedSz = ssh->scpConfirm; + ssh->scpBufferedSz += ssh->scpConfirm; ssh->scpConfirm = WS_SCP_CONTINUE; /* only send timestamp and file header first time */ @@ -572,15 +574,20 @@ int DoScpSource(WOLFSSH* ssh) ret = wolfSSH_stream_send(ssh, ssh->scpFileBuffer, ssh->scpBufferedSz); + wolfSSH_CheckPeerWindow(ssh); /*check for adjust window packet*/ if (ret < 0) { WLOG(WS_LOG_ERROR, scpError, "failed to send file", ret); break; } ssh->scpFileOffset += ret; - ssh->scpBufferedSz = 0; + if (ret != (int)ssh->scpBufferedSz) { + /* case where not all of buffer was sent */ + WMEMMOVE(ssh->scpFileBuffer, ssh->scpFileBuffer + ret, + ssh->scpBufferedSz - ret); + } + ssh->scpBufferedSz -= ret; ret = WS_SUCCESS; - if (ssh->scpFileOffset < ssh->scpFileSz) { ssh->scpState = SCP_TRANSFER; ssh->scpRequestType = WOLFSSH_SCP_CONTINUE_FILE_TRANSFER; @@ -1352,7 +1359,6 @@ int SendScpConfirmation(WOLFSSH* ssh) /* skip first byte for accurate strlen, may be 0 */ msgSz = (int)XSTRLEN(msg + 1) + 1; ret = wolfSSH_stream_send(ssh, (byte*)msg, msgSz); - if (ret != msgSz || ssh->scpConfirm == WS_SCP_ABORT) { ret = WS_FATAL_ERROR; @@ -1646,6 +1652,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, if (bytes != bufSz) { WLOG(WS_LOG_ERROR, scpError, "scp receive callback unable " "to write requested size to file", bytes); + WFCLOSE(fp); ret = WS_SCP_ABORT; } break; @@ -2101,6 +2108,10 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, if (ret == WS_SUCCESS && sendCtx != NULL && sendCtx->fp != NULL) { ret = (word32)WFREAD(buf, 1, bufSz, sendCtx->fp); + if (ret == 0) { /* handle unexpected case */ + ret = WS_EOF; + } + } else { ret = WS_SCP_ABORT; } @@ -2246,6 +2257,10 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, } ret = (word32)WFREAD(buf, 1, bufSz, sendCtx->fp); + if (ret == 0) { /* handle case of EOF */ + ret = WS_EOF; + } + if ((ret <= 0) || (fileOffset + ret == *totalFileSz)) { WFCLOSE(sendCtx->fp); } diff --git a/src/wolfsftp.c b/src/wolfsftp.c index 63e5b93..44f8eb4 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -2400,7 +2400,6 @@ int wolfSSH_SFTP_RecvSetSTAT(WOLFSSH* ssh, int reqId, word32 maxSz) clean_path(name); if (SFTP_ParseAtributes_buffer(ssh, &atr, data + idx, maxSz - idx) != 0) { - printf("error parsing attributes\n"); wolfSSH_SFTP_SendStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, "Unable to parse attributes error", "English"); return WS_BAD_FILE_E; @@ -2623,6 +2622,7 @@ int SendPacketType(WOLFSSH* ssh, byte type, byte* buf, word32 bufSz) * one time */ do { ret = wolfSSH_stream_send(ssh, data + sent, idx - sent); + wolfSSH_CheckPeerWindow(ssh); /* check for adjust window packet */ sent += (word32)ret; } while (ret > 0 && sent < idx); @@ -4258,6 +4258,7 @@ int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume, statusCb(ssh, pOfst, from); } } + wolfSSH_CheckPeerWindow(ssh); /* check for adjust window packet */ } while (sz > 0 && ssh->sftpInt == 0); if (ssh->sftpInt) { wolfSSH_SFTP_SaveOfst(ssh, from, to, pOfst); diff --git a/wolfssh/port.h b/wolfssh/port.h index 4800eac..b22166d 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -482,6 +482,29 @@ extern "C" { #define FALL_THROUGH #endif +/* used for checking bytes on wire for window adjust packet read */ +#ifndef WIOCTL +#ifdef WOLFSSL_NUCLEUS + #include "nucleus.h" + #include "networking/nu_networking.h" + static inline void ws_Ioctl(int fd, int flag, int* ret) + { + SCK_IOCTL_OPTION op; + op.s_optval = (unsigned char*)&fd; + if (NU_Ioctl(flag, &op, sizeof(op)) != NU_SUCCESS) { + *ret = 0; + } + else { + *ret = op.s_ret.sck_bytes_pending; + } + } + #define WIOCTL ws_Ioctl +#else + #include + #define WIOCTL ioctl +#endif +#endif + #ifdef __cplusplus } diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 4857c86..329e5c7 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -181,6 +181,7 @@ typedef enum { WOLFSSH_API WS_SessionType wolfSSH_GetSessionType(const WOLFSSH*); WOLFSSH_API const char* wolfSSH_GetSessionCommand(const WOLFSSH*); WOLFSSH_API int wolfSSH_SetChannelType(WOLFSSH*, byte, byte*, word32); +WOLFSSH_API void wolfSSH_CheckPeerWindow(WOLFSSH* ssh); enum WS_HighwaterSide {