add callback and example for no file system with SCP

pull/271/head
Jacob Barthelmeh 2020-07-21 16:50:19 -06:00
parent 728a6c2e73
commit 217a7d6520
7 changed files with 267 additions and 58 deletions

View File

@ -1695,11 +1695,16 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
/* if creating a ready file with port then override port to be 0 */ /* if creating a ready file with port then override port to be 0 */
if (readyFile != NULL) { if (readyFile != NULL) {
#ifdef NO_FILESYSTEM
fprintf(stderr, "cannot create readyFile with no file system.\r\n");
exit(EXIT_FAILURE);
#endif
port = 0; port = 0;
} }
tcp_listen(&listenFd, &port, 1); tcp_listen(&listenFd, &port, 1);
/* write out port number listing to, to user set ready file */ /* write out port number listing to, to user set ready file */
if (readyFile != NULL) { if (readyFile != NULL) {
#ifndef NO_FILESYSTEM
WFILE* f = NULL; WFILE* f = NULL;
int ret; int ret;
ret = WFOPEN(&f, readyFile, "w"); ret = WFOPEN(&f, readyFile, "w");
@ -1707,6 +1712,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
fprintf(f, "%d\n", (int)port); fprintf(f, "%d\n", (int)port);
WFCLOSE(f); WFCLOSE(f);
} }
#endif
} }
do { do {

View File

@ -37,6 +37,9 @@
#ifdef NO_FILESYSTEM #ifdef NO_FILESYSTEM
#include <wolfssh/certs_test.h> #include <wolfssh/certs_test.h>
#ifdef WOLFSSH_SCP
#include <wolfssh/wolfscp.h>
#endif
#endif #endif
@ -143,6 +146,27 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs)
int ret; int ret;
thread_ctx_t* threadCtx = (thread_ctx_t*)vArgs; thread_ctx_t* threadCtx = (thread_ctx_t*)vArgs;
#if defined(WOLFSSH_SCP) && defined(NO_FILESYSTEM)
ScpBuffer scpBufferRecv, scpBufferSend;
byte fileBuffer[1024];
byte fileTmp[] = "wolfSSH SCP buffer file";
WMEMSET(&scpBufferRecv, 0, sizeof(ScpBuffer));
scpBufferRecv.buffer = fileBuffer;
scpBufferRecv.bufferSz = 1024;
wolfSSH_SetScpRecvCtx(threadCtx->ssh, (void*)&scpBufferRecv);
/* make buffer file to send if asked */
WMEMSET(&scpBufferSend, 0, sizeof(ScpBuffer));
WMEMCPY(scpBufferSend.name, "test.txt", sizeof("test.txt"));
scpBufferSend.nameSz = WSTRLEN("test.txt");
scpBufferSend.buffer = fileTmp;
scpBufferSend.bufferSz = sizeof(fileTmp);
scpBufferSend.fileSz = sizeof(fileTmp);
scpBufferSend.mode = 0x1A4;
wolfSSH_SetScpSendCtx(threadCtx->ssh, (void*)&scpBufferSend);
#endif
if (!threadCtx->nonBlock) if (!threadCtx->nonBlock)
ret = wolfSSH_accept(threadCtx->ssh); ret = wolfSSH_accept(threadCtx->ssh);
else else
@ -218,6 +242,21 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs)
free(buf); free(buf);
} else if (ret == WS_SCP_COMPLETE) { } else if (ret == WS_SCP_COMPLETE) {
printf("scp file transfer completed\n"); printf("scp file transfer completed\n");
#if defined(WOLFSSH_SCP) && defined(NO_FILESYSTEM)
if (scpBufferRecv.fileSz > 0) {
word32 z;
printf("file name : %s\n", scpBufferRecv.name);
printf(" size : %d\n", scpBufferRecv.fileSz);
printf(" mode : %o\n", scpBufferRecv.mode);
printf(" mTime : %lu\n", scpBufferRecv.mTime);
printf("\n");
for (z = 0; z < scpBufferRecv.fileSz; z++)
printf("%c", scpBufferRecv.buffer[z]);
printf("\n");
}
#endif
} else if (ret == WS_SFTP_COMPLETE) { } else if (ret == WS_SFTP_COMPLETE) {
printf("Use example/echoserver/echoserver for SFTP\n"); printf("Use example/echoserver/echoserver for SFTP\n");
} }

View File

@ -421,8 +421,7 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap)
#endif /* WOLFSSH_USER_IO */ #endif /* WOLFSSH_USER_IO */
ctx->highwaterMark = DEFAULT_HIGHWATER_MARK; ctx->highwaterMark = DEFAULT_HIGHWATER_MARK;
ctx->highwaterCb = wsHighwater; ctx->highwaterCb = wsHighwater;
#if defined(WOLFSSH_SCP) && !defined(WOLFSSH_SCP_USER_CALLBACKS) && \ #if defined(WOLFSSH_SCP) && !defined(WOLFSSH_SCP_USER_CALLBACKS)
!defined(NO_FILESYSTEM)
ctx->scpRecvCb = wsScpRecvCallback; ctx->scpRecvCb = wsScpRecvCallback;
ctx->scpSendCb = wsScpSendCallback; ctx->scpSendCb = wsScpSendCallback;
#endif /* WOLFSSH_SCP */ #endif /* WOLFSSH_SCP */
@ -8744,7 +8743,7 @@ int SendChannelRequest(WOLFSSH* ssh, byte* name, word32 nameSz)
} }
#ifdef WOLFSSH_TERM #if defined(WOLFSSH_TERM) && !defined(NO_FILESYSTEM)
#if !defined(USE_WINDOWS_API) && !defined(MICROCHIP_PIC32) && \ #if !defined(USE_WINDOWS_API) && !defined(MICROCHIP_PIC32) && \
!defined(NO_TERMIOS) !defined(NO_TERMIOS)

View File

@ -872,7 +872,7 @@ int wolfSSH_connect(WOLFSSH* ssh)
FALL_THROUGH; FALL_THROUGH;
case CONNECT_CLIENT_CHANNEL_AGENT_REQUEST_SENT: case CONNECT_CLIENT_CHANNEL_AGENT_REQUEST_SENT:
#ifdef WOLFSSH_TERM #if defined(WOLFSSH_TERM) && !defined(NO_FILESYSTEM)
if (ssh->sendTerminalRequest) { if (ssh->sendTerminalRequest) {
if ( (ssh->error = SendChannelTerminalRequest(ssh)) if ( (ssh->error = SendChannelTerminalRequest(ssh))
< WS_SUCCESS) { < WS_SUCCESS) {

View File

@ -47,13 +47,11 @@
#include "src/misc.c" #include "src/misc.c"
#endif #endif
#if defined(NO_FILESYSTEM) && !defined(WOLFSSH_SCP_USER_CALLBACKS) #ifndef NO_FILESYSTEM
#error "scp with no filesystem requires user callbacks"
#endif
static int ScpFileIsDir(ScpSendCtx* ctx); static int ScpFileIsDir(ScpSendCtx* ctx);
static int ScpPushDir(ScpSendCtx* ctx, const char* path, void* heap); static int ScpPushDir(ScpSendCtx* ctx, const char* path, void* heap);
static int ScpPopDir(ScpSendCtx* ctx, void* heap); static int ScpPopDir(ScpSendCtx* ctx, void* heap);
#endif
const char scpError[] = "scp error: %s, %d"; const char scpError[] = "scp error: %s, %d";
const char scpState[] = "scp state: %s"; const char scpState[] = "scp state: %s";
@ -1091,20 +1089,26 @@ static int ScpCheckForRename(WOLFSSH* ssh, int cmdSz)
* returns WS_SUCCESS on success */ * returns WS_SUCCESS on success */
static int ParseBasePathHelper(WOLFSSH* ssh, int cmdSz) static int ParseBasePathHelper(WOLFSSH* ssh, int cmdSz)
{ {
ScpSendCtx ctx;
int ret; int ret;
WMEMSET(&ctx, 0, sizeof(ScpSendCtx));
ret = ScpCheckForRename(ssh, cmdSz); ret = ScpCheckForRename(ssh, cmdSz);
if (ScpPushDir(&ctx, ssh->scpBasePath, ssh->ctx->heap) != WS_SUCCESS) {
WLOG(WS_LOG_DEBUG, "scp : issue opening base dir"); #ifndef NO_FILESYSTEM
} {
else { ScpSendCtx ctx;
ret = ScpPopDir(&ctx, ssh->ctx->heap);
if (ret == WS_SCP_DIR_STACK_EMPTY_E) { WMEMSET(&ctx, 0, sizeof(ScpSendCtx));
ret = WS_SUCCESS; /* is ok to empty the directory stack here */ if (ScpPushDir(&ctx, ssh->scpBasePath, ssh->ctx->heap) != WS_SUCCESS) {
WLOG(WS_LOG_DEBUG, "scp : issue opening base dir");
}
else {
ret = ScpPopDir(&ctx, ssh->ctx->heap);
if (ret == WS_SCP_DIR_STACK_EMPTY_E) {
ret = WS_SUCCESS; /* is ok to empty the directory stack here */
}
} }
} }
#endif /* NO_FILESYSTEM */
/* default case of directory */ /* default case of directory */
return ret; return ret;
@ -1608,7 +1612,43 @@ int wolfSSH_SCP_from(WOLFSSH* ssh, const char* src, const char* dst)
} }
#if !defined(WOLFSSH_SCP_USER_CALLBACKS) && !defined(NO_FILESYSTEM) #if !defined(WOLFSSH_SCP_USER_CALLBACKS)
/* Extract file name from full path, store in fileName.
* Return WS_SUCCESS on success, negative upon error */
static int ExtractFileName(const char* filePath, char* fileName,
word32 fileNameSz)
{
int ret = WS_SUCCESS;
word32 fileLen;
int idx = 0, pathLen, separator = -1;
if (filePath == NULL || fileName == NULL)
return WS_BAD_ARGUMENT;
pathLen = (int)WSTRLEN(filePath);
/* find last separator */
while (idx < pathLen) {
if (filePath[idx] == '/' || filePath[idx] == '\\')
separator = idx;
idx++;
}
if (separator < 0)
return WS_BAD_ARGUMENT;
fileLen = pathLen - separator - 1;
if (fileLen + 1 > fileNameSz)
return WS_SCP_PATH_LEN_E;
WMEMCPY(fileName, filePath + separator + 1, fileLen);
fileName[fileLen] = '\0';
return ret;
}
#if !defined(NO_FILESYSTEM)
/* for porting to systems without errno */ /* for porting to systems without errno */
static INLINE int wolfSSH_LastError(void) static INLINE int wolfSSH_LastError(void)
@ -1882,40 +1922,6 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath,
return ret; return ret;
} }
/* Extract file name from full path, store in fileName.
* Return WS_SUCCESS on success, negative upon error */
static int ExtractFileName(const char* filePath, char* fileName,
word32 fileNameSz)
{
int ret = WS_SUCCESS;
word32 fileLen;
int idx = 0, pathLen, separator = -1;
if (filePath == NULL || fileName == NULL)
return WS_BAD_ARGUMENT;
pathLen = (int)WSTRLEN(filePath);
/* find last separator */
while (idx < pathLen) {
if (filePath[idx] == '/' || filePath[idx] == '\\')
separator = idx;
idx++;
}
if (separator < 0)
return WS_BAD_ARGUMENT;
fileLen = pathLen - separator - 1;
if (fileLen + 1 > fileNameSz)
return WS_SCP_PATH_LEN_E;
WMEMCPY(fileName, filePath + separator + 1, fileLen);
fileName[fileLen] = '\0';
return ret;
}
static int GetFileSize(WFILE* fp, word32* fileSz) static int GetFileSize(WFILE* fp, word32* fileSz)
{ {
if (fp == NULL || fileSz == NULL) if (fp == NULL || fileSz == NULL)
@ -2481,6 +2487,152 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest,
return ret; return ret;
} }
#else
/* single file transfer with no filesystem */
int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath,
const char* fileName, int fileMode, word64 mTime, word64 aTime,
word32 totalFileSz, byte* buf, word32 bufSz, word32 fileOffset,
void* ctx)
{
ScpBuffer* recvBuffer;
int ret = WS_SCP_CONTINUE;
int sz;
if (ctx == NULL) {
wolfSSH_SetScpErrorMsg(ssh, "SCP receive ctx not set");
return WS_SCP_ABORT;
}
recvBuffer = (ScpBuffer*)ctx;
switch (state) {
case WOLFSSH_SCP_NEW_REQUEST:
break;
case WOLFSSH_SCP_NEW_FILE:
/* create file */
WMEMCPY(recvBuffer->name, fileName, WSTRLEN(fileName));
recvBuffer->mTime = mTime;
recvBuffer->mode = fileMode;
break;
case WOLFSSH_SCP_FILE_PART:
/* read file, or file part */
sz = (bufSz < recvBuffer->bufferSz - recvBuffer->idx) ?
bufSz : recvBuffer->bufferSz - recvBuffer->idx;
WMEMCPY(recvBuffer->buffer + recvBuffer->idx, buf, sz);
recvBuffer->fileSz += sz;
break;
case WOLFSSH_SCP_FILE_DONE:
recvBuffer->idx = 0; /* rewind when done */
recvBuffer->mTime = 0; /* @TODO set time if wanted */
break;
case WOLFSSH_SCP_NEW_DIR:
case WOLFSSH_SCP_END_DIR:
wolfSSH_SetScpErrorMsg(ssh,
"creating a new directory not supported");
ret = WS_SCP_ABORT;
break;
default:
wolfSSH_SetScpErrorMsg(ssh, "invalid scp command request");
ret = WS_SCP_ABORT;
}
(void)totalFileSz;
(void)fileOffset;
(void)aTime;
(void)basePath;
return ret;
}
/* callback for single file transfer with no file system */
int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest,
char* fileName, word32 fileNameSz, word64* mTime, word64* aTime,
int* fileMode, word32 fileOffset, word32* totalFileSz, byte* buf,
word32 bufSz, void* ctx)
{
ScpBuffer* sendBuffer= NULL;
int ret = WS_SUCCESS;
if (ctx == NULL) {
wolfSSH_SetScpErrorMsg(ssh, "no ctx sent to hold file info");
return WS_SCP_ABORT;
}
sendBuffer = (ScpBuffer*)ctx;
switch (state) {
case WOLFSSH_SCP_NEW_REQUEST:
break;
case WOLFSSH_SCP_SINGLE_FILE_REQUEST:
if (sendBuffer->buffer == NULL) {
wolfSSH_SetScpErrorMsg(ssh, "no buffer to send");
ret = WS_SCP_ABORT;
break;
}
*totalFileSz = sendBuffer->bufferSz;
*mTime = sendBuffer->mTime;
*aTime = sendBuffer->mTime;
*fileMode = sendBuffer->mode;
ret = ExtractFileName(peerRequest, fileName, fileNameSz);
if (WSTRLEN(fileName) != sendBuffer->nameSz ||
WMEMCMP(sendBuffer->name, fileName, fileNameSz) != 0) {
wolfSSH_SetScpErrorMsg(ssh, "file name did not match");
ret = WS_SCP_ABORT;
break;
}
/* copy over buffer info */
if (sendBuffer->idx >= sendBuffer->bufferSz) {
ret = WS_SCP_ABORT;
break;
}
ret = (bufSz < (sendBuffer->bufferSz - sendBuffer->idx))?
bufSz : sendBuffer->bufferSz - sendBuffer->idx;
WMEMCPY(buf, sendBuffer->buffer + sendBuffer->idx, ret);
sendBuffer->idx += ret;
break;
case WOLFSSH_SCP_RECURSIVE_REQUEST:
wolfSSH_SetScpErrorMsg(ssh,
"recursive request without filesystem not supported");
ret = WS_SCP_ABORT;
break;
case WOLFSSH_SCP_CONTINUE_FILE_TRANSFER:
/* copy over buffer info */
if (sendBuffer->idx >= sendBuffer->bufferSz) {
ret = WS_SCP_ABORT;
break;
}
ret = (bufSz < (sendBuffer->bufferSz - sendBuffer->idx))?
bufSz : sendBuffer->bufferSz - sendBuffer->idx;
if (ret > 0) {
WMEMCPY(buf, sendBuffer->buffer + sendBuffer->idx, ret);
sendBuffer->idx += ret;
}
if (ret == 0) { /* handle case of EOF */
ret = WS_EOF;
}
break;
default:
wolfSSH_SetScpErrorMsg(ssh, "bad state");
ret = WS_SCP_ABORT;
}
(void)fileOffset;
return ret;
}
#endif /* NO_FILESYSTME */
#endif /* WOLFSSH_SCP_USER_CALLBACKS */ #endif /* WOLFSSH_SCP_USER_CALLBACKS */
#endif /* WOLFSSH_SCP */ #endif /* WOLFSSH_SCP */

View File

@ -70,8 +70,9 @@ extern "C" {
#endif #endif
#endif /* !WOLFSSH_HANDLE */ #endif /* !WOLFSSH_HANDLE */
#ifndef NO_FILESYSTEM #ifdef NO_FILESYSTEM
#ifdef WOLFSSL_NUCLEUS #define WS_DELIM '/'
#elif defined(WOLFSSL_NUCLEUS)
#include "storage/nu_storage.h" #include "storage/nu_storage.h"
#define WFILE int #define WFILE int
@ -276,7 +277,6 @@ extern "C" {
#endif #endif
#endif #endif
#endif #endif
#endif /* NO_FILESYSTEM */
/* setup string handling */ /* setup string handling */
#ifndef WSTRING_USER #ifndef WSTRING_USER
@ -369,7 +369,7 @@ extern "C" {
#endif #endif
#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \ #if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \
!defined(NO_WOLFSSH_SERVER) !defined(NO_WOLFSSH_SERVER) && !defined(NO_FILESYSTEM)
#ifndef SIZEOF_OFF_T #ifndef SIZEOF_OFF_T
/* if not using autoconf then make a guess on off_t size based on sizeof /* if not using autoconf then make a guess on off_t size based on sizeof

View File

@ -52,7 +52,8 @@ extern "C" {
#define DEFAULT_SCP_BUFFER_SZ DEFAULT_MAX_PACKET_SZ #define DEFAULT_SCP_BUFFER_SZ DEFAULT_MAX_PACKET_SZ
#endif #endif
#if !defined(WOLFSSH_SCP_USER_CALLBACKS) && !defined(NO_FILESYSTEM) #if !defined(WOLFSSH_SCP_USER_CALLBACKS)
#if !defined(NO_FILESYSTEM)
#include <time.h> #include <time.h>
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
#include <sys/time.h> #include <sys/time.h>
@ -77,7 +78,19 @@ extern "C" {
WDIR dir; /* dir pointer, from opendir() */ WDIR dir; /* dir pointer, from opendir() */
struct ScpDir* next; /* previous directory in stack */ struct ScpDir* next; /* previous directory in stack */
} ScpDir; } ScpDir;
#else
/* Use a buffer for built in no filesystem send/recv */
typedef struct ScpBuffer {
char name[DEFAULT_SCP_FILE_NAME_SZ];
byte* buffer;
word64 mTime;
word32 bufferSz; /* size of "buffer" */
word32 fileSz; /* size of file in "buffer" */
word32 idx; /* current index into "buffer" */
word32 nameSz;
int mode;
} ScpBuffer;
#endif /* NO_FILESYSTEM */
#endif /* WOLFSSH_SCP_USER_CALLBACKS */ #endif /* WOLFSSH_SCP_USER_CALLBACKS */
enum WS_ScpFileStates { enum WS_ScpFileStates {