diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 36a6c4c9..7518f816 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 @@ -206,13 +210,19 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) break; } - if (ret != 0) { - fprintf(stderr, "Error [%d] with handling connection.\n", ret); - exit(EXIT_FAILURE); + if (wolfSSH_shutdown(threadCtx->ssh) != WS_SUCCESS) { + fprintf(stderr, "Error with SSH shutdown.\n"); } WCLOSESOCKET(threadCtx->fd); wolfSSH_free(threadCtx->ssh); + + if (ret != 0) { + fprintf(stderr, "Error [%d] \"%s\" with handling connection.\n", ret, + wolfSSH_ErrorToName(ret)); + exit(EXIT_FAILURE); + } + free(threadCtx); return 0; @@ -585,6 +595,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 +623,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 +672,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 +728,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 +780,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) return 0; } + #ifndef NO_MAIN_DRIVER int main(int argc, char** argv) @@ -734,7 +800,9 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) wolfSSH_Init(); +#ifndef WOLFSSL_NUCLEUS ChangeToWolfSshRoot(); +#endif echoserver_test(&args); wolfSSH_Cleanup(); @@ -747,3 +815,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..0a57a492 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; } @@ -7007,6 +7011,118 @@ int SendChannelSuccess(WOLFSSH* ssh, word32 channelId, int success) } +#if defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP) +/* cleans up absolute path */ +void clean_path(char* path) +{ + int i; + long sz = (long)WSTRLEN(path); + byte found; + +#ifdef WOLFSSL_NUCLEUS + for (i = 0; i < sz; i++) { + 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--; + } + } + + if (path != NULL) { + /* go through path until no cases are found */ + do { + sz = WSTRLEN(path); + int prIdx = 0; /* begin of cut */ + int enIdx = 0; /* end of cut */ + + found = 0; + for (i = 1; i < sz; i++) { + if (path[i] == WS_DELIM) { + int z; + + /* if next two chars are .. then delete */ + if (path[i+1] == '.' && path[i+2] == '.') { + enIdx = i + 3; + + /* start at one char before / and retrace path */ + for (z = i - 1; z > 0; z--) { + if (path[z] == WS_DELIM || path[z] == ':') { + prIdx = z; + break; + } + } + + /* cut out .. and previous */ + WMEMMOVE(path + prIdx, path + enIdx, sz - enIdx); + path[sz - (enIdx - prIdx)] = '\0'; + + if (enIdx == sz) { + path[prIdx] = '\0'; + } + + /* case of at / */ + if (WSTRLEN(path) == 0) { + path[0] = '/'; + path[1] = '\0'; + } + + found = 1; + break; + } + } + } + } 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'; + } + } +} +#endif /* WOLFSSH_SFTP || WOLFSSH_SCP */ + + #ifdef DEBUG_WOLFSSH #define LINE_WIDTH 16 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/log.c b/src/log.c index 13235500..3bc43882 100644 --- a/src/log.c +++ b/src/log.c @@ -142,7 +142,7 @@ void DefaultLoggingCb(enum wolfSSH_LogLevel level, const char *const msgStr) } } #endif /* WOLFSSH_NO_TIMESTAMP */ - fprintf(stdout, "%s[%s] %s\n", timeStr, GetLogStr(level), msgStr); + fprintf(stdout, "%s[%s] %s\r\n", timeStr, GetLogStr(level), msgStr); } #endif /* WOLFSSH_NO_DEFAULT_LOGGING_CB */ diff --git a/src/port.c b/src/port.c index de194722..ee552ab7 100644 --- a/src/port.c +++ b/src/port.c @@ -40,6 +40,36 @@ 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") && WSTRSTR(mode, "w")) { + m |= WOLFSSH_O_RDWR; + } + else { + if (WSTRSTR(mode, "r")) { + m |= WOLFSSH_O_RDONLY; + } + if (WSTRSTR(mode, "w")) { + m |= WOLFSSH_O_WRONLY; + } + } + + if (filename != NULL && f != NULL) { + if ((**f = WOPEN(filename, m, 0)) < 0) { + return **f; + } + + /* fopen defaults to normal */ + if (NU_Set_Attributes(filename, 0) != NU_SUCCESS) { + WCLOSE(**f); + return 1; + } + return 0; + } + else { + return 1; + } #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..723a5f8f 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -31,12 +31,14 @@ #include #endif +#include + #ifdef WOLFSSH_SCP #include #include #include -#include + #ifdef NO_INLINE #include @@ -71,7 +73,7 @@ int DoScpSink(WOLFSSH* ssh) ssh->scpConfirm = ssh->ctx->scpRecvCb(ssh, WOLFSSH_SCP_NEW_REQUEST, ssh->scpBasePath, - NULL, 0, 0, 0, 0, NULL, 0, 0, ssh->scpRecvCtx); + NULL, 0, 0, 0, 0, NULL, 0, 0, wolfSSH_GetScpRecvCtx(ssh)); continue; case SCP_RECEIVE_MESSAGE: @@ -117,7 +119,7 @@ int DoScpSink(WOLFSSH* ssh) ssh->scpConfirm = ssh->ctx->scpRecvCb(ssh, ssh->scpFileState, ssh->scpBasePath, ssh->scpFileName, ssh->scpFileMode, ssh->scpMTime, ssh->scpATime, ssh->scpFileSz, NULL, 0, - 0, ssh->scpRecvCtx); + 0, wolfSSH_GetScpRecvCtx(ssh)); continue; @@ -160,7 +162,7 @@ int DoScpSink(WOLFSSH* ssh) ssh->scpFileName, ssh->scpFileMode, ssh->scpMTime, ssh->scpATime, ssh->scpFileSz, ssh->scpFileBuffer, ssh->scpFileBufferSz, ssh->scpFileOffset, - ssh->scpRecvCtx); + wolfSSH_GetScpRecvCtx(ssh)); ssh->scpFileOffset += ssh->scpFileBufferSz; @@ -183,7 +185,7 @@ int DoScpSink(WOLFSSH* ssh) WOLFSSH_SCP_FILE_DONE, ssh->scpBasePath, ssh->scpFileName, ssh->scpFileMode, ssh->scpMTime, ssh->scpATime, ssh->scpFileSz, NULL, 0, 0, - ssh->scpRecvCtx); + wolfSSH_GetScpRecvCtx(ssh)); ssh->scpFileOffset = 0; ssh->scpATime = 0; @@ -375,7 +377,7 @@ int DoScpSource(WOLFSSH* ssh) ssh->scpConfirm = ssh->ctx->scpSendCb(ssh, WOLFSSH_SCP_NEW_REQUEST, NULL, NULL, 0, NULL, NULL, - NULL, 0, NULL, NULL, 0, ssh->scpSendCtx); + NULL, 0, NULL, NULL, 0, wolfSSH_GetScpSendCtx(ssh)); if (ssh->scpConfirm == WS_SCP_ABORT) { ssh->scpState = SCP_RECEIVE_CONFIRMATION_WITH_RECEIPT; @@ -451,7 +453,7 @@ int DoScpSource(WOLFSSH* ssh) &(ssh->scpATime), &(ssh->scpFileMode), ssh->scpFileOffset, &(ssh->scpFileSz), ssh->scpFileBuffer, ssh->scpFileBufferSz, - ssh->scpSendCtx); + wolfSSH_GetScpSendCtx(ssh)); if (ssh->scpConfirm == WS_SCP_ENTER_DIR) { ssh->scpState = SCP_SEND_ENTER_DIRECTORY; @@ -743,7 +745,7 @@ static int GetScpFileMode(WOLFSSH* ssh, byte* buf, word32 bufSz, { int ret; word32 idx; - byte modeOctet[SCP_MODE_OCTET_LEN]; + byte modeOctet[SCP_MODE_OCTET_LEN + 1]; #if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || \ defined(WOLFSSL_DEBUG_MATH) || defined(DEBUG_WOLFSSL) || \ defined(WOLFSSL_PUBLIC_MP) @@ -764,7 +766,8 @@ static int GetScpFileMode(WOLFSSH* ssh, byte* buf, word32 bufSz, return WS_BAD_ARGUMENT; idx++; - WMEMCPY(modeOctet, buf + idx, sizeof(modeOctet)); + WMEMCPY(modeOctet, buf + idx, SCP_MODE_OCTET_LEN); + modeOctet[SCP_MODE_OCTET_LEN] = '\0'; idx += SCP_MODE_OCTET_LEN; #if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || \ @@ -1104,6 +1107,7 @@ int ParseScpCommand(WOLFSSH* ssh) /* skip space */ idx += 2; ssh->scpBasePath = cmd + idx; + clean_path((char*)ssh->scpBasePath); } break; @@ -1113,6 +1117,7 @@ int ParseScpCommand(WOLFSSH* ssh) /* skip space */ idx += 2; ssh->scpBasePath = cmd + idx; + clean_path((char*)ssh->scpBasePath); } break; } /* end switch */ @@ -1155,7 +1160,7 @@ int ReceiveScpMessage(WOLFSSH* ssh) switch (buf[0]) { case 'C': - FALL_THROUGH; + FALL_THROUGH /* no break */ case 'D': if (buf[0] == 'C') { @@ -1207,6 +1212,9 @@ int ReceiveScpFile(WOLFSSH* ssh) partSz = min(ssh->scpFileSz - ssh->scpFileOffset, DEFAULT_SCP_BUFFER_SZ); + /* don't even bother reading if read size is 0 */ + if (partSz == 0) return ret; + part = (byte*)WMALLOC(partSz, ssh->ctx->heap, DYNTYPE_BUFFER); if (part == NULL) ret = WS_MEMORY_E; @@ -1255,7 +1263,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 +1315,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)", @@ -1400,7 +1408,7 @@ static int SetTimestampInfo(const char* fileName, word64 mTime, word64 aTime) tmp[1].tv_sec = mTime; tmp[1].tv_usec = 0; - ret = utimes(fileName, tmp); + ret = WUTIMES(fileName, tmp); } return ret; @@ -1472,24 +1480,73 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, int ret = WS_SCP_CONTINUE; word32 bytes; - if (ctx != NULL) +#ifdef WOLFSSL_NUCLEUS + char abslut[WOLFSSH_MAX_FILENAME]; + fp = (WFILE*)&ssh->scpFd; /* uses file descriptor for file operations */ + abslut[0] = '\0'; +#endif + + if (ctx != NULL) { fp = (WFILE*)ctx; + } switch (state) { case WOLFSSH_SCP_NEW_REQUEST: /* cd into requested root path */ + #ifdef WOLFSSL_NUCLEUS + { + DSTAT stat; + + clean_path((char*)basePath); + + /* make sure is directory */ + if ((ret = NU_Get_First(&stat, basePath)) != NU_SUCCESS) { + /* if back to root directory i.e. A:/ then handle case + * where file system has nothing in it. */ + if (basePath[1] == ':' && ret == NUF_NOFILE) { + ret = WS_SCP_CONTINUE; + } + else { + wolfSSH_SetScpErrorMsg(ssh, + "invalid destination directory"); + ret = WS_SCP_ABORT; + } + } + else { + ret = WS_SCP_CONTINUE; + + /* check to make sure that it is a directory */ + if ((stat.fattribute & ADIRENT) == 0) { + wolfSSH_SetScpErrorMsg(ssh, + "invalid destination directory"); + ret = WS_SCP_ABORT; + } + NU_Done(&stat); + } + } + #else if (WCHDIR(basePath) != 0) { wolfSSH_SetScpErrorMsg(ssh, "invalid destination directory"); ret = WS_SCP_ABORT; } + #endif break; case WOLFSSH_SCP_NEW_FILE: /* open file */ + #ifdef WOLFSSL_NUCLEUS + /* use absolute path */ + WSTRNCAT(abslut, (char*)basePath, WOLFSSH_MAX_FILENAME); + WSTRNCAT(abslut, "/", sizeof("/")); + WSTRNCAT(abslut, fileName, WSTRLEN(fileName)); + clean_path(abslut); + if (WFOPEN(&fp, abslut, "wb") != 0) { + #else if (WFOPEN(&fp, fileName, "wb") != 0) { + #endif wolfSSH_SetScpErrorMsg(ssh, "unable to open file for writing"); ret = WS_SCP_ABORT; break; @@ -1505,7 +1562,6 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, ret = WS_SCP_ABORT; break; } - /* read file, or file part */ bytes = (word32)WFWRITE(buf, 1, bufSz, fp); if (bytes != bufSz) { @@ -1537,7 +1593,16 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, case WOLFSSH_SCP_NEW_DIR: /* try to create new directory */ +#ifdef WOLFSSL_NUCLEUS + /* get absolute path */ + WSTRNCAT(abslut, (char*)basePath, WOLFSSH_MAX_FILENAME); + WSTRNCAT(abslut, "/", sizeof("/")); + WSTRNCAT(abslut, fileName, WSTRLEN(fileName)); + clean_path(abslut); + if (WMKDIR(abslut, fileMode) != 0) { +#else if (WMKDIR(fileName, fileMode) != 0) { +#endif if (wolfSSH_LastError() != EEXIST) { wolfSSH_SetScpErrorMsg(ssh, "error creating directory"); ret = WS_SCP_ABORT; @@ -1546,19 +1611,30 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, } /* cd into directory */ + #ifdef WOLFSSL_NUCLEUS + WSTRNCAT((char*)basePath, "/", sizeof("/")); + WSTRNCAT((char*)basePath, fileName, WOLFSSH_MAX_FILENAME); + clean_path((char*)basePath); + #else if (WCHDIR(fileName) != 0) { wolfSSH_SetScpErrorMsg(ssh, "unable to cd into directory"); ret = WS_SCP_ABORT; } + #endif break; case WOLFSSH_SCP_END_DIR: /* cd out of directory */ + #ifdef WOLFSSL_NUCLEUS + WSTRNCAT((char*)basePath, "/..", WOLFSSH_MAX_FILENAME - 1); + clean_path((char*)basePath); + #else if (WCHDIR("..") != 0) { wolfSSH_SetScpErrorMsg(ssh, "unable to cd out of directory"); ret = WS_SCP_ABORT; } + #endif break; default: @@ -1629,13 +1705,27 @@ static int GetFileStats(ScpSendCtx* ctx, const char* fileName, } /* get file stats for times and mode */ - if (stat(fileName, &ctx->s) < 0) { + if (WSTAT(fileName, &ctx->s) < 0) { ret = WS_BAD_FILE_E; } else { + #ifdef WOLFSSL_NUCLEUS + if (ctx->s.fattribute & ARDONLY) { + *fileMode = 0x124; /* octal 444 */ + } + if (ctx->s.fattribute == ANORMAL) { /* ANORMAL = 0 */ + *fileMode = 0x1B6; /* octal 666 */ + } + if (ctx->s.fattribute == ADIRENT) { + *fileMode = 0x1ED; /* octal 755 */ + } + *mTime = ctx->s.fupdate; + *aTime = ctx->s.faccdate; + #else *mTime = (word64)ctx->s.st_mtime; *aTime = (word64)ctx->s.st_atime; *fileMode = ctx->s.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + #endif } return ret; @@ -1660,8 +1750,11 @@ static ScpDir* ScpNewDir(const char* path, void* heap) } entry->next = NULL; - entry->dir = opendir(path); - if (entry->dir == NULL) { + if (WOPENDIR(&entry->dir, path) != 0 + #ifndef WOLFSSL_NUCLEUS + || entry->dir == NULL + #endif + ) { WFREE(entry, heap, DYNTYPE_SCPDIR); WLOG(WS_LOG_ERROR, scpError, "opendir failed on directory", WS_INVALID_PATH_E); @@ -1710,7 +1803,7 @@ static int ScpPopDir(ScpSendCtx* ctx, void* heap) } if (entry != NULL) { - closedir(entry->dir); + WCLOSEDIR(&entry->dir); WFREE(entry, heap, DYNTYPE_SCPDIR); } @@ -1742,11 +1835,25 @@ static int FindNextDirEntry(ScpSendCtx* ctx) return WS_BAD_ARGUMENT; /* skip self (.) and parent (..) directories */ +#ifdef WOLFSSL_NUCLEUS + { + WDIR* dr; + do { + dr = WREADDIR(&ctx->currentDir->dir); + } while (dr != NULL && + (WSTRNCMP(ctx->currentDir->dir.lfname, ".", 1) == 0 || + WSTRNCMP(ctx->currentDir->dir.lfname ,"..", 2) == 0)); + if (dr == NULL) { + return WS_NEXT_ERROR; + } + } +#else do { - ctx->entry = readdir(ctx->currentDir->dir); + ctx->entry = WREADDIR(&ctx->currentDir->dir); } while ((ctx->entry != NULL) && (WSTRNCMP(ctx->entry->d_name, ".", 1) == 0 || WSTRNCMP(ctx->entry->d_name ,"..", 2) == 0)); +#endif return WS_SUCCESS; } @@ -1760,14 +1867,23 @@ static int ScpDirStackIsEmpty(ScpSendCtx* ctx) return 0; } +/* returns 1 if is directory */ static int ScpFileIsDir(ScpSendCtx* ctx) { +#ifdef WOLFSSL_NUCLEUS + return (ctx->s.fattribute & ADIRENT); +#else return S_ISDIR(ctx->s.st_mode); +#endif } static int ScpFileIsFile(ScpSendCtx* ctx) { +#ifdef WOLFSSL_NUCLEUS + return (ctx->s.fattribute != ADIRENT); +#else return S_ISREG(ctx->s.st_mode); +#endif } /* Default SCP send callback, called by wolfSSH when an application has called @@ -1858,6 +1974,10 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, sendCtx = (ScpSendCtx*)ctx; } +#ifdef WOLFSSL_NUCLEUS + if (sendCtx != NULL) sendCtx->fp = &sendCtx->fd; +#endif + WMEMSET(filePath, 0, DEFAULT_SCP_FILE_NAME_SZ); switch (state) { @@ -1873,16 +1993,21 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, break; case WOLFSSH_SCP_SINGLE_FILE_REQUEST: - if ((sendCtx == NULL) || WFOPEN(&(sendCtx->fp), peerRequest, "rb") != 0) { + wolfSSH_SetScpErrorMsg(ssh, "unable to open file for reading"); ret = WS_SCP_ABORT; } if (ret == WS_SUCCESS) { + #ifdef WOLFSSL_NUCLEUS + if (sendCtx->fd < 0) + ret = WS_SCP_ABORT; + #else if (sendCtx->fp == NULL) ret = WS_SCP_ABORT; + #endif } if (ret == WS_SUCCESS) @@ -1936,10 +2061,14 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, } ret = FindNextDirEntry(sendCtx); - if (ret == WS_SUCCESS) { + if (ret == WS_SUCCESS || ret == WS_NEXT_ERROR) { + #ifdef WOLFSSL_NUCLEUS + if (ret == WS_NEXT_ERROR) { + #else /* reached end of directory */ if (sendCtx->entry == NULL) { + #endif ret = ScpPopDir(sendCtx, ssh->ctx->heap); if (ret == WS_SUCCESS) { ret = WS_SCP_EXIT_DIR; @@ -1959,8 +2088,11 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, if (ret == WS_SUCCESS) { dirNameLen = (int)WSTRLEN(sendCtx->dirName); + #ifdef WOLFSSL_NUCLEUS + dNameLen = (int)WSTRLEN(sendCtx->currentDir->dir.lfname); + #else dNameLen = (int)WSTRLEN(sendCtx->entry->d_name); - + #endif if ((dirNameLen + 1 + dNameLen) > DEFAULT_SCP_FILE_NAME_SZ) { ret = WS_SCP_ABORT; @@ -1968,11 +2100,19 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, WSTRNCPY(filePath, sendCtx->dirName, DEFAULT_SCP_FILE_NAME_SZ); WSTRNCAT(filePath, "/", 1); + + #ifdef WOLFSSL_NUCLEUS + WSTRNCAT(filePath, sendCtx->currentDir->dir.lfname, + DEFAULT_SCP_FILE_NAME_SZ - 1 - dirNameLen); + WSTRNCPY(fileName, sendCtx->currentDir->dir.lfname, + DEFAULT_SCP_FILE_NAME_SZ); + clean_path(filePath); + #else WSTRNCAT(filePath, sendCtx->entry->d_name, DEFAULT_SCP_FILE_NAME_SZ - 1 - dirNameLen); WSTRNCPY(fileName, sendCtx->entry->d_name, DEFAULT_SCP_FILE_NAME_SZ); - + #endif ret = GetFileStats(sendCtx, filePath, mTime, aTime, fileMode); } @@ -2012,6 +2152,7 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, } } else { + ret = WS_SCP_ABORT; } @@ -2025,7 +2166,7 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, } ret = (word32)WFREAD(buf, 1, bufSz, sendCtx->fp); - if ((ret < 0) || (fileOffset + ret == *totalFileSz)) { + if ((ret <= 0) || (fileOffset + ret == *totalFileSz)) { WFCLOSE(sendCtx->fp); } diff --git a/src/wolfsftp.c b/src/wolfsftp.c index 9495678f..8bd7ac72 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -23,9 +23,11 @@ #include #endif -#include -#include #include + +#ifdef WOLFSSH_SFTP + +#include #include #ifdef NO_INLINE @@ -41,6 +43,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 +202,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,87 +308,6 @@ static int SFTP_SetAtributes(WOLFSSH* ssh, byte* buf, word32 bufSz, } - -/* cleans up absolute path */ -static void clean_path(char* path) -{ - int i; - long sz = (long)WSTRLEN(path); - byte found; - - /* remove any double '/' chars */ - for (i = 0; i < sz; i++) { - if (path[i] == '/' && path[i+1] == '/') { - 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 { - sz = WSTRLEN(path); - int prIdx = 0; /* begin of cut */ - int enIdx = 0; /* end of cut */ - - found = 0; - for (i = 0; i < sz; i++) { - if (path[i] == '/') { - int z; - - /* if next two chars are .. then delete */ - if (path[i+1] == '.' && path[i+2] == '.') { - enIdx = i + 3; - - /* start at one char before / and retrace path */ - for (z = i - 1; z > 0; z--) { - if (path[z] == '/') { - prIdx = z; - break; - } - } - - /* cut out .. and previous */ - WMEMMOVE(path + prIdx, path + enIdx, sz - enIdx); - path[sz - (enIdx - prIdx)] = '\0'; - - if (enIdx == sz) { - path[prIdx] = '\0'; - } - - /* case of at / */ - if (WSTRLEN(path) == 0) { - path[0] = '/'; - path[1] = '\0'; - } - - found = 1; - break; - } - } - } - } while (found); - } -} - - /* returns WS_SUCCESS on success */ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, int maxSz) { @@ -394,6 +316,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 +337,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 +346,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 +359,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 +443,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 +476,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 +537,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 +549,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 +608,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 +639,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 +673,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 +755,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 +784,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 +794,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 +816,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 +872,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 +892,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 +909,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 +926,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; @@ -983,6 +994,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 +1012,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 +1046,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 +1085,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 +1108,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 +1127,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 +1146,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 +1183,7 @@ int wolfSSH_SFTP_RecvReadDir(WOLFSSH* ssh, int reqId, word32 maxSz) int wolfSSH_SFTP_RecvCloseDir(WOLFSSH* ssh, byte* handle, word32 handleSz) { DIR_HANDLE* cur = dirList; - WDIR dir = NULL; + WDIR* dir = NULL; if (ssh == NULL || handle == NULL || handleSz != sizeof(word64)) { return WS_BAD_ARGUMENT; @@ -1172,7 +1194,7 @@ int wolfSSH_SFTP_RecvCloseDir(WOLFSSH* ssh, byte* handle, word32 handleSz) /* find DIR given handle */ while (cur != NULL) { if (cur->id == *((word64*)handle)) { - dir = cur->dir; + dir = &cur->dir; break; } cur = cur->next; @@ -1188,7 +1210,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 +1258,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 +1265,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 +1294,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 +1334,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 +1412,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 +1435,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 +1489,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 +1505,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 +1601,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 +1624,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 +1896,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 +2045,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 +2121,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 +2261,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 +3656,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'; @@ -3512,3 +3909,4 @@ int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume, return ret; } +#endif /* WOLFSSH_SFTP */ 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/internal.h b/wolfssh/internal.h index bfeb08de..7a4973a4 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -303,6 +303,9 @@ struct WOLFSSH { word32 scpFileBufferSz; /* size of transfer buffer, octets */ word32 scpFileOffset; /* current offset into file transfer */ word32 scpBufferedSz; /* bytes buffered to send to peer */ +#ifdef WOLFSSL_NUCLEUS + int scpFd; /* SCP receive callback context handle */ +#endif void* scpRecvCtx; /* SCP receive callback context handle */ void* scpSendCtx; /* SCP send callback context handle */ #if !defined(WOLFSSH_SCP_USER_CALLBACKS) && !defined(NO_FILESYSTEM) @@ -657,6 +660,7 @@ WOLFSSH_LOCAL int wsScpSendCallback(WOLFSSH*, int, const char*, char*, word32, #endif +WOLFSSH_LOCAL void clean_path(char* path); WOLFSSH_LOCAL void DumpOctetString(const byte*, word32); diff --git a/wolfssh/port.h b/wolfssh/port.h index d2d689fd..7ce0e95e 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -53,6 +53,43 @@ extern "C" { #endif #ifndef NO_FILESYSTEM +#ifdef WOLFSSL_NUCLEUS + #include "storage/nu_storage.h" + + #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) ((s) != 0)? NU_Write(*(f),(const CHAR*)(b),(s)): 0 + #define WFREAD(b,x,s,f) NU_Read(*(f),(CHAR*)(b),(s)) + #define WFSEEK(s,o,w) NU_Seek(*(s),(o),(w)) + #define WFTELL(s) NU_Seek(*(s), 0, PSEEK_CUR) + #define WREWIND(s) NU_Seek(*(s), 0, PSEEK_SET) + #define WSEEK_END PSEEK_END + + #define WS_DELIM '\\' + #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 + +#ifndef WOPEN + static inline int wOpen(const 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)) + +#else #define WFILE FILE WOLFSSH_API int wfopen(WFILE**, const char*, const char*); @@ -64,6 +101,7 @@ extern "C" { #define WFTELL(s) ftell((s)) #define WREWIND(s) rewind((s)) #define WSEEK_END SEEK_END + #define WUTIMES(f,t) utimes((f),(t)) #if (defined(WOLFSSH_SCP) || defined(WOLFSSH_SFTP)) && \ !defined(WOLFSSH_SCP_USER_CALLBACKS) && \ @@ -76,7 +114,7 @@ extern "C" { #define WMKDIR(p,m) mkdir((p),(m)) #endif #endif - +#endif /* setup string handling */ #ifndef WSTRING_USER #include @@ -130,8 +168,150 @@ extern "C" { #define WLOCALTIME(c,r) (localtime_r((c),(r))!=NULL) #endif -#ifdef WOLFSSH_SFTP -#ifndef NO_WOLFSSH_SERVER +#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \ + !defined(NO_WOLFSSH_SERVER) +#ifdef WOLFSSL_NUCLEUS + #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 WFD int + +#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 + +#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 + + static inline int wUtimes(const char* f, struct timeval t[2]) + { + DSTAT stat; + int ret = -1; + + if (NU_Get_First(&stat, f) == NU_SUCCESS) { + ret = NU_Utime(&stat, 0xFFFF, t[0].tv_sec, 0xFFFF, t[1].tv_sec, + 0xFFFF, 0xFFFF); + NU_Done(&stat); + if (ret == NU_SUCCESS) { + ret = 0; + } + else { + ret = -1; + } + } + return ret; + } + #define WUTIMES(f,t) wUtimes((f), (t)) + + #ifndef NO_WOLFSSL_DIR + #define WDIR DSTAT + +#ifndef WOPENDIR + static inline int wOpenDir(WDIR* d, const 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 +323,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,12 +343,14 @@ extern "C" { #ifndef NO_WOLFSSL_DIR #include /* used for opendir, readdir, and closedir */ #define WDIR DIR* - #define WOPENDIR(d) opendir((d)) - #define WCLOSEDIR(d) closedir((d)) - #define WREADDIR(d) readdir((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 */ #endif -#endif /* WOLFSSH_SFTP */ +#endif /* WOLFSSH_SFTP or WOLFSSH_SCP */ /* setup compiler inlining */ #ifndef INLINE 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/wolfscp.h b/wolfssh/wolfscp.h index dae978cb..1ceb6ee8 100644 --- a/wolfssh/wolfscp.h +++ b/wolfssh/wolfscp.h @@ -24,6 +24,7 @@ #define WOLFSSH_WOLFSCP_H #include +#include #include #ifdef WOLFSSH_SCP @@ -57,15 +58,20 @@ extern "C" { #include typedef struct ScpSendCtx { + #ifndef WOLFSSL_NUCLEUS struct dirent* entry; /* file entry, from readdir() */ - struct ScpDir* currentDir; /* dir being copied, stack */ - WFILE* fp; /* file pointer */ struct stat s; /* stat info from file */ + #else + int fd; /* file descriptor, in the case of Nucleus fp points to fd */ + DSTAT s; + #endif + WFILE* fp; /* file pointer */ + struct ScpDir* currentDir; /* dir being copied, stack */ char dirName[DEFAULT_SCP_FILE_NAME_SZ]; /* current dir name */ } ScpSendCtx; typedef struct ScpDir { - DIR* dir; /* dir pointer, from opendir() */ + WDIR dir; /* dir pointer, from opendir() */ struct ScpDir* next; /* previous directory in stack */ } ScpDir; diff --git a/wolfssh/wolfsftp.h b/wolfssh/wolfsftp.h index d56f3079..cacf8b70 100644 --- a/wolfssh/wolfsftp.h +++ b/wolfssh/wolfsftp.h @@ -26,6 +26,8 @@ #include #endif +#include + /* Packet Types */ enum WS_PacketTypes { WOLFSSH_FTP_INIT = 1, @@ -107,6 +109,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 +124,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 +215,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 +223,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);