diff --git a/src/internal.c b/src/internal.c index 1e76ad6..26659e5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -9199,12 +9199,26 @@ int SendChannelSuccess(WOLFSSH* ssh, word32 channelId, int success) #if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \ !defined(NO_WOLFSSH_SERVER) -/* cleans up absolute path */ -void clean_path(char* path) +/* cleans up absolute path + * returns size of new path on success (strlen sz) and negative values on fail*/ +int wolfSSH_CleanPath(WOLFSSH* ssh, char* in) { int i; - long sz = (long)WSTRLEN(path); + long sz; byte found; + char *path; + + if (in == NULL) { + return WS_BAD_ARGUMENT; + } + + sz = (long)WSTRLEN(in); + path = (char*)WMALLOC(sz+1, ssh->ctx->heap, DYNTYPE_TEMP); + if (path == NULL) { + return WS_MEMORY_E; + } + WMEMCPY(path, in, sz); + path[sz] = '\0'; #if defined(WOLFSSL_NUCLEUS) || defined(USE_WINDOWS_API) for (i = 0; i < sz; i++) { @@ -9334,6 +9348,18 @@ void clean_path(char* path) } #endif } + + /* copy result back to 'in' buffer */ + if (WSTRLEN(in) < WSTRLEN(path)) { + WLOG(WS_LOG_ERROR, "Fatal error cleaning path"); + WFREE(path, ssh->heap, DYNTYPE_TMP); + return WS_BUFFER_E; + } + sz = WSTRLEN(path); + WMEMCPY(in, path, sz); + in[sz] = '\0'; + WFREE(path, ssh->heap, DYNTYPE_TMP); + return (int)sz; } #endif /* WOLFSSH_SFTP || WOLFSSH_SCP */ diff --git a/src/wolfscp.c b/src/wolfscp.c index f974f68..9f29242 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -1054,9 +1054,11 @@ static int ScpCheckForRename(WOLFSSH* ssh, int cmdSz) WSTRNCPY(buf, ssh->scpBasePath, cmdSz); buf[sz] = '\0'; WSTRNCAT(buf, "/..", sizeof("/..")); - clean_path(buf); - - idx = (int)WSTRLEN(buf) + 1; /* +1 for delimiter */ + idx = wolfSSH_CleanPath(ssh, buf); + if (idx < 0) { + return WS_FATAL_ERROR; + } + idx = idx + 1; /* +1 for delimiter */ #ifdef WOLFSSL_NUCLEUS /* no delimiter to skip in case of at base address */ if (idx == 4) { /* case of 4 for drive letter plus ":\" + 1 */ @@ -1219,7 +1221,8 @@ int ParseScpCommand(WOLFSSH* ssh) #endif } ret = ParseBasePathHelper(ssh, cmdSz); - clean_path((char*)ssh->scpBasePath); + if (wolfSSH_CleanPath(ssh, (char*)ssh->scpBasePath) < 0) + ret = WS_FATAL_ERROR; break; case 'f': @@ -1239,7 +1242,9 @@ int ParseScpCommand(WOLFSSH* ssh) #else ssh->scpBasePath = cmd + idx; #endif - clean_path((char*)ssh->scpBasePath); + if (wolfSSH_CleanPath(ssh, + (char*)ssh->scpBasePath) < 0) + ret = WS_FATAL_ERROR; } break; } /* end switch */ @@ -1787,8 +1792,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, { DSTAT stat; - clean_path((char*)basePath); - + wolfSSH_CleanPath(ssh, (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 @@ -1830,7 +1834,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, WSTRNCAT(abslut, (char*)basePath, WOLFSSH_MAX_FILENAME); WSTRNCAT(abslut, "/", WOLFSSH_MAX_FILENAME); WSTRNCAT(abslut, fileName, WOLFSSH_MAX_FILENAME); - clean_path(abslut); + wolfSSH_CleanPath(ssh, abslut); if (WFOPEN(&fp, abslut, "wb") != 0) { #else if (WFOPEN(&fp, fileName, "wb") != 0) { @@ -1888,7 +1892,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, WSTRNCAT(abslut, (char*)basePath, WOLFSSH_MAX_FILENAME); WSTRNCAT(abslut, "/", WOLFSSH_MAX_FILENAME); WSTRNCAT(abslut, fileName, WOLFSSH_MAX_FILENAME); - clean_path(abslut); + wolfSSH_CleanPath(ssh, abslut); if (WMKDIR(ssh->fs, abslut, fileMode) != 0) { /* check if directory already exists */ if (NU_Make_Dir(abslut) != NUF_EXIST) { @@ -1912,7 +1916,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, #ifdef WOLFSSL_NUCLEUS WSTRNCAT((char*)basePath, "/", sizeof("/")); WSTRNCAT((char*)basePath, fileName, WOLFSSH_MAX_FILENAME); - clean_path((char*)basePath); + wolfSSH_CleanPath(ssh, (char*)basePath); #else if (WCHDIR(fileName) != 0) { wolfSSH_SetScpErrorMsg(ssh, "unable to cd into directory"); @@ -1927,7 +1931,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, /* cd out of directory */ #ifdef WOLFSSL_NUCLEUS WSTRNCAT((char*)basePath, "/..", WOLFSSH_MAX_FILENAME - 1); - clean_path((char*)basePath); + wolfSSH_CleanPath(ssh, (char*)basePath); #else if (WCHDIR("..") != 0) { wolfSSH_SetScpErrorMsg(ssh, "unable to cd out of directory"); @@ -2217,15 +2221,18 @@ static int ScpProcessEntry(WOLFSSH* ssh, char* fileName, word64* mTime, DEFAULT_SCP_FILE_NAME_SZ); WSTRNCPY(fileName, sendCtx->currentDir->dir.lfname, DEFAULT_SCP_FILE_NAME_SZ); - clean_path(filePath); + if (wolfSSH_CleanPath(ssh, filePath) < 0) { + ret = WS_SCP_ABORT; + } #else WSTRNCAT(filePath, sendCtx->entry->d_name, DEFAULT_SCP_FILE_NAME_SZ); WSTRNCPY(fileName, sendCtx->entry->d_name, DEFAULT_SCP_FILE_NAME_SZ); #endif - ret = GetFileStats(sendCtx, filePath, mTime, aTime, - fileMode); + if (ret == WS_SUCCESS) { + ret = GetFileStats(sendCtx, filePath, mTime, aTime, fileMode); + } } } diff --git a/src/wolfsftp.c b/src/wolfsftp.c index e9175c5..ca26309 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -1168,8 +1168,18 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, byte* data, WMEMCPY(r, wd, WOLFSSH_MAX_FILENAME); } - clean_path(r); - rSz = (int)WSTRLEN(r); + if ((rSz = wolfSSH_CleanPath(ssh, r)) < 0) { + return WS_FATAL_ERROR; + } + + /* For real path remove ending case of /. + * Lots of peers send a '.' wanting a return of the current absolute path + * not the absolute path + . + */ + if (r[rSz - 2] == WS_DELIM && r[rSz - 1] == '.') { + r[rSz - 1] = '\0'; + rSz -= 1; + } /* for real path always send '/' chars */ for (i = 0; i < rSz; i++) { @@ -1572,12 +1582,17 @@ int wolfSSH_SFTP_RecvRMDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) WMEMCPY(dir, data + idx, sz); dir[sz] = '\0'; - clean_path(dir); -#ifndef USE_WINDOWS_API - ret = WRMDIR(ssh->fs, dir); -#else /* USE_WINDOWS_API */ - ret = WS_RemoveDirectoryA(dir, ssh->ctx->heap) == 0; -#endif /* USE_WINDOWS_API */ + if (wolfSSH_CleanPath(ssh, dir) < 0) { + ret = WS_FATAL_ERROR; + } + + if (ret == 0) { + #ifndef USE_WINDOWS_API + ret = WRMDIR(ssh->fs, dir); + #else /* USE_WINDOWS_API */ + ret = WS_RemoveDirectoryA(dir, ssh->ctx->heap) == 0; + #endif /* USE_WINDOWS_API */ + } WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); res = (ret != 0)? err : suc; @@ -1671,7 +1686,12 @@ int wolfSSH_SFTP_RecvMKDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) else { ato32(data + idx, &mode); } - clean_path(dir); + + if (wolfSSH_CleanPath(ssh, dir) < 0) { + WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); + return WS_FATAL_ERROR; + } + #ifndef USE_WINDOWS_API ret = WMKDIR(ssh->fs, dir, mode); #else /* USE_WINDOWS_API */ @@ -1793,7 +1813,10 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) atr.per = 0644; } - clean_path(dir); + if (wolfSSH_CleanPath(ssh, dir) < 0) { + WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); + return WS_FATAL_ERROR; + } fd = WOPEN(dir, m, atr.per); if (fd < 0) { WLOG(WS_LOG_SFTP, "Error opening file %s", dir); @@ -1925,7 +1948,10 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) } #endif - clean_path(dir); + if (wolfSSH_CleanPath(ssh, dir) < 0) { + return WS_FATAL_ERROR; + } + fileHandle = WS_CreateFileA(dir, desiredAccess, 0, creationDisp, FILE_ATTRIBUTE_NORMAL, ssh->ctx->heap); if (fileHandle == INVALID_HANDLE_VALUE) { @@ -2038,7 +2064,11 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) dir[sz] = '\0'; /* get directory handle */ - clean_path(dir); + if (wolfSSH_CleanPath(ssh, dir) < 0) { + WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); + return WS_FATAL_ERROR; + } + if (WOPENDIR(ssh->fs, ssh->ctx->heap, &ctx, dir) != 0) { WLOG(WS_LOG_SFTP, "Error with opening directory"); WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER); @@ -2140,7 +2170,10 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) } WMEMCPY(dirName, data + idx, sz); dirName[sz] = '\0'; - clean_path(dirName); + if (wolfSSH_CleanPath(ssh, buf) < 0) { + WFREE(dirName, ssh->ctx->heap, DYNTYPE_BUFFER); + return WS_FATAL_ERROR; + } /* get directory handle */ findHandle = (HANDLE)WS_FindFirstFileA(dirName, @@ -2403,7 +2436,12 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, } WSTRNCAT(buf, out->fName, bufSz + 1); - clean_path(buf); + if (wolfSSH_CleanPath(ssh, buf) < 0) { + WLOG(WS_LOG_SFTP, "Error cleaning path to get attributes"); + WFREE(buf, out->heap, DYNTYPE_SFTP); + return WS_FATAL_ERROR; + } + if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap) != WS_SUCCESS) { WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s", buf); @@ -2490,7 +2528,11 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, } WSTRNCAT(buf, out->fName, bufSz + 1); - clean_path(buf); + if (wolfSSH_CleanPath(ssh, buf) < 0) { + WFREE(buf, out->heap, DYNTYPE_SFTP); + return WS_FATAL_ERROR; + } + if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap) != WS_SUCCESS) { WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s", @@ -2585,7 +2627,11 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, } WSTRNCAT(buf, out->fName, bufSz + 1); - clean_path(buf); + if (wolfSSH_CleanPath(ssh, buf) < 0) { + WFREE(buf, out->heap, DYNTYPE_SFTP); + return WS_FATAL_ERROR; + } + if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap) != WS_SUCCESS) { WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s", @@ -2659,7 +2705,11 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, } WSTRNCAT(buf, out->fName, bufSz + 1); - clean_path(buf); + if (wolfSSH_CleanPath(ssh, buf) < 0) { + WFREE(buf, out->heap, DYNTYPE_SFTP); + return WS_FATAL_ERROR; + } + if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap) != WS_SUCCESS) { WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s", @@ -3520,28 +3570,33 @@ int wolfSSH_SFTP_RecvRemove(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) WMEMCPY(name, data + idx, sz); name[sz] = '\0'; - clean_path(name); -#ifndef USE_WINDOWS_API - if ((ret = WREMOVE(ssh->fs, name)) < 0) -#else /* USE_WINDOWS_API */ - if (WS_DeleteFileA(name, ssh->ctx->heap) == 0) -#endif /* USE_WINDOWS_API */ - { - WLOG(WS_LOG_SFTP, "Error removing file"); - #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 + if (wolfSSH_CleanPath(ssh, name) < 0) { ret = WS_BAD_FILE_E; } - else { - ret = WS_SUCCESS; + + if (ret == WS_SUCCESS) { + #ifndef USE_WINDOWS_API + if ((ret = WREMOVE(ssh->fs, name)) < 0) + #else /* USE_WINDOWS_API */ + if (WS_DeleteFileA(name, ssh->ctx->heap) == 0) + #endif /* USE_WINDOWS_API */ + { + WLOG(WS_LOG_SFTP, "Error removing file"); + #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 */ @@ -3625,8 +3680,13 @@ int wolfSSH_SFTP_RecvRename(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) nw[sz] = '\0'; } - clean_path(old); - clean_path(nw); + if (wolfSSH_CleanPath(ssh, old) < 0) { + ret = WS_FATAL_ERROR; + } + if (wolfSSH_CleanPath(ssh, nw) < 0) { + ret = WS_FATAL_ERROR; + } + if (ret == WS_SUCCESS) { #ifndef USE_WINDOWS_API if (WRENAME(ssh->fs, old, nw) < 0) @@ -4314,21 +4374,31 @@ int wolfSSH_SFTP_RecvSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) name[sz] = '\0'; /* try to get file attributes and send back to client */ - clean_path(name); - WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB)); - if (SFTP_GetAttributes(ssh->fs, name, &atr, 0, ssh->ctx->heap) - != WS_SUCCESS) { - WLOG(WS_LOG_SFTP, "Unable to get stat of file/directory"); + if (wolfSSH_CleanPath(ssh, name) < 0) { if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, "STAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) { WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER); return WS_FATAL_ERROR; } - ret = WS_BAD_FILE_E; + ret = WS_FATAL_ERROR; } - else { - sz = SFTP_AtributesSz(ssh, &atr); - outSz = sz + WOLFSSH_SFTP_HEADER; + + if (ret == WS_SUCCESS) { + WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB)); + if (SFTP_GetAttributes(ssh->fs, name, &atr, 0, ssh->ctx->heap) + != WS_SUCCESS) { + WLOG(WS_LOG_SFTP, "Unable to get stat of file/directory"); + if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, + "STAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) { + WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER); + return WS_FATAL_ERROR; + } + ret = WS_BAD_FILE_E; + } + else { + sz = SFTP_AtributesSz(ssh, &atr); + outSz = sz + WOLFSSH_SFTP_HEADER; + } } WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER); @@ -4365,7 +4435,7 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) { WS_SFTP_FILEATRB atr; char* name = NULL; - int ret; + int ret = WS_SUCCESS; word32 sz; word32 idx = 0; @@ -4391,24 +4461,34 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) } WMEMCPY(name, data + idx, sz); name[sz] = '\0'; - clean_path(name); - - /* try to get file attributes and send back to client */ - WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB)); - if ((ret = SFTP_GetAttributes(ssh->fs, name, &atr, 1, ssh->ctx->heap)) - != WS_SUCCESS) { - /* tell peer that was not ok */ - WLOG(WS_LOG_SFTP, "Unable to get lstat of file/directory"); + if (wolfSSH_CleanPath(ssh, name) < 0) { + WLOG(WS_LOG_SFTP, "Unable to clean path"); if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, "LSTAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) { WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER); return WS_FATAL_ERROR; } - ret = WS_BAD_FILE_E; + ret = WS_FATAL_ERROR; } - else { - sz = SFTP_AtributesSz(ssh, &atr); - outSz = sz + WOLFSSH_SFTP_HEADER; + + /* try to get file attributes and send back to client */ + if (ret == WS_SUCCESS) { + WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB)); + if ((ret = SFTP_GetAttributes(ssh->fs, name, &atr, 1, ssh->ctx->heap)) + != WS_SUCCESS) { + /* tell peer that was not ok */ + WLOG(WS_LOG_SFTP, "Unable to get lstat of file/directory"); + if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, + "LSTAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) { + WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER); + return WS_FATAL_ERROR; + } + ret = WS_BAD_FILE_E; + } + else { + sz = SFTP_AtributesSz(ssh, &atr); + outSz = sz + WOLFSSH_SFTP_HEADER; + } } WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER); @@ -4531,9 +4611,12 @@ int wolfSSH_SFTP_RecvSetSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) } WMEMCPY(name, data + idx, sz); idx += sz; name[sz] = '\0'; - clean_path(name); + if (wolfSSH_CleanPath(ssh, name) < 0) { + ret = WS_FATAL_ERROR; + } - if (SFTP_ParseAtributes_buffer(ssh, &atr, data, &idx, maxSz) != 0) { + if (ret == WS_SUCCESS && + SFTP_ParseAtributes_buffer(ssh, &atr, data, &idx, maxSz) != 0) { type = WOLFSSH_FTP_FAILURE; res = per; ret = WS_BAD_FILE_E; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index ca92680..346cdb7 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -753,7 +753,8 @@ enum WS_DynamicTypes { DYNTYPE_AGENT_KEY, DYNTYPE_AGENT_BUFFER, DYNTYPE_FILE, - DYNTYPE_TEMP + DYNTYPE_TEMP, + DYNTYPE_PATH }; @@ -830,7 +831,7 @@ WOLFSSH_LOCAL int wsScpSendCallback(WOLFSSH*, int, const char*, char*, word32, #endif -WOLFSSH_LOCAL void clean_path(char* path); +WOLFSSH_LOCAL int wolfSSH_CleanPath(WOLFSSH* ssh, char* in); WOLFSSH_LOCAL void DumpOctetString(const byte*, word32); WOLFSSH_LOCAL int wolfSSH_oct2dec(WOLFSSH* ssh, byte* oct, word32 octSz); WOLFSSH_LOCAL void AddAssign64(word32*, word32);