diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 36a6c4c9..386dc9a2 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -32,6 +32,10 @@ #include #include "examples/echoserver/echoserver.h" +#ifdef WOLFSSL_NUCLEUS + /* use buffers for keys with server */ + #define NO_FILESYSTEM +#endif #ifdef NO_FILESYSTEM #include @@ -211,6 +215,10 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) exit(EXIT_FAILURE); } + if (wolfSSH_shutdown(threadCtx->ssh) != WS_SUCCESS) { + fprintf(stderr, "Error with SSH shutdown.\n"); + } + WCLOSESOCKET(threadCtx->fd); wolfSSH_free(threadCtx->ssh); free(threadCtx); @@ -585,6 +593,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) char** argv = serverArgs->argv; serverArgs->return_code = 0; + if (argc > 0) { while ((ch = mygetopt(argc, argv, "?1ep:")) != -1) { switch (ch) { case '?' : @@ -612,6 +621,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) exit(MY_EX_USAGE); } } + } myoptind = 0; /* reset for test cases */ if (wolfSSH_Init() != WS_SUCCESS) { @@ -660,13 +670,41 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) buf[bufSz] = 0; LoadPublicKeyBuffer(buf, bufSz, &pwMapList); } +#ifdef WOLFSSL_NUCLEUS + { + int i; + int ret = !NU_SUCCESS; + + /* wait for network and storage device */ + if (NETBOOT_Wait_For_Network_Up(NU_SUSPEND) != NU_SUCCESS) { + fprintf(stderr, "Couldn't find network.\r\n"); + exit(EXIT_FAILURE); + } + + for(i = 0; i < 15 && ret != NU_SUCCESS; i++) + { + fprintf(stdout, "Checking for storage device\r\n"); + + ret = NU_Storage_Device_Wait(NU_NULL, NU_PLUS_TICKS_PER_SEC); + } + + if (ret != NU_SUCCESS) { + fprintf(stderr, "Couldn't find storage device.\r\n"); + exit(EXIT_FAILURE); + } + } +#endif tcp_listen(&listenFd, &port, 1); do { SOCKET_T clientFd = 0; + #ifdef WOLFSSL_NUCLEUS + struct addr_struct clientAddr; + #else SOCKADDR_IN_T clientAddr; socklen_t clientAddrSz = sizeof(clientAddr); + #endif WOLFSSH* ssh; thread_ctx_t* threadCtx; @@ -688,10 +726,35 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) wolfSSH_SetHighwater(ssh, defaultHighwater); } + #ifdef WOLFSSL_NUCLEUS + { + byte ipaddr[MAX_ADDRESS_SIZE]; + char buf[16]; + short addrLength; + struct sockaddr_struct sock; + + addrLength = sizeof(struct sockaddr_struct); + + /* Get the local IP address for the socket. 0.0.0.0 if ip adder any */ + if (NU_Get_Sock_Name(listenFd, &sock, &addrLength) != NU_SUCCESS) { + fprintf(stderr, "Couldn't find network.\r\n"); + exit(EXIT_FAILURE); + } + + WMEMCPY(ipaddr, &sock.ip_num, MAX_ADDRESS_SIZE); + NU_Inet_NTOP(NU_FAMILY_IP, &ipaddr[0], buf, 16); + fprintf(stdout, "Listing on %s:%d\r\n", buf, port); + } + #endif + SignalTcpReady(serverArgs, port); + #ifdef WOLFSSL_NUCLEUS + clientFd = NU_Accept(listenFd, &clientAddr, 0); + #else clientFd = accept(listenFd, (struct sockaddr*)&clientAddr, - &clientAddrSz); + &clientAddrSz); + #endif if (clientFd == -1) err_sys("tcp accept failed"); @@ -715,6 +778,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) return 0; } + #ifndef NO_MAIN_DRIVER int main(int argc, char** argv) @@ -734,7 +798,9 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) wolfSSH_Init(); +#ifndef WOLFSSL_NUCLEUS ChangeToWolfSshRoot(); +#endif echoserver_test(&args); wolfSSH_Cleanup(); @@ -747,3 +813,37 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) char* myoptarg = NULL; #endif /* NO_MAIN_DRIVER */ + +#ifdef WOLFSSL_NUCLEUS + + #define WS_TASK_SIZE 200000 + #define WS_TASK_PRIORITY 31 + static NU_TASK serverTask; + + /* expecting void return on main function */ + static VOID main_nucleus(UNSIGNED argc, VOID* argv) + { + main((int)argc, (char**)argv); + } + + + /* using port 8080 because it was an open port on QEMU */ + VOID Application_Initialize (NU_MEMORY_POOL* memPool, + NU_MEMORY_POOL* uncachedPool) + { + void* pt; + int ret; + + UNUSED_PARAMETER(uncachedPool); + + ret = NU_Allocate_Memory(memPool, &pt, WS_TASK_SIZE, NU_NO_SUSPEND); + if (ret == NU_SUCCESS) { + ret = NU_Create_Task(&serverTask, "wolfSSH Server", main_nucleus, 0, + NU_NULL, pt, WS_TASK_SIZE, WS_TASK_PRIORITY, 0, + NU_PREEMPT, NU_START); + if (ret != NU_SUCCESS) { + NU_Deallocate_Memory(pt); + } + } + } +#endif /* WOLFSSL_NUCLEUS */ diff --git a/ide/CSBENCH/.cproject b/ide/CSBENCH/.cproject new file mode 100644 index 00000000..1c7c7ee4 --- /dev/null +++ b/ide/CSBENCH/.cproject @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ide/CSBENCH/.project b/ide/CSBENCH/.project new file mode 100644 index 00000000..302cf9c5 --- /dev/null +++ b/ide/CSBENCH/.project @@ -0,0 +1,38 @@ + + + sftp + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + echoserver + 2 + PARENT-2-PROJECT_LOC../examples/echoserver + + + src + 2 + PARENT-2-PROJECT_LOC../src + + + diff --git a/ide/CSBENCH/README b/ide/CSBENCH/README new file mode 100644 index 00000000..c51c050f --- /dev/null +++ b/ide/CSBENCH/README @@ -0,0 +1,13 @@ +This is to build with Sourcery CodeBench IDE + +It makes the assumption that the root wolfssl and wolfssh directory are in the same folder + +workspace -> + ->wolfssl + ->wolfssh + +To build first compile the wolfssl library using the project provided in wolfssl/IDE/CSBENCH + +Next compile the sftp example project provided in wolfssh/ide/CSBENCH + +Note that this is using port 8080 to listen on by default diff --git a/ide/CSBENCH/include.am b/ide/CSBENCH/include.am new file mode 100644 index 00000000..22cd0165 --- /dev/null +++ b/ide/CSBENCH/include.am @@ -0,0 +1,7 @@ +# vim:ft=automake +# included from Top Level Makefile.am +# All paths should be given relative to the root + +EXTRA_DIST+= ide/CSBENCH/.cproject +EXTRA_DIST+= ide/CSBENCH/.project +EXTRA_DIST+= ide/CSBENCH/README diff --git a/ide/include.am b/ide/include.am index e028e04c..4c020b9e 100644 --- a/ide/include.am +++ b/ide/include.am @@ -1,5 +1,6 @@ -# vim:ft=automake -# included from Top Level Makefile.am -# All paths should be given relative to the root - -include ide/winvs/include.am +# vim:ft=automake +# included from Top Level Makefile.am +# All paths should be given relative to the root + +include ide/winvs/include.am +include ide/CSBENCH/include.am diff --git a/src/internal.c b/src/internal.c index 15e3f006..8e278bc7 100644 --- a/src/internal.c +++ b/src/internal.c @@ -236,6 +236,9 @@ const char* GetErrorString(int err) case WS_SFTP_COMPLETE: return "sftp connection established"; + case WS_NEXT_ERROR: + return "Getting next value/state results in error"; + default: return "Unknown error code"; } @@ -4502,7 +4505,7 @@ int DoReceive(WOLFSSH* ssh) return ret; } } - FALL_THROUGH; + FALL_THROUGH /* no break */ case PROCESS_PACKET_LENGTH: if (ssh->inputBuffer.idx + UINT32_SZ > ssh->inputBuffer.bufferSz) @@ -4515,7 +4518,7 @@ int DoReceive(WOLFSSH* ssh) return WS_OVERFLOW_E; ssh->processReplyState = PROCESS_PACKET_FINISH; - FALL_THROUGH; + FALL_THROUGH /* no break */ case PROCESS_PACKET_FINISH: readSz = ssh->curSz + LENGTH_SZ + peerMacSz; @@ -4581,7 +4584,7 @@ int DoReceive(WOLFSSH* ssh) } } ssh->processReplyState = PROCESS_PACKET; - FALL_THROUGH; + FALL_THROUGH /* no break */ case PROCESS_PACKET: if ( (ret = DoPacket(ssh)) < 0) { @@ -4604,6 +4607,7 @@ int DoReceive(WOLFSSH* ssh) return WS_SUCCESS; } + return ret; } diff --git a/src/io.c b/src/io.c index afdf5a8a..8b272873 100644 --- a/src/io.c +++ b/src/io.c @@ -128,6 +128,10 @@ void* wolfSSH_GetIOWriteCtx(WOLFSSH* ssh) #include "tcpip/tcpip.h" #include "sys/errno.h" #include + #elif defined(WOLFSSL_NUCLEUS) + #include "nucleus.h" + #include "networking/nu_networking.h" + #include #else #include #include @@ -208,6 +212,14 @@ void* wolfSSH_GetIOWriteCtx(WOLFSSH* ssh) #define SOCKET_ECONNREFUSED SCK_ERROR #define SOCKET_ECONNABORTED SCK_ERROR #endif +#elif defined(WOLFSSL_NUCLEUS) + #define SOCKET_EWOULDBLOCK NU_WOULD_BLOCK + #define SOCKET_EAGAIN NU_WOULD_BLOCK + #define SOCKET_ECONNRESET NU_NOT_CONNECTED + #define SOCKET_EINTR NU_NOT_CONNECTED + #define SOCKET_EPIPE NU_NOT_CONNECTED + #define SOCKET_ECONNREFUSED NU_CONNECTION_REFUSED + #define SOCKET_ECONNABORTED NU_NOT_CONNECTED #else #define SOCKET_EWOULDBLOCK EWOULDBLOCK #define SOCKET_EAGAIN EAGAIN @@ -233,6 +245,9 @@ void* wolfSSH_GetIOWriteCtx(WOLFSSH* ssh) TCPIP_TCP_ArrayPut((socket),(uint8_t*)(buf),(sz)) #define RECV_FUNCTION(socket,buf,sz,flags) \ TCPIP_TCP_ArrayGet((socket),(uint8_t*)(buf),(sz)) +#elif defined(WOLFSSL_NUCLEUS) + #define SEND_FUNCTION NU_Send + #define RECV_FUNCTION NU_Recv #else #define SEND_FUNCTION send #define RECV_FUNCTION recv diff --git a/src/keygen.c b/src/keygen.c index e5c56ce7..1292c1e1 100644 --- a/src/keygen.c +++ b/src/keygen.c @@ -29,7 +29,13 @@ #include #endif +#ifdef WOLFSSL_USER_SETTINGS +#include +#else #include +#endif + + #include #include #include diff --git a/src/port.c b/src/port.c index de194722..6f9278d4 100644 --- a/src/port.c +++ b/src/port.c @@ -40,6 +40,28 @@ int wfopen(WFILE** f, const char* filename, const char* mode) { #ifdef USE_WINDOWS_API return fopen_s(f, filename, mode) != 0; +#elif defined(WOLFSSL_NUCLEUS) + int m = WOLFSSH_O_CREAT; + if (WSTRSTR(mode, "r")) { + m |= WOLFSSH_O_RDONLY; + } + if (WSTRSTR(mode, "w")) { + if (m &= WOLFSSH_O_RDONLY) { + m ^= WOLFSSH_O_RDONLY; + m |= WOLFSSH_O_RDWR; + } + else { + m |= WOLFSSH_O_WRONLY; + } + } + + if (filename != NULL && f != NULL) { + **f = NU_Open(filename, m, 0); + return 1; + } + else { + return 0; + } #else if (f != NULL) { *f = fopen(filename, mode); diff --git a/src/ssh.c b/src/ssh.c index bc4048fc..db0ad273 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -270,7 +270,7 @@ int wolfSSH_accept(WOLFSSH* ssh) } ssh->acceptState = ACCEPT_SERVER_VERSION_SENT; WLOG(WS_LOG_DEBUG, acceptState, "SERVER_VERSION_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case ACCEPT_SERVER_VERSION_SENT: while (ssh->clientState < CLIENT_VERSION_DONE) { @@ -282,7 +282,7 @@ int wolfSSH_accept(WOLFSSH* ssh) } ssh->acceptState = ACCEPT_CLIENT_VERSION_DONE; WLOG(WS_LOG_DEBUG, acceptState, "CLIENT_VERSION_DONE"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case ACCEPT_CLIENT_VERSION_DONE: if ( (ssh->error = SendKexInit(ssh)) < WS_SUCCESS) { @@ -292,7 +292,7 @@ int wolfSSH_accept(WOLFSSH* ssh) } ssh->acceptState = ACCEPT_SERVER_KEXINIT_SENT; WLOG(WS_LOG_DEBUG, acceptState, "SERVER_KEXINIT_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case ACCEPT_SERVER_KEXINIT_SENT: while (ssh->isKeying) { @@ -304,7 +304,7 @@ int wolfSSH_accept(WOLFSSH* ssh) } ssh->acceptState = ACCEPT_KEYED; WLOG(WS_LOG_DEBUG, acceptState, "KEYED"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case ACCEPT_KEYED: while (ssh->clientState < CLIENT_USERAUTH_REQUEST_DONE) { @@ -316,7 +316,7 @@ int wolfSSH_accept(WOLFSSH* ssh) } ssh->acceptState = ACCEPT_CLIENT_USERAUTH_REQUEST_DONE; WLOG(WS_LOG_DEBUG, acceptState, "CLIENT_USERAUTH_REQUEST_DONE"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case ACCEPT_CLIENT_USERAUTH_REQUEST_DONE: if ( (ssh->error = SendServiceAccept(ssh, @@ -328,7 +328,7 @@ int wolfSSH_accept(WOLFSSH* ssh) ssh->acceptState = ACCEPT_SERVER_USERAUTH_ACCEPT_SENT; WLOG(WS_LOG_DEBUG, acceptState, "ACCEPT_SERVER_USERAUTH_ACCEPT_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case ACCEPT_SERVER_USERAUTH_ACCEPT_SENT: while (ssh->clientState < CLIENT_USERAUTH_DONE) { @@ -340,7 +340,7 @@ int wolfSSH_accept(WOLFSSH* ssh) } ssh->acceptState = ACCEPT_CLIENT_USERAUTH_DONE; WLOG(WS_LOG_DEBUG, acceptState, "CLIENT_USERAUTH_DONE"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case ACCEPT_CLIENT_USERAUTH_DONE: if ( (ssh->error = SendUserAuthSuccess(ssh)) < WS_SUCCESS) { @@ -350,7 +350,7 @@ int wolfSSH_accept(WOLFSSH* ssh) } ssh->acceptState = ACCEPT_SERVER_USERAUTH_SENT; WLOG(WS_LOG_DEBUG, acceptState, "SERVER_USERAUTH_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case ACCEPT_SERVER_USERAUTH_SENT: while (ssh->clientState < CLIENT_CHANNEL_OPEN_DONE) { @@ -362,7 +362,7 @@ int wolfSSH_accept(WOLFSSH* ssh) } ssh->acceptState = ACCEPT_CLIENT_CHANNEL_REQUEST_DONE; WLOG(WS_LOG_DEBUG, acceptState, "CLIENT_CHANNEL_REQUEST_DONE"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case ACCEPT_CLIENT_CHANNEL_REQUEST_DONE: if ( (ssh->error = SendChannelOpenConf(ssh)) < WS_SUCCESS) { @@ -372,7 +372,7 @@ int wolfSSH_accept(WOLFSSH* ssh) } ssh->acceptState = ACCEPT_SERVER_CHANNEL_ACCEPT_SENT; WLOG(WS_LOG_DEBUG, acceptState, "SERVER_CHANNEL_ACCEPT_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case ACCEPT_SERVER_CHANNEL_ACCEPT_SENT: while (ssh->clientState < CLIENT_DONE) { @@ -440,7 +440,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } ssh->connectState = CONNECT_CLIENT_VERSION_SENT; WLOG(WS_LOG_DEBUG, connectState, "CLIENT_VERSION_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_CLIENT_VERSION_SENT: while (ssh->serverState < SERVER_VERSION_DONE) { @@ -452,7 +452,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } ssh->connectState = CONNECT_SERVER_VERSION_DONE; WLOG(WS_LOG_DEBUG, connectState, "SERVER_VERSION_DONE"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_SERVER_VERSION_DONE: if ( (ssh->error = SendKexInit(ssh)) < WS_SUCCESS) { @@ -462,7 +462,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } ssh->connectState = CONNECT_CLIENT_KEXINIT_SENT; WLOG(WS_LOG_DEBUG, connectState, "CLIENT_KEXINIT_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_CLIENT_KEXINIT_SENT: while (ssh->serverState < SERVER_KEXINIT_DONE) { @@ -474,7 +474,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } ssh->connectState = CONNECT_SERVER_KEXINIT_DONE; WLOG(WS_LOG_DEBUG, connectState, "SERVER_KEXINIT_DONE"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_SERVER_KEXINIT_DONE: if (ssh->handshake->kexId == ID_DH_GEX_SHA256) @@ -488,7 +488,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } ssh->connectState = CONNECT_CLIENT_KEXDH_INIT_SENT; WLOG(WS_LOG_DEBUG, connectState, "CLIENT_KEXDH_INIT_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_CLIENT_KEXDH_INIT_SENT: while (ssh->isKeying) { @@ -500,7 +500,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } ssh->connectState = CONNECT_KEYED; WLOG(WS_LOG_DEBUG, connectState, "KEYED"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_KEYED: if ( (ssh->error = SendServiceRequest(ssh, ID_SERVICE_USERAUTH)) < @@ -510,7 +510,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } ssh->connectState = CONNECT_CLIENT_USERAUTH_REQUEST_SENT; WLOG(WS_LOG_DEBUG, connectState, "CLIENT_USERAUTH_REQUEST_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_CLIENT_USERAUTH_REQUEST_SENT: while (ssh->serverState < SERVER_USERAUTH_REQUEST_DONE) { @@ -522,7 +522,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } ssh->connectState = CONNECT_SERVER_USERAUTH_REQUEST_DONE; WLOG(WS_LOG_DEBUG, connectState, "SERVER_USERAUTH_REQUEST_DONE"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_SERVER_USERAUTH_REQUEST_DONE: if ( (ssh->error = SendUserAuthRequest(ssh, ID_NONE)) < @@ -533,7 +533,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } ssh->connectState = CONNECT_CLIENT_USERAUTH_SENT; WLOG(WS_LOG_DEBUG, connectState, "CLIENT_USERAUTH_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_CLIENT_USERAUTH_SENT: while (ssh->serverState < SERVER_USERAUTH_ACCEPT_DONE) { @@ -545,7 +545,7 @@ int wolfSSH_connect(WOLFSSH* ssh) } ssh->connectState = CONNECT_SERVER_USERAUTH_ACCEPT_DONE; WLOG(WS_LOG_DEBUG, connectState, "SERVER_USERAUTH_ACCEPT_DONE"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_SERVER_USERAUTH_ACCEPT_DONE: if ( (ssh->error = SendChannelOpenSession(ssh, DEFAULT_WINDOW_SZ, @@ -557,7 +557,7 @@ int wolfSSH_connect(WOLFSSH* ssh) ssh->connectState = CONNECT_CLIENT_CHANNEL_OPEN_SESSION_SENT; WLOG(WS_LOG_DEBUG, connectState, "CLIENT_CHANNEL_OPEN_SESSION_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_CLIENT_CHANNEL_OPEN_SESSION_SENT: while (ssh->serverState < SERVER_CHANNEL_OPEN_DONE) { @@ -570,7 +570,7 @@ int wolfSSH_connect(WOLFSSH* ssh) ssh->connectState = CONNECT_SERVER_CHANNEL_OPEN_SESSION_DONE; WLOG(WS_LOG_DEBUG, connectState, "SERVER_CHANNEL_OPEN_SESSION_DONE"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_SERVER_CHANNEL_OPEN_SESSION_DONE: if ( (ssh->error = SendChannelRequest(ssh, ssh->channelName, @@ -582,7 +582,7 @@ int wolfSSH_connect(WOLFSSH* ssh) ssh->connectState = CONNECT_CLIENT_CHANNEL_REQUEST_SENT; WLOG(WS_LOG_DEBUG, connectState, "CLIENT_CHANNEL_REQUEST_SENT"); - FALL_THROUGH; + FALL_THROUGH /* no break */ case CONNECT_CLIENT_CHANNEL_REQUEST_SENT: while (ssh->serverState < SERVER_DONE) { diff --git a/src/wolfscp.c b/src/wolfscp.c index 7735fa1d..bd4edb7b 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -1155,7 +1155,7 @@ int ReceiveScpMessage(WOLFSSH* ssh) switch (buf[0]) { case 'C': - FALL_THROUGH; + FALL_THROUGH /* no break */ case 'D': if (buf[0] == 'C') { @@ -1255,7 +1255,7 @@ int SendScpConfirmation(WOLFSSH* ssh) case WS_SCP_CONTINUE: /* default to ok confirmation */ - FALL_THROUGH; + FALL_THROUGH /* no break */ default: msg[0] = SCP_CONFIRM_OK; @@ -1307,9 +1307,9 @@ int ReceiveScpConfirmation(WOLFSSH* ssh) case SCP_CONFIRM_OK: break; case SCP_CONFIRM_ERR: - FALL_THROUGH; + FALL_THROUGH /* no break */ case SCP_CONFIRM_FATAL: - FALL_THROUGH; + FALL_THROUGH /* no break */ default: WLOG(WS_LOG_ERROR, "scp error: peer sent error confirmation (code: %d)", diff --git a/src/wolfsftp.c b/src/wolfsftp.c index 9495678f..63ec9277 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -41,6 +41,7 @@ static int SFTP_ParseAtributes_buffer(WOLFSSH* ssh, WS_SFTP_FILEATRB* atr, byte* buf, word32 bufSz); static int SFTP_GetAttributes(const char* fileName, WS_SFTP_FILEATRB* atr, byte link); +static int SFTP_GetAttributes_Handle(byte* handle, int handleSz, WS_SFTP_FILEATRB* atr); static WS_SFTPNAME* wolfSSH_SFTPNAME_new(void* heap); /* Gets packet header information @@ -199,7 +200,7 @@ int wolfSSH_SFTP_accept(WOLFSSH* ssh) return WS_FATAL_ERROR; } ssh->connectState = SFTP_RECV; - FALL_THROUGH + FALL_THROUGH /* no break */ case SFTP_RECV: if ((ssh->error = SFTP_ServerSendInit(ssh)) != WS_SUCCESS) { @@ -305,7 +306,6 @@ static int SFTP_SetAtributes(WOLFSSH* ssh, byte* buf, word32 bufSz, } - /* cleans up absolute path */ static void clean_path(char* path) { @@ -313,31 +313,31 @@ static void clean_path(char* path) long sz = (long)WSTRLEN(path); byte found; - /* remove any double '/' chars */ +#ifdef WOLFSSL_NUCLEUS for (i = 0; i < sz; i++) { - if (path[i] == '/' && path[i+1] == '/') { + if (path[i] == '/') path[i] = '\\'; + } +#endif + + /* remove any ./ patterns */ + for (i = 1; i < sz - 1; i++) { + if (path[i] == '.' && path[i - 1] != '.' && path[i + 1] == WS_DELIM) { + WMEMMOVE(path + i, path + i + 1, sz - i - 1); + path[sz - 1] = '\0'; + i--; + } + } + sz = (int)WSTRLEN(path); + + /* remove any double '/' or '\' chars */ + for (i = 0; i < sz; i++) { + if ((path[i] == WS_DELIM && path[i+1] == WS_DELIM)) { WMEMMOVE(path + i, path + i + 1, sz - i + 1); sz -= 1; i--; } } - /* remove any trailing '.' and '/' chars */ - sz = WSTRLEN(path); - do { - i = (int)sz - 1; - if (i > 0 && path[i] == '.' && path[i-1] == '.') { - break; - } - - if (path[i] == '.' || path[i] == '/') { - path[i] = '\0'; - - } - sz = WSTRLEN(path); - } while ((int)sz - 1 > 0 && - (path[(int)sz - 1] == '.' || path[(int)sz - 1] == '/')); - if (path != NULL) { /* go through path until no cases are found */ do { @@ -346,8 +346,8 @@ static void clean_path(char* path) int enIdx = 0; /* end of cut */ found = 0; - for (i = 0; i < sz; i++) { - if (path[i] == '/') { + for (i = 1; i < sz; i++) { + if (path[i] == WS_DELIM) { int z; /* if next two chars are .. then delete */ @@ -356,7 +356,7 @@ static void clean_path(char* path) /* start at one char before / and retrace path */ for (z = i - 1; z > 0; z--) { - if (path[z] == '/') { + if (path[z] == WS_DELIM || path[z] == ':') { prIdx = z; break; } @@ -382,6 +382,35 @@ static void clean_path(char* path) } } } while (found); + +#ifdef WOLFSSL_NUCLEUS + sz = WSTRLEN(path); + if (path[sz - 1] == ':') { + path[sz] = WS_DELIM; + path[sz + 1] = '\0'; + } + + /* clean up any multiple drive listed i.e. A:/A: */ + { + int i,j; + sz = WSTRLEN(path); + for (i = 0, j = 0; i < sz; i++) { + if (path[i] == ':') { + if (j == 0) j = i; + else { + /* @TODO only checking once */ + WMEMMOVE(path, path + i - WS_DRIVE_SIZE, sz - i + WS_DRIVE_SIZE); + path[sz - i + WS_DRIVE_SIZE] = '\0'; + break; + } + } + } + } +#endif + /* remove trailing delimiter */ + if (sz > 3 && path[sz - 1] == WS_DELIM) { + path[sz - 1] = '\0'; + } } } @@ -394,6 +423,7 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, int maxSz) char r[WOLFSSH_MAX_FILENAME]; word32 rSz; word32 idx = 0; + word32 i; byte* out; WLOG(WS_LOG_SFTP, "Receiving WOLFSSH_FTP_REALPATH"); @@ -414,7 +444,7 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, int maxSz) } ato32((byte*)dir, &rSz); - if (rSz > WOLFSSH_MAX_FILENAME) { + if (rSz > WOLFSSH_MAX_FILENAME || (int)(rSz + UINT32_SZ) > maxSz) { WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); return WS_BUFFER_E; } @@ -423,7 +453,7 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, int maxSz) WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); /* get working directory in the case of receiving non absolute path */ - if (r[0] != '/') { + if (r[0] != '/' && r[1] != ':') { char wd[WOLFSSH_MAX_FILENAME]; if (WGETCWD(wd, WOLFSSH_MAX_FILENAME) == NULL) { @@ -436,8 +466,14 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, int maxSz) WSTRNCAT(wd, r, WOLFSSH_MAX_FILENAME - 1); WMEMCPY(r, wd, WOLFSSH_MAX_FILENAME); } + clean_path(r); rSz = (int)WSTRLEN(r); + + /* for real path always send '/' chars */ + for (i = 0; i < rSz; i++) { + if (r[i] == WS_DELIM) r[i] = '/'; + } WLOG(WS_LOG_SFTP, "Real Path Directory = %s", r); /* send response */ @@ -514,6 +550,9 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh) case WOLFSSH_FTP_LSTAT: return wolfSSH_SFTP_RecvLSTAT(ssh, reqId, maxSz); + case WOLFSSH_FTP_FSTAT: + return wolfSSH_SFTP_RecvFSTAT(ssh, reqId, maxSz); + case WOLFSSH_FTP_OPEN: return wolfSSH_SFTP_RecvOpen(ssh, reqId, maxSz); @@ -544,7 +583,7 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh) /* read rest of data off the wire and send error status to client */ { byte* data; - WLOG(WS_LOG_SFTP, "Unknown packet type received"); + WLOG(WS_LOG_SFTP, "Unknown packet type [%d] received", type); data = (byte*)WMALLOC(maxSz, ssh->ctx->heap, DYNTYPE_BUFFER); if (data != NULL) { wolfSSH_stream_read(ssh, data, maxSz); @@ -605,6 +644,11 @@ int wolfSSH_SFTP_SendStatus(WOLFSSH* ssh, word32 status, word32 reqId, c32toa(status, buf + idx); idx += UINT32_SZ; sz = (reason != NULL)? (int)WSTRLEN(reason): 0; + if (sz + idx + UINT32_SZ > maxSz) { + WFREE(buf, ssh->heap, DYNTYPE_BUFFER); + return WS_BUFFER_E; + } + c32toa(sz, buf + idx); idx += UINT32_SZ; if (reason != NULL) { WMEMCPY(buf + idx, reason, sz); idx += sz; @@ -612,6 +656,11 @@ int wolfSSH_SFTP_SendStatus(WOLFSSH* ssh, word32 status, word32 reqId, sz = (lang != NULL)? (int)WSTRLEN(lang): 0; + if (sz + idx + UINT32_SZ > maxSz) { + WFREE(buf, ssh->heap, DYNTYPE_BUFFER); + return WS_BUFFER_E; + } + c32toa(sz, buf + idx); idx += UINT32_SZ; if (lang != NULL) { WMEMCPY(buf + idx, lang, sz); @@ -666,6 +715,7 @@ int wolfSSH_SFTP_RecvRMDIR(WOLFSSH* ssh, int reqId, word32 maxSz) WMEMCPY(dir, data + idx, sz); dir[sz] = '\0'; + clean_path(dir); ret = WRMDIR(dir); WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); @@ -696,7 +746,7 @@ int wolfSSH_SFTP_RecvMKDIR(WOLFSSH* ssh, int reqId, word32 maxSz) int ret; byte* data; char* dir; - word32 mode; + word32 mode = 0; word32 idx = 0; if (ssh == NULL) { @@ -730,11 +780,12 @@ int wolfSSH_SFTP_RecvMKDIR(WOLFSSH* ssh, int reqId, word32 maxSz) ato32(data + idx, &sz); idx += UINT32_SZ; if (sz != UINT32_SZ) { WLOG(WS_LOG_SFTP, "Attribute size larger than 4 not yet supported"); - WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); - WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); - return WS_FATAL_ERROR; + WLOG(WS_LOG_SFTP, "Skipping over attribute"); } - ato32(data + idx, &mode); + else { + ato32(data + idx, &mode); + } + clean_path(dir); ret = WMKDIR(dir, mode); WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); @@ -811,28 +862,28 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, word32 maxSz) WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); if ((reason & WOLFSSH_FXF_READ) && (reason & WOLFSSH_FXF_WRITE)) { - m |= O_RDWR; + m |= WOLFSSH_O_RDWR; } else { if (reason & WOLFSSH_FXF_READ) { - m |= O_RDONLY; + m |= WOLFSSH_O_RDONLY; } if (reason & WOLFSSH_FXF_WRITE) { - m |= O_WRONLY; + m |= WOLFSSH_O_WRONLY; } } if (reason & WOLFSSH_FXF_APPEND) { - m |= O_APPEND; + m |= WOLFSSH_O_APPEND; } if (reason & WOLFSSH_FXF_CREAT) { - m |= O_CREAT; + m |= WOLFSSH_O_CREAT; } if (reason & WOLFSSH_FXF_TRUNC) { - m |= O_TRUNC; + m |= WOLFSSH_O_TRUNC; } if (reason & WOLFSSH_FXF_EXCL) { - m |= O_EXCL; + m |= WOLFSSH_O_EXCL; } /* if file permissions not set then use default */ @@ -840,6 +891,7 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, word32 maxSz) atr.per = 0644; } + clean_path(dir); fd = WOPEN(dir, m, atr.per); if (fd < 0) { WLOG(WS_LOG_SFTP, "Error opening file %s", dir); @@ -849,6 +901,15 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, word32 maxSz) return WS_BAD_FILE_E; } +#ifdef WOLFSSH_STOREHANDLE + if (SFTP_AddHandleNode(ssh, (byte*)&fd, sizeof(WFD), dir) != WS_SUCCESS) { + WLOG(WS_LOG_SFTP, "Unable to store handle"); + WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); + wolfSSH_SFTP_SendStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, + "Internal Failure", "English"); + return WS_FATAL_ERROR; + } +#endif WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); SendPacketType(ssh, WOLFSSH_FTP_HANDLE, (byte*)&fd, sizeof(WFD)); @@ -862,6 +923,7 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, word32 maxSz) /* hold pointers to directory handles */ typedef struct DIR_HANDLE { WDIR dir; + byte isEof; /* flag for if read everything */ word64 id; /* handle ID */ struct DIR_HANDLE* next; } DIR_HANDLE; @@ -917,10 +979,14 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, word32 maxSz) WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); /* get directory handle */ - ctx = WOPENDIR(dir); - if (ctx == NULL) { + clean_path(dir); + if (WOPENDIR(&ctx, dir) != 0) { + WLOG(WS_LOG_SFTP, "Error with opening directory"); WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); - return WS_FATAL_ERROR; + + wolfSSH_SFTP_SendStatus(ssh, WOLFSSH_FTP_NOFILE, reqId, + "Unable To Open Directory", "English"); + return WS_BAD_FILE_E; } WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); @@ -933,9 +999,14 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, word32 maxSz) if (dirList == NULL) { return WS_MEMORY_E; } +#ifdef WOLFSSL_NUCLEUS + WMEMCPY(&dirList->dir, &ctx, sizeof(WDIR)); +#else dirList->dir = ctx; - dirList->id = idCount++; - dirList->next = NULL; +#endif + dirList->id = idCount++; + dirList->isEof = 0; + dirList->next = NULL; SendPacketType(ssh, WOLFSSH_FTP_HANDLE, (byte*)&dirList->id, sizeof(word64)); } @@ -945,10 +1016,15 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, word32 maxSz) if (cur == NULL) { return WS_MEMORY_E; } +#ifdef WOLFSSL_NUCLEUS + WMEMCPY(&cur->dir, &ctx, sizeof(WDIR)); +#else cur->dir = ctx; - cur->id = idCount++; - cur->next = dirList; - dirList = cur; +#endif + cur->id = idCount++; + cur->isEof = 0; + cur->next = dirList; + dirList = cur; SendPacketType(ssh, WOLFSSH_FTP_HANDLE, (byte*)&cur->id, sizeof(word64)); } @@ -957,12 +1033,54 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, word32 maxSz) } +#ifdef WOLFSSL_NUCLEUS +/* For Nucleus port + * helper function that gets file information from reading directory + * @TODO allow user to override + * + * returns WS_SUCCESS on success + */ +static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out) +{ + int sz; + + if (dir == NULL || ssh == NULL || out == NULL) { + return WS_BAD_ARGUMENT; + } + + sz = (int)WSTRLEN(dir->sfname); + out->fName = (char*)WMALLOC(sz + 1, out->heap, DYNTYPE_SFTP); + if (out->fName == NULL) { + return WS_MEMORY_E; + } + WMEMCPY(out->fName, dir->sfname, sz); + out->fName[sz] = '\0'; + out->fSz = sz; + + sz = (int)WSTRLEN(dir->lfname); + out->lName = (char*)WMALLOC(sz + 1, out->heap, DYNTYPE_SFTP); + if (out ->lName == NULL) { + return WS_MEMORY_E; + } + WMEMCPY(out->lName, dir->lfname, sz); + out->lName[sz] = '\0'; + out->lSz = sz; + + SFTP_GetAttributes(out->fName, &out->atrb, 0); + + if ((WREADDIR(dir)) == NULL) { + return WS_NEXT_ERROR; + } + + return WS_SUCCESS; +} +#else /* helper function that gets file information from reading directory * @TODO allow user to override * * returns WS_SUCCESS on success */ -static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR dir, WS_SFTPNAME* out) +static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out) { struct dirent* dp; int sz; @@ -971,7 +1089,7 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR dir, WS_SFTPNAME* out) return WS_BAD_ARGUMENT; } - dp = WREADDIR(dir); + dp = WREADDIR(*dir); if (dp == NULL) { return WS_FATAL_ERROR; } @@ -983,6 +1101,7 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR dir, WS_SFTPNAME* out) } out->lName = (char*)WMALLOC(sz + 1, out->heap, DYNTYPE_SFTP); if (out ->lName == NULL) { + WFREE(out->fName, out->heap, DYNTYPE_SFTP); return WS_MEMORY_E; } @@ -1000,6 +1119,7 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR dir, WS_SFTPNAME* out) return WS_SUCCESS; } +#endif /* helper function to create a name packet. out buffer will have the following @@ -1033,6 +1153,11 @@ static int wolfSSH_SFTP_SendName(WOLFSSH* ssh, WS_SFTPNAME* list, word32 count, c32toa(count, out + idx); idx += UINT32_SZ; for (i = 0; i < count && cur != NULL; i++) { + if (*outSz - idx < cur->fSz + cur->lSz + UINT32_SZ * 2) { + /* not enough space for the buffer */ + return WS_FATAL_ERROR; + } + c32toa(cur->fSz, out + idx); idx += UINT32_SZ; WMEMCPY(out + idx, cur->fName, cur->fSz); idx += cur->fSz; c32toa(cur->lSz, out + idx); idx += UINT32_SZ; @@ -1067,6 +1192,7 @@ int wolfSSH_SFTP_RecvReadDir(WOLFSSH* ssh, int reqId, word32 maxSz) WS_SFTPNAME* name = NULL; WS_SFTPNAME* list = NULL; word32 outSz = 0; + DIR_HANDLE* cur = dirList; if (ssh == NULL) { return WS_BAD_ARGUMENT; @@ -1089,19 +1215,16 @@ int wolfSSH_SFTP_RecvReadDir(WOLFSSH* ssh, int reqId, word32 maxSz) WMEMCPY((byte*)&handle, data + idx, sz); /* find DIR given handle */ - { - DIR_HANDLE* cur = dirList; - while (cur != NULL) { - if (cur->id == handle) { - dir = cur->dir; - break; - } - cur = cur->next; - } - if (cur == NULL) { - /* unable to find handle */ - return WS_FATAL_ERROR; + while (cur != NULL) { + if (cur->id == handle) { + dir = cur->dir; + break; } + cur = cur->next; + } + if (cur == NULL) { + /* unable to find handle */ + return WS_FATAL_ERROR; } /* this closes the directory before returning */ @@ -1111,8 +1234,8 @@ int wolfSSH_SFTP_RecvReadDir(WOLFSSH* ssh, int reqId, word32 maxSz) outSz += UINT32_SZ + WOLFSSH_SFTP_HEADER; /* hold header+number of files */ do { name = wolfSSH_SFTPNAME_new(ssh->ctx->heap); - ret = wolfSSH_SFTPNAME_readdir(ssh, dir, name); - if (ret == WS_SUCCESS) { + ret = wolfSSH_SFTPNAME_readdir(ssh, &dir, name); + if (ret == WS_SUCCESS || ret == WS_NEXT_ERROR) { count++; outSz += name->fSz + name->lSz + (UINT32_SZ * 2); outSz += SFTP_AtributesSz(ssh, &name->atrb); @@ -1130,12 +1253,18 @@ int wolfSSH_SFTP_RecvReadDir(WOLFSSH* ssh, int reqId, word32 maxSz) } while (ret == WS_SUCCESS); WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); - if (list == NULL) { + if (list == NULL || cur->isEof) { wolfSSH_SFTP_SendStatus(ssh, WOLFSSH_FTP_EOF, reqId, "No More Files In Directory", "English"); return WS_SUCCESS; } + /* if next state would cause an error then set EOF flag for when called + * again */ + if (ret == WS_NEXT_ERROR) { + cur->isEof = 1; + } + data = (byte*)WMALLOC(outSz, ssh->ctx->heap, DYNTYPE_BUFFER); if (data == NULL) { return WS_MEMORY_E; @@ -1161,7 +1290,11 @@ int wolfSSH_SFTP_RecvReadDir(WOLFSSH* ssh, int reqId, word32 maxSz) int wolfSSH_SFTP_RecvCloseDir(WOLFSSH* ssh, byte* handle, word32 handleSz) { DIR_HANDLE* cur = dirList; +#ifdef WOLFSSL_NUCLEUS + WDIR* dir = NULL; +#else WDIR dir = NULL; +#endif if (ssh == NULL || handle == NULL || handleSz != sizeof(word64)) { return WS_BAD_ARGUMENT; @@ -1172,7 +1305,11 @@ int wolfSSH_SFTP_RecvCloseDir(WOLFSSH* ssh, byte* handle, word32 handleSz) /* find DIR given handle */ while (cur != NULL) { if (cur->id == *((word64*)handle)) { +#ifdef WOLFSSL_NUCLEUS + dir = &cur->dir; +#else dir = cur->dir; +#endif break; } cur = cur->next; @@ -1188,7 +1325,8 @@ int wolfSSH_SFTP_RecvCloseDir(WOLFSSH* ssh, byte* handle, word32 handleSz) if (cur != NULL) { DIR_HANDLE* pre = dirList; - WLOG(WS_LOG_SFTP, "Free'ing and closing handle %ld pointer of [%p]", cur->id, cur); + WLOG(WS_LOG_SFTP, "Free'ing and closing handle %ld pointer of [%p]", + (long)cur->id, cur); /* case where node is at head of list */ if (pre == cur) { dirList = cur->next; @@ -1235,7 +1373,6 @@ int wolfSSH_SFTP_RecvWrite(WOLFSSH* ssh, int reqId, word32 maxSz) return WS_MEMORY_E; } - /* @TODO check for infinite loop */ sz = 0; do { ret = wolfSSH_stream_read(ssh, data + sz, maxSz - sz); @@ -1243,6 +1380,10 @@ int wolfSSH_SFTP_RecvWrite(WOLFSSH* ssh, int reqId, word32 maxSz) sz += ret; } } while (sz < maxSz && ret > 0); + if (ret < 0) { + WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + return ret; + } /* get file handle */ ato32(data + idx, &sz); idx += UINT32_SZ; @@ -1268,6 +1409,11 @@ int wolfSSH_SFTP_RecvWrite(WOLFSSH* ssh, int reqId, word32 maxSz) ret = (int)WPWRITE(fd, data + idx, sz, ofst); WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); if (ret < 0) { +#if defined(WOLFSSL_NUCLEUS) && defined(DEBUG_WOLFSSH) + if (ret == NUF_NOSPC) { + WLOG(WS_LOG_SFTP, "Ran out of memory"); + } +#endif WLOG(WS_LOG_SFTP, "Error writing to file"); wolfSSH_SFTP_SendStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, "Write File Error", "English"); @@ -1303,7 +1449,10 @@ int wolfSSH_SFTP_RecvRead(WOLFSSH* ssh, int reqId, word32 maxSz) if (data == NULL) { return WS_MEMORY_E; } - wolfSSH_stream_read(ssh, data, maxSz); + if ((ret = wolfSSH_stream_read(ssh, data, maxSz)) < 0) { + WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + return ret; + } /* get file handle */ ato32(data + idx, &sz); idx += UINT32_SZ; @@ -1378,7 +1527,10 @@ int wolfSSH_SFTP_RecvClose(WOLFSSH* ssh, int reqId, word32 maxSz) if (data == NULL) { return WS_MEMORY_E; } - wolfSSH_stream_read(ssh, data, maxSz); + if ((ret = wolfSSH_stream_read(ssh, data, maxSz)) < 0) { + WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + return ret; + } /* get file handle */ ato32(data + idx, &sz); idx += UINT32_SZ; @@ -1398,6 +1550,12 @@ int wolfSSH_SFTP_RecvClose(WOLFSSH* ssh, int reqId, word32 maxSz) WMEMSET((byte*)&fd, 0, sizeof(WFD)); WMEMCPY((byte*)&fd, data + idx, sz); ret = WCLOSE(fd); + #ifdef WOLFSSH_STOREHANDLE + if (SFTP_RemoveHandleNode(ssh, data + idx, sz) != WS_SUCCESS) { + WLOG(WS_LOG_SFTP, "Unable to remove handle from list"); + ret = WS_FATAL_ERROR; + } + #endif } else { ret = WS_FATAL_ERROR; @@ -1446,9 +1604,6 @@ int wolfSSH_SFTP_RecvRemove(WOLFSSH* ssh, int reqId, word32 maxSz) WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); return ret; } - else { - ret = WS_SUCCESS; - } /* get file name */ ato32(data + idx, &sz); idx += UINT32_SZ; @@ -1465,9 +1620,23 @@ int wolfSSH_SFTP_RecvRemove(WOLFSSH* ssh, int reqId, word32 maxSz) name[sz] = '\0'; WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); - if (WREMOVE(name) < 0) { + clean_path(name); + if ((ret = WREMOVE(name)) < 0) { WLOG(WS_LOG_SFTP, "Error removing file"); - ret = WS_FATAL_ERROR; + #if defined(WOLFSSL_NUCLEUS) && defined(DEBUG_WOLFSSH) + if (ret == NUF_ACCES) + WLOG(WS_LOG_SFTP, "access error"); + if (ret == NUF_BAD_USER) + WLOG(WS_LOG_SFTP, "bad user"); + if (ret == NUF_IO_ERROR) + WLOG(WS_LOG_SFTP, "io error"); + if (ret == NUF_NOFILE) + WLOG(WS_LOG_SFTP, "%s file not found", name); + #endif + ret = WS_BAD_FILE_E; + } + else { + ret = WS_SUCCESS; } /* Let the client know the results from trying to remove the file */ @@ -1547,6 +1716,8 @@ int wolfSSH_SFTP_RecvRename(WOLFSSH* ssh, int reqId, word32 maxSz) } WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + clean_path(old); + clean_path(nw); if (ret == WS_SUCCESS && WRENAME(old, nw) < 0) { WLOG(WS_LOG_SFTP, "Error renaming file"); ret = WS_BAD_FILE_E; @@ -1568,6 +1739,233 @@ int wolfSSH_SFTP_RecvRename(WOLFSSH* ssh, int reqId, word32 maxSz) } +#ifdef WOLFSSH_STOREHANDLE +/* some systems do not have a fstat function to allow for attribute lookup given + * a file descriptor. In those cases we keep track of an internal list matching + * handles to file names */ + +typedef struct WS_HANDLE_LIST { + byte handle[WOLFSSH_MAX_HANDLE]; + word32 handleSz; + char name[WOLFSSH_MAX_FILENAME]; + struct WS_HANDLE_LIST* next; + struct WS_HANDLE_LIST* prev; +} WS_HANDLE_LIST; +static WS_HANDLE_LIST* handleList = NULL; + + +/* get a handle node from the list + * returns WS_HANDLE_LIST pointer on success and NULL on failure */ +static WS_HANDLE_LIST* SFTP_GetHandleNode(byte* handle, word32 handleSz) +{ + WS_HANDLE_LIST* cur = handleList; + + if (handle == NULL) { + return NULL; + } + + /* for Nucleus need to find name from handle */ + while (cur != NULL) { + if(handleSz == cur->handleSz && WMEMCMP(handle, cur->handle, handleSz) == 0) { + break; /* found handle */ + } + cur = cur->next; + } + + return cur; +} + + +/* add a name and handle to the handle list + * return WS_SUCCESS on success */ +int SFTP_AddHandleNode(WOLFSSH* ssh, byte* handle, word32 handleSz, char* name) +{ + WS_HANDLE_LIST* cur; + int sz; + + if (handle == NULL || name == NULL) { + return WS_BAD_ARGUMENT; + } + + cur = (WS_HANDLE_LIST*)WMALLOC(sizeof(WS_HANDLE_LIST), ssh->ctx->heap, + DYNTYPE_SFTP); + if (cur == NULL) { + return WS_MEMORY_E; + } + + WMEMCPY(cur->handle, handle, handleSz); + cur->handleSz = handleSz; + + sz = (int)WSTRLEN(name); + if (sz + 1 >= WOLFSSH_MAX_FILENAME) { + WFREE(cur, ssh->ctx->heap, DYNTYPE_SFTP); + return WS_BUFFER_E; + } + WMEMCPY(cur->name, name, sz); + cur->name[sz] = '\0'; + + cur->prev = NULL; + cur->next = handleList; + if (handleList != NULL) { + handleList->prev = cur; + } + handleList = cur; + + return WS_SUCCESS; +} + + +/* remove a handle node from the list + * returns WS_SUCCESS on success */ +int SFTP_RemoveHandleNode(WOLFSSH* ssh, byte* handle, word32 handleSz) +{ + WS_HANDLE_LIST* cur; + + if (ssh == NULL || handle == NULL) { + return WS_BAD_ARGUMENT; + } + + cur = SFTP_GetHandleNode(handle, handleSz); + if (cur == NULL) { + WLOG(WS_LOG_SFTP, "Fatal Error! Trying to remove a handle that was not in the list"); + return WS_FATAL_ERROR; + } + + if (cur->next != NULL) { + cur->next->prev = cur->prev; + } + + if (cur->prev != NULL) { + cur->prev->next = cur->next; + } + + if (cur->next == NULL && cur->prev == NULL) { + handleList = NULL; + } + + WFREE(cur, ssh->ctx->heap, DYNTYPE_SFTP); + + return WS_SUCCESS; +} +#endif /* WOLFSSH_STOREHANDLE */ + + +#ifdef WOLFSSL_NUCLEUS +/* @TODO can be overriden by user for portability + * NOTE: if atr->flags is set to a value of 0 then no attributes are set. + * Fills out a WS_SFTP_FILEATRB structure + * returns WS_SUCCESS on success + */ +int SFTP_GetAttributes(const char* fileName, WS_SFTP_FILEATRB* atr, byte link) +{ + DSTAT stats; + int sz = (int)WSTRLEN(fileName); + int ret; + + if (link) { + ret = WLSTAT(fileName, &stats); + } + else { + ret = WSTAT(fileName, &stats); + } + + WMEMSET(atr, 0, sizeof(WS_SFTP_FILEATRB)); + if (sz > 2 && fileName[sz - 2] == ':' && ret == NUF_NOFILE) { + atr->flags |= WOLFSSH_FILEATRB_PERM; + atr->per |= 0x4000; + return WS_SUCCESS; + } + + if (ret != NU_SUCCESS) { + return WS_BAD_FILE_E; + } + + atr->flags |= WOLFSSH_FILEATRB_SIZE; + atr->sz = (word64)stats.fsize; + + /* get additional attributes */ + { + byte atrib = 0; + if (NU_Get_Attributes(&atrib, fileName) == NU_SUCCESS) { + atr->flags |= WOLFSSH_FILEATRB_PERM; + if (atrib & ADIRENT) { + atr->per |= 0x4000; + } + else { + atr->per |= 0x8000; + } + if (atrib & ANORMAL) { + atr->per |= 0x755; + } + if (atrib & ARDONLY) { + atr->per |= 0x444; + } + } + } + + /* @TODO handle attribute extensions */ + + NU_Done(&stats); + return WS_SUCCESS; +} + + +/* @TODO can be overriden by user for portability + * Gets attributes based on file descriptor + * NOTE: if atr->flags is set to a value of 0 then no attributes are set. + * Fills out a WS_SFTP_FILEATRB structure + * returns WS_SUCCESS on success + */ +int SFTP_GetAttributes_Handle(byte* handle, int handleSz, WS_SFTP_FILEATRB* atr) +{ + DSTAT stats; + WS_HANDLE_LIST* cur; + + if (handle == NULL || atr == NULL) { + return WS_FATAL_ERROR; + } + + cur = SFTP_GetHandleNode(handle, handleSz); + if (cur == NULL) { + WLOG(WS_LOG_SFTP, "Unknown handle"); + return WS_BAD_FILE_E; + } + + if (WSTAT(cur->name, &stats) != NU_SUCCESS) { + return WS_FATAL_ERROR; + } + + WMEMSET(atr, 0, sizeof(WS_SFTP_FILEATRB)); + + atr->flags |= WOLFSSH_FILEATRB_SIZE; + atr->sz = (word64)stats.fsize; + + { + byte atrib = 0; + if (NU_Get_Attributes(&atrib, cur->name) == NU_SUCCESS) { + atr->flags |= WOLFSSH_FILEATRB_PERM; + if (atrib & ADIRENT) { + atr->per |= 0x4000; + } + else { + atr->per |= 0x8000; + } + if (atrib & ANORMAL) { + atr->per |= 0x755; + } + + if (atrib & ARDONLY) { + atr->per |= 0x444; + } + } + } + /* @TODO handle attribute extensions */ + + NU_Done(&stats); + return WS_SUCCESS; +} +#else + /* @TODO can be overriden by user for portability * NOTE: if atr->flags is set to a value of 0 then no attributes are set. * Fills out a WS_SFTP_FILEATRB structure @@ -1613,6 +2011,114 @@ int SFTP_GetAttributes(const char* fileName, WS_SFTP_FILEATRB* atr, byte link) } +/* @TODO can be overriden by user for portability + * Gets attributes based on file descriptor + * NOTE: if atr->flags is set to a value of 0 then no attributes are set. + * Fills out a WS_SFTP_FILEATRB structure + * returns WS_SUCCESS on success + */ +int SFTP_GetAttributes_Handle(byte* handle, int handleSz, WS_SFTP_FILEATRB* atr) +{ + struct stat stats; + + if (handleSz != sizeof(word32)) { + WLOG(WS_LOG_SFTP, "Unexpected handle size SFTP_GetAttributes_Handle()"); + } + + if (fstat(*(int*)handle, &stats) != 0) { + return WS_BAD_FILE_E; + } + + WMEMSET(atr, 0, sizeof(WS_SFTP_FILEATRB)); + + atr->flags |= WOLFSSH_FILEATRB_SIZE; + atr->sz = (word64)stats.st_size; + + atr->flags |= WOLFSSH_FILEATRB_UIDGID; + atr->uid = (word32)stats.st_uid; + atr->gid = (word32)stats.st_gid; + + atr->flags |= WOLFSSH_FILEATRB_PERM; + atr->per = (word32)stats.st_mode; + +#if 0 + /* @TODO porting time from stat structure */ + atr->flags |= WOLFSSH_FILEATRB_TIME; + atr->atime = (word32)stats.st_atimespec.tv_sec; + atr->mtime = (word32)stats.st_mtimespec.tv_sec; +#endif + + /* @TODO handle attribute extensions */ + + return WS_SUCCESS; +} +#endif + + +/* Handles receiving fstat packet + * returns WS_SUCCESS on success + */ +int wolfSSH_SFTP_RecvFSTAT(WOLFSSH* ssh, int reqId, word32 maxSz) +{ + WS_SFTP_FILEATRB atr; + word32 handleSz; + word32 sz; + byte* data; + byte* handle; + word32 idx = 0; + + if (ssh == NULL) { + return WS_BAD_ARGUMENT; + } + + WLOG(WS_LOG_SFTP, "Receiving WOLFSSH_FTP_FSTAT"); + + data = (byte*)WMALLOC(maxSz, ssh->ctx->heap, DYNTYPE_BUFFER); + if (data == NULL) { + return WS_MEMORY_E; + } + wolfSSH_stream_read(ssh, data, maxSz); + + ato32(data + idx, &handleSz); idx += UINT32_SZ; + if (handleSz + idx > maxSz) { + WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + return WS_BUFFER_E; + } + handle = data + idx; + + /* try to get file attributes and send back to client */ + WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB)); + if (SFTP_GetAttributes_Handle(handle, handleSz, &atr) != WS_SUCCESS) { + WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + WLOG(WS_LOG_SFTP, "Unable to get fstat of file/directory"); + wolfSSH_SFTP_SendStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, + "STAT error", "English"); + return WS_BAD_FILE_E; + } + WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + + sz = SFTP_AtributesSz(ssh, &atr); + data = (byte*)WMALLOC(sz + WOLFSSH_SFTP_HEADER, ssh->ctx->heap, + DYNTYPE_BUFFER); + if (data == NULL) { + return WS_MEMORY_E; + } + + if (SFTP_SetHeader(ssh, reqId, WOLFSSH_FTP_ATTRS, sz, data) != WS_SUCCESS) { + WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + return WS_FATAL_ERROR; + } + SFTP_SetAtributes(ssh, data + WOLFSSH_SFTP_HEADER, sz, &atr); + if (wolfSSH_stream_send(ssh, data, sz + WOLFSSH_SFTP_HEADER) < 0) { + WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + return WS_FATAL_ERROR; + } + WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + + return WS_SUCCESS; +} + + /* Handles receiving stat packet * returns WS_SUCCESS on success */ @@ -1654,6 +2160,7 @@ int wolfSSH_SFTP_RecvSTAT(WOLFSSH* ssh, int reqId, word32 maxSz) WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); /* try to get file attributes and send back to client */ + clean_path(name); WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB)); if (SFTP_GetAttributes(name, &atr, 0) != WS_SUCCESS) { WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER); @@ -1729,6 +2236,7 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, word32 maxSz) WMEMCPY(name, data + idx, sz); name[sz] = '\0'; WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); + clean_path(name); /* try to get file attributes and send back to client */ WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB)); @@ -1868,7 +2376,7 @@ int wolfSSH_SFTP_connect(WOLFSSH* ssh) return WS_FATAL_ERROR; } ssh->connectState = SFTP_RECV; - FALL_THROUGH + FALL_THROUGH /* no break */ case SFTP_RECV: if ((ssh->error = SFTP_ClientRecvInit(ssh)) != WS_SUCCESS) { @@ -3263,7 +3771,11 @@ int wolfSSH_SFTP_SaveOfst(WOLFSSH* ssh, char* frm, char* to, word64 ofst) return WS_MEMORY_E; } - /* @TODO sanity check before copy */ + if (frmSz > WOLFSSH_MAX_FILENAME || toSz > WOLFSSH_MAX_FILENAME) { + WLOG(WS_LOG_SFTP, "File name is too large"); + return WS_BUFFER_E; + } + current = &ssh->sftpOfst[idx]; WMEMCPY(current->from, frm, frmSz); current->from[frmSz] = '\0'; diff --git a/wolfssh/error.h b/wolfssh/error.h index eb14206e..b787ecd6 100644 --- a/wolfssh/error.h +++ b/wolfssh/error.h @@ -93,8 +93,9 @@ enum WS_ErrorCodes { WS_MATCH_MAC_ALGO_E = -53, /* cannot match MAC algo with peer */ WS_PERMISSIONS = -54, WS_SFTP_COMPLETE = -55, /* SFTP connection established */ + WS_NEXT_ERROR = -56, /* Getting next value/state results in error */ - WS_LAST_E = -55 /* Update this to indicate last error */ + WS_LAST_E = -56 /* Update this to indicate last error */ }; diff --git a/wolfssh/port.h b/wolfssh/port.h index d2d689fd..692a9782 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -53,6 +53,15 @@ extern "C" { #endif #ifndef NO_FILESYSTEM +#ifdef WOLFSSL_NUCLEUS + #define WFILE int + WOLFSSH_API int wfopen(WFILE**, const char*, const char*); + + #define WFOPEN(f,fn,m) wfopen((f),(fn),(m)) + #define WFCLOSE(f) NU_Close(*(f)) + #define WFWRITE(b,x,s,f) NU_Write(*(f),(const CHAR*)(b),(s)) + #define WFREAD(b,x,s,f) NU_Read(*(f),(CHAR*)(b),(s)) +#else #define WFILE FILE WOLFSSH_API int wfopen(WFILE**, const char*, const char*); @@ -76,7 +85,7 @@ extern "C" { #define WMKDIR(p,m) mkdir((p),(m)) #endif #endif - +#endif /* setup string handling */ #ifndef WSTRING_USER #include @@ -130,8 +139,153 @@ extern "C" { #define WLOCALTIME(c,r) (localtime_r((c),(r))!=NULL) #endif -#ifdef WOLFSSH_SFTP -#ifndef NO_WOLFSSH_SERVER +#if defined(WOLFSSH_SFTP) && !defined(NO_WOLFSSH_SERVER) +#ifdef WOLFSSL_NUCLEUS + #include "storage/nu_storage.h" + + #define WRMDIR(d) (NU_Remove_Dir((d)) == NU_SUCCESS)?0:1 + #define WMKDIR(d,m) (NU_Make_Dir((d)) == NU_SUCCESS)?0:1 + #define WSTAT(p,b) NU_Get_First((b),(p)) + #define WLSTAT(p,b) NU_Get_First((b),(p)) + #define WREMOVE(d) NU_Delete((d)) + #define WRENAME(o,n) NU_Rename((o),(n)) + #define WS_DELIM '\\' + +#ifndef WGETCWD + static inline char* wGetCwd(char* buf, unsigned int bufSz) + { + int ret; + MNT_LIST_S* list = NU_NULL; + + if (buf == NULL || bufSz < 3) { + return NULL; + } + + ret = NU_List_Mount(&list); + if (ret != NU_SUCCESS) { + return NULL; + } + + buf[0] = list->mnt_name[0]; + buf[1] = ':'; + buf[2] = '\0'; + + return buf; + } + #define WGETCWD(r,rSz) wGetCwd((r),(rSz)) +#endif + + #define WOLFSSH_O_RDWR PO_RDWR + #define WOLFSSH_O_RDONLY PO_RDONLY + #define WOLFSSH_O_WRONLY PO_WRONLY + #define WOLFSSH_O_APPEND PO_APPEND + #define WOLFSSH_O_CREAT PO_CREAT + #define WOLFSSH_O_TRUNC PO_TRUNC + #define WOLFSSH_O_EXCL PO_EXCL + + #define WFD int + +#ifndef WOPEN + static inline int wOpen(char* f, short flag, short mode) + { + /* @TODO could use PS_IWRITE only or PS_IREAD only? */ + return NU_Open(f, PO_TEXT | flag, (PS_IWRITE | PS_IREAD)); + } + + #define WOPEN(f,m,p) wOpen((f),(m),(p)) +#endif + + #define WCLOSE(fd) NU_Close((fd)) + +#ifndef WPWRITE + static inline int wPwrite(WFD fd, unsigned char* buf, unsigned int sz, long ofst) + { + if (ofst > 0) { + NU_Seek(fd, ofst, 0); + } + + return NU_Write(fd, (const CHAR*)buf, sz); + } + #define WPWRITE(fd,b,s,o) wPwrite((fd),(b),(s),(o)) +#endif + +#ifndef WPREAD + static inline int wPread(WFD fd, unsigned char* buf, unsigned int sz, long ofst) + { + if (ofst > 0) { + NU_Seek(fd, ofst, 0); + } + + return NU_Read(fd, (CHAR*)buf, sz); + } + #define WPREAD(fd,b,s,o) wPread((fd),(b),(s),(o)) +#endif + + #ifndef NO_WOLFSSL_DIR + #define WDIR DSTAT + +#ifndef WOPENDIR + static inline int wOpenDir(WDIR* d, char* dir) + { + int ret; + int idx = WSTRLEN(dir); + char tmp[256]; /* default max file name size */ + + if (idx < 3) { + return -1; + } + + memcpy(tmp, dir, idx); + if (tmp[idx - 1] == '.') { + tmp[idx - 1] = '*'; + } + else { + /* if opening a directory then make sure pattern '/' '*' is used */ + unsigned char atrib = 0; + if (NU_Get_Attributes(&atrib, dir) == NU_SUCCESS) { + if (atrib & ADIRENT) { + if (tmp[idx-1] != WS_DELIM) { + if (idx + 2 > sizeof(tmp)) { + /* not enough space */ + return -1; + } + tmp[idx++] = WS_DELIM; + tmp[idx++] = '*'; + } + } + } + } + + if (tmp[idx - 1] == WS_DELIM) { + if (idx + 1 > sizeof(tmp)) { + /* not enough space */ + return -1; + } + tmp[idx++] = '*'; + } + tmp[idx] = '\0'; + ret = NU_Get_First(d, tmp); + + /* if back to root directory i.e. A:/ then handle case + * where file system has nothing in it. */ + if (dir[idx - 3] == ':' && ret == NUF_NOFILE) { + memset(d, 0, sizeof(WDIR)); + ret = NU_SUCCESS; + } + + if (ret == NU_SUCCESS) { + return 0; + } + + return -1; + } + #define WOPENDIR(c,d) wOpenDir((c),(d)) +#endif + + #define WCLOSEDIR(d) NU_Done((d)) + #define WREADDIR(d) (NU_Get_Next((d)) == NU_SUCCESS)?(d):NULL + #endif /* NO_WOLFSSL_DIR */ +#else #include /* used for rmdir */ #include /* used for mkdir, stat, and lstat */ #include /* used for remove and rename */ @@ -143,9 +297,18 @@ extern "C" { #define WREMOVE(d) remove((d)) #define WRENAME(o,n) rename((o),(n)) #define WGETCWD(r,rSz) getcwd((r),(rSz)) + #define WS_DELIM '/' #include /* used for open, close, pwrite, and pread */ #define WFD int + #define WOLFSSH_O_RDWR O_RDWR + #define WOLFSSH_O_RDONLY O_RDONLY + #define WOLFSSH_O_WRONLY O_WRONLY + #define WOLFSSH_O_APPEND O_APPEND + #define WOLFSSH_O_CREAT O_CREAT + #define WOLFSSH_O_TRUNC O_TRUNC + #define WOLFSSH_O_EXCL O_EXCL + #define WOPEN(f,m,p) open((f),(m),(p)) #define WCLOSE(fd) close((fd)) #define WPWRITE(fd,b,s,o) pwrite((fd),(b),(s),(o)) @@ -154,7 +317,9 @@ extern "C" { #ifndef NO_WOLFSSL_DIR #include /* used for opendir, readdir, and closedir */ #define WDIR DIR* - #define WOPENDIR(d) opendir((d)) + + /* returns 0 on success */ + #define WOPENDIR(c,d) ((*(c) = opendir((d))) == NULL) #define WCLOSEDIR(d) closedir((d)) #define WREADDIR(d) readdir((d)) #endif /* NO_WOLFSSL_DIR */ diff --git a/wolfssh/settings.h b/wolfssh/settings.h index 38fffba1..0ed10519 100644 --- a/wolfssh/settings.h +++ b/wolfssh/settings.h @@ -49,6 +49,11 @@ extern "C" { #define USE_WINDOWS_API #endif +#ifdef WOLFSSL_NUCLEUS + #ifndef WOLFSSH_STOREHANDLE + #define WOLFSSH_STOREHANDLE + #endif +#endif #ifdef __cplusplus } diff --git a/wolfssh/test.h b/wolfssh/test.h index d8acccd9..ba68aa79 100644 --- a/wolfssh/test.h +++ b/wolfssh/test.h @@ -33,6 +33,22 @@ #endif #define socklen_t int #define NUM_SOCKETS 1 +#elif defined(WOLFSSL_NUCLEUS) + #include "nucleus.h" + #include "networking/nu_networking.h" + #define SOCKET_T int + #define socklen_t int + #define NUM_SOCKETS 1 + #define INADDR_ANY IP_ADDR_ANY + #define AF_INET NU_FAMILY_IP + #define SOCK_STREAM NU_TYPE_STREAM + + #define sin_addr id + #define s_addr is_ip_addrs + + #define sin_family family + #define sin_port port + #else /* USE_WINDOWS_API */ #include #include @@ -88,6 +104,9 @@ #define WCLOSESOCKET(s) closesocket((s)) #endif #define WSTARTTCP() +#elif defined(WOLFSSL_NUCLEUS) + #define WCLOSESOCKET(s) NU_Close_Socket((s)) + #define WSTARTTCP() #else #define WCLOSESOCKET(s) close(s) #define WSTARTTCP() @@ -105,6 +124,10 @@ #define WOLFSSH_THREAD #define INFINITE -1 #define WAIT_OBJECT_0 0L + #elif defined(WOLFSSL_NUCLEUS) + typedef unsigned int THREAD_RETURN; + typedef intptr_t THREAD_TYPE; + #define WOLFSSH_THREAD #else typedef unsigned int THREAD_RETURN; typedef intptr_t THREAD_TYPE; @@ -116,7 +139,9 @@ typedef struct sockaddr_in6 SOCKADDR_IN_T; #define AF_INET_V AF_INET6 #else - typedef struct sockaddr_in SOCKADDR_IN_T; + #ifndef WOLFSSL_NUCLEUS + typedef struct sockaddr_in SOCKADDR_IN_T; + #endif #define AF_INET_V AF_INET #endif @@ -179,8 +204,12 @@ void WaitTcpReady(func_args*); #else /* TEST_IPV6 */ static const char* const wolfSshIp = "::1"; #endif /* TEST_IPV6 */ -static const word16 wolfSshPort = 22222; - +#ifdef WOLFSSL_NUCLEUS + /* port 8080 was open with QEMU */ + static const word16 wolfSshPort = 8080; +#else + static const word16 wolfSshPort = 22222; +#endif #ifdef __GNUC__ #define WS_NORETURN __attribute__((noreturn)) @@ -283,6 +312,43 @@ static INLINE int mygetopt(int argc, char** argv, const char* optstring) * - 4996: deprecated function */ #endif +#ifdef WOLFSSL_NUCLEUS +static INLINE void build_addr(struct addr_struct* addr, const char* peer, + word16 port) +{ + int useLookup = 0; + (void)useLookup; + + memset(addr, 0, sizeof(struct addr_struct)); + +#ifndef TEST_IPV6 + /* peer could be in human readable form */ + if ( ((size_t)peer != INADDR_ANY) && isalpha((int)peer[0])) { + + NU_HOSTENT* entry; + NU_HOSTENT h; + entry = &h; + NU_Get_Host_By_Name((char*)peer, entry); + + if (entry) { + memcpy(&addr->id.is_ip_addrs, entry->h_addr_list[0], + entry->h_length); + useLookup = 1; + } + else + err_sys("no entry for host"); + } +#endif + +#ifndef TEST_IPV6 + addr->family = NU_FAMILY_IP; + addr->port = port; + + /* @TODO always setting any ip addr here */ + PUT32(addr->id.is_ip_addrs, 0, IP_ADDR_ANY); +#endif +} +#else static INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer, word16 port) { @@ -299,13 +365,23 @@ static INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer, struct hostent* entry = gethostbyname(peer, &err); #elif defined(MICROCHIP_MPLAB_HARMONY) struct hostent* entry = gethostbyname((char*)peer); - #else + #elif defined(WOLFSSL_NUCLEUS) + NU_HOSTENT* entry; + NU_HOSTENT h; + entry = &h; + NU_Get_Host_By_Name((char*)peer, entry); + #else struct hostent* entry = gethostbyname(peer); #endif if (entry) { +#ifdef WOLFSSL_NUCLEUS + memcpy(&addr->id.is_ip_addrs, entry->h_addr_list[0], + entry->h_length); +#else memcpy(&addr->sin_addr.s_addr, entry->h_addr_list[0], entry->h_length); +#endif useLookup = 1; } else @@ -321,7 +397,11 @@ static INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer, #endif addr->sin_port = htons(port); if ((size_t)peer == INADDR_ANY) +#ifdef WOLFSSL_NUCLEUS + PUT32(addr->id.is_ip_addrs, 0, INADDR_ANY); +#else addr->sin_addr.s_addr = INADDR_ANY; +#endif else { if (!useLookup) { #ifdef MICROCHIP_MPLAB_HARMONY @@ -367,6 +447,7 @@ static INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer, } #endif } +#endif /* WOLFSSL_NUCLEUS */ #ifdef USE_WINDOWS_API #pragma warning(pop) @@ -380,6 +461,8 @@ static INLINE void tcp_socket(SOCKET_T* sockFd) *sockFd = 0; #elif defined(MICROCHIP_TCPIP) *sockFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +#elif defined(WOLFSSL_NUCLEUS) + *sockFd = NU_Socket(NU_FAMILY_IP, NU_TYPE_STREAM, 0); #else *sockFd = socket(AF_INET_V, SOCK_STREAM, 0); #endif @@ -405,6 +488,8 @@ static INLINE void tcp_socket(SOCKET_T* sockFd) /* nothing to define */ #elif defined(MICROCHIP_MPLAB_HARMONY) && !defined(_FULL_SIGNAL_IMPLEMENTATION) /* not full signal implementation */ +#elif defined(WOLFSSL_NUCLEUS) + /* nothing to define */ #else /* no S_NOSIGPIPE */ signal(SIGPIPE, SIG_IGN); #endif /* S_NOSIGPIPE */ @@ -415,6 +500,7 @@ static INLINE void tcp_socket(SOCKET_T* sockFd) if (!TCPIP_TCP_OptionsSet(*sockFd, TCP_OPTION_NODELAY, (void*)1)) { err_sys("setsockopt TCP_NODELAY failed\n"); } + #elif defined(WOLFSSL_NUCLEUS) #else int on = 1; socklen_t len = sizeof(on); @@ -439,15 +525,19 @@ static INLINE void tcp_listen(SOCKET_T* sockfd, word16* port, int useAnyAddr) *sockfd = TCPIP_TCP_ServerOpen(IP_ADDRESS_TYPE_IPV4, *port, 0); return; #else - SOCKADDR_IN_T addr; - + #ifdef WOLFSSL_NUCLEUS + struct addr_struct addr; + #else + SOCKADDR_IN_T addr; + #endif /* don't use INADDR_ANY by default, firewall may block, make user switch on */ build_addr(&addr, (useAnyAddr ? INADDR_ANY : wolfSshIp), *port); tcp_socket(sockfd); #if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_MDK_ARM)\ - && !defined(WOLFSSL_KEIL_TCP_NET) + && !defined(WOLFSSL_KEIL_TCP_NET)\ + && !defined(WOLFSSL_NUCLEUS) { int res; #ifdef MICROCHIP_TCPIP @@ -462,11 +552,19 @@ static INLINE void tcp_listen(SOCKET_T* sockfd, word16* port, int useAnyAddr) } #endif +#ifdef WOLFSSL_NUCLEUS + if (NU_Bind(*sockfd, &addr, sizeof(addr)) <= 0) + err_sys("tcp bind failed"); + if (NU_Listen(*sockfd, NUM_SOCKETS) != NU_SUCCESS) + err_sys("tcp listen failed"); +#else if (bind(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0) err_sys("tcp bind failed"); if (listen(*sockfd, NUM_SOCKETS) != 0) err_sys("tcp listen failed"); - #if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_TIRTOS) +#endif + + #if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_TIRTOS) && !defined(WOLFSSL_NUCLEUS) if (*port == 0) { socklen_t len = sizeof(addr); if (getsockname(*sockfd, (struct sockaddr*)&addr, &len) == 0) { @@ -484,7 +582,7 @@ static INLINE void tcp_listen(SOCKET_T* sockfd, word16* port, int useAnyAddr) /* Wolf Root Directory Helper */ /* KEIL-RL File System does not support relative directory */ #if !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_KEIL_FS) && !defined(WOLFSSL_TIRTOS) \ - && !defined(NO_WOLFSSL_DIR) + && !defined(NO_WOLFSSL_DIR) && !defined(WOLFSSL_NUCLEUS) /* Maximum depth to search for WolfSSL root */ #define MAX_WOLF_ROOT_DEPTH 5 diff --git a/wolfssh/wolfsftp.h b/wolfssh/wolfsftp.h index d56f3079..ce4db340 100644 --- a/wolfssh/wolfsftp.h +++ b/wolfssh/wolfsftp.h @@ -107,6 +107,10 @@ enum { WOLFSSH_FXF_EXCL = 0x00000020 }; +#ifndef WS_DRIVE_SIZE + #define WS_DRIVE_SIZE 1 +#endif + typedef struct WS_SFTP_FILEATRB_EX WS_SFTP_FILEATRB_EX; struct WS_SFTP_FILEATRB_EX { char* type; @@ -118,7 +122,7 @@ struct WS_SFTP_FILEATRB_EX { typedef struct WS_SFTP_FILEATRB { word32 flags; - long sz; + word64 sz; word32 uid; /* user ID */ word32 gid; /* group ID */ word32 per; /* permissions */ @@ -209,6 +213,7 @@ WOLFSSH_LOCAL int wolfSSH_SFTP_RecvRemove(WOLFSSH* ssh, int reqId, word32 maxSz) WOLFSSH_LOCAL int wolfSSH_SFTP_RecvRename(WOLFSSH* ssh, int reqId, word32 maxSz); WOLFSSH_LOCAL int wolfSSH_SFTP_RecvSTAT(WOLFSSH* ssh, int reqId, word32 maxSz); WOLFSSH_LOCAL int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, word32 maxSz); +WOLFSSH_LOCAL int wolfSSH_SFTP_RecvFSTAT(WOLFSSH* ssh, int reqId, word32 maxSz); #ifndef NO_WOLFSSL_DIR WOLFSSH_LOCAL int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, word32 maxSz); @@ -216,3 +221,6 @@ WOLFSSH_LOCAL int wolfSSH_SFTP_RecvReadDir(WOLFSSH* ssh, int reqId, word32 maxSz WOLFSSH_LOCAL int wolfSSH_SFTP_RecvCloseDir(WOLFSSH* ssh, byte* handle, word32 handleSz); #endif /* NO_WOLFSSL_DIR */ + +WOLFSSL_LOCAL int SFTP_AddHandleNode(WOLFSSH* ssh, byte* handle, word32 handleSz, char* name); +WOLFSSL_LOCAL int SFTP_RemoveHandleNode(WOLFSSH* ssh, byte* handle, word32 handleSz);