mirror of https://github.com/wolfSSL/wolfssh.git
add callback and example for no file system with SCP
parent
728a6c2e73
commit
217a7d6520
|
@ -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 (readyFile != NULL) {
|
||||
#ifdef NO_FILESYSTEM
|
||||
fprintf(stderr, "cannot create readyFile with no file system.\r\n");
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
port = 0;
|
||||
}
|
||||
tcp_listen(&listenFd, &port, 1);
|
||||
/* write out port number listing to, to user set ready file */
|
||||
if (readyFile != NULL) {
|
||||
#ifndef NO_FILESYSTEM
|
||||
WFILE* f = NULL;
|
||||
int ret;
|
||||
ret = WFOPEN(&f, readyFile, "w");
|
||||
|
@ -1707,6 +1712,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
|
|||
fprintf(f, "%d\n", (int)port);
|
||||
WFCLOSE(f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
do {
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
|
||||
#ifdef NO_FILESYSTEM
|
||||
#include <wolfssh/certs_test.h>
|
||||
#ifdef WOLFSSH_SCP
|
||||
#include <wolfssh/wolfscp.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -143,6 +146,27 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs)
|
|||
int ret;
|
||||
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)
|
||||
ret = wolfSSH_accept(threadCtx->ssh);
|
||||
else
|
||||
|
@ -218,6 +242,21 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs)
|
|||
free(buf);
|
||||
} else if (ret == WS_SCP_COMPLETE) {
|
||||
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) {
|
||||
printf("Use example/echoserver/echoserver for SFTP\n");
|
||||
}
|
||||
|
|
|
@ -421,8 +421,7 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap)
|
|||
#endif /* WOLFSSH_USER_IO */
|
||||
ctx->highwaterMark = DEFAULT_HIGHWATER_MARK;
|
||||
ctx->highwaterCb = wsHighwater;
|
||||
#if defined(WOLFSSH_SCP) && !defined(WOLFSSH_SCP_USER_CALLBACKS) && \
|
||||
!defined(NO_FILESYSTEM)
|
||||
#if defined(WOLFSSH_SCP) && !defined(WOLFSSH_SCP_USER_CALLBACKS)
|
||||
ctx->scpRecvCb = wsScpRecvCallback;
|
||||
ctx->scpSendCb = wsScpSendCallback;
|
||||
#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) && \
|
||||
!defined(NO_TERMIOS)
|
||||
|
|
|
@ -872,7 +872,7 @@ int wolfSSH_connect(WOLFSSH* ssh)
|
|||
FALL_THROUGH;
|
||||
|
||||
case CONNECT_CLIENT_CHANNEL_AGENT_REQUEST_SENT:
|
||||
#ifdef WOLFSSH_TERM
|
||||
#if defined(WOLFSSH_TERM) && !defined(NO_FILESYSTEM)
|
||||
if (ssh->sendTerminalRequest) {
|
||||
if ( (ssh->error = SendChannelTerminalRequest(ssh))
|
||||
< WS_SUCCESS) {
|
||||
|
|
234
src/wolfscp.c
234
src/wolfscp.c
|
@ -47,13 +47,11 @@
|
|||
#include "src/misc.c"
|
||||
#endif
|
||||
|
||||
#if defined(NO_FILESYSTEM) && !defined(WOLFSSH_SCP_USER_CALLBACKS)
|
||||
#error "scp with no filesystem requires user callbacks"
|
||||
#endif
|
||||
|
||||
#ifndef NO_FILESYSTEM
|
||||
static int ScpFileIsDir(ScpSendCtx* ctx);
|
||||
static int ScpPushDir(ScpSendCtx* ctx, const char* path, void* heap);
|
||||
static int ScpPopDir(ScpSendCtx* ctx, void* heap);
|
||||
#endif
|
||||
|
||||
const char scpError[] = "scp error: %s, %d";
|
||||
const char scpState[] = "scp state: %s";
|
||||
|
@ -1091,11 +1089,15 @@ static int ScpCheckForRename(WOLFSSH* ssh, int cmdSz)
|
|||
* returns WS_SUCCESS on success */
|
||||
static int ParseBasePathHelper(WOLFSSH* ssh, int cmdSz)
|
||||
{
|
||||
ScpSendCtx ctx;
|
||||
int ret;
|
||||
|
||||
WMEMSET(&ctx, 0, sizeof(ScpSendCtx));
|
||||
ret = ScpCheckForRename(ssh, cmdSz);
|
||||
|
||||
#ifndef NO_FILESYSTEM
|
||||
{
|
||||
ScpSendCtx ctx;
|
||||
|
||||
WMEMSET(&ctx, 0, sizeof(ScpSendCtx));
|
||||
if (ScpPushDir(&ctx, ssh->scpBasePath, ssh->ctx->heap) != WS_SUCCESS) {
|
||||
WLOG(WS_LOG_DEBUG, "scp : issue opening base dir");
|
||||
}
|
||||
|
@ -1105,6 +1107,8 @@ static int ParseBasePathHelper(WOLFSSH* ssh, int cmdSz)
|
|||
ret = WS_SUCCESS; /* is ok to empty the directory stack here */
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* NO_FILESYSTEM */
|
||||
|
||||
/* default case of directory */
|
||||
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 */
|
||||
static INLINE int wolfSSH_LastError(void)
|
||||
|
@ -1882,40 +1922,6 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath,
|
|||
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)
|
||||
{
|
||||
if (fp == NULL || fileSz == NULL)
|
||||
|
@ -2481,6 +2487,152 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest,
|
|||
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 */
|
||||
|
|
|
@ -70,8 +70,9 @@ extern "C" {
|
|||
#endif
|
||||
#endif /* !WOLFSSH_HANDLE */
|
||||
|
||||
#ifndef NO_FILESYSTEM
|
||||
#ifdef WOLFSSL_NUCLEUS
|
||||
#ifdef NO_FILESYSTEM
|
||||
#define WS_DELIM '/'
|
||||
#elif defined(WOLFSSL_NUCLEUS)
|
||||
#include "storage/nu_storage.h"
|
||||
|
||||
#define WFILE int
|
||||
|
@ -276,7 +277,6 @@ extern "C" {
|
|||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif /* NO_FILESYSTEM */
|
||||
|
||||
/* setup string handling */
|
||||
#ifndef WSTRING_USER
|
||||
|
@ -369,7 +369,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \
|
||||
!defined(NO_WOLFSSH_SERVER)
|
||||
!defined(NO_WOLFSSH_SERVER) && !defined(NO_FILESYSTEM)
|
||||
|
||||
#ifndef SIZEOF_OFF_T
|
||||
/* if not using autoconf then make a guess on off_t size based on sizeof
|
||||
|
|
|
@ -52,7 +52,8 @@ extern "C" {
|
|||
#define DEFAULT_SCP_BUFFER_SZ DEFAULT_MAX_PACKET_SZ
|
||||
#endif
|
||||
|
||||
#if !defined(WOLFSSH_SCP_USER_CALLBACKS) && !defined(NO_FILESYSTEM)
|
||||
#if !defined(WOLFSSH_SCP_USER_CALLBACKS)
|
||||
#if !defined(NO_FILESYSTEM)
|
||||
#include <time.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
|
@ -77,7 +78,19 @@ extern "C" {
|
|||
WDIR dir; /* dir pointer, from opendir() */
|
||||
struct ScpDir* next; /* previous directory in stack */
|
||||
} 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 */
|
||||
|
||||
enum WS_ScpFileStates {
|
||||
|
|
Loading…
Reference in New Issue