diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index adbb5df53..9e1a7d4d7 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -523,6 +523,12 @@ static int doCmds(func_args* args) #endif if (ret != WS_SUCCESS) { + if (wolfSSH_get_error(ssh) == WS_SFTP_NOT_FILE_E) { + if (SFTP_FPUTS(args, "Not a regular file\n") < 0) { + err_msg("fputs error"); + return -1; + } + } if (SFTP_FPUTS(args, "Error getting file\n") < 0) { err_msg("fputs error"); return -1; @@ -628,6 +634,12 @@ static int doCmds(func_args* args) #endif if (ret != WS_SUCCESS) { + if (wolfSSH_get_error(ssh) == WS_SFTP_NOT_FILE_E) { + if (SFTP_FPUTS(args, "Not a regular file\n") < 0) { + err_msg("fputs error"); + return -1; + } + } if (SFTP_FPUTS(args, "Error pushing file\n") < 0) { err_msg("fputs error"); return -1; diff --git a/src/internal.c b/src/internal.c index ea6bce4d7..c68e136c0 100644 --- a/src/internal.c +++ b/src/internal.c @@ -430,6 +430,9 @@ const char* GetErrorString(int err) case WS_KEY_FORMAT_E: return "key format wrong error"; + case WS_SFTP_NOT_FILE_E: + return "not a regular file"; + default: return "Unknown error code"; } diff --git a/src/wolfsftp.c b/src/wolfsftp.c index 5ac05dd05..3bc55c09e 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -1977,6 +1977,7 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) char* res = NULL; char ier[] = "Internal Failure"; char oer[] = "Open File Error"; + char naf[] = "Not A File"; if (ssh == NULL) { return WS_BAD_ARGUMENT; @@ -2036,20 +2037,40 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) m |= WOLFSSH_O_EXCL; } - /* if file permissions not set then use default */ - if (!(atr.flags & WOLFSSH_FILEATRB_PERM)) { - atr.per = 0644; + { + WS_SFTP_FILEATRB fileAtr = { 0 }; + if (SFTP_GetAttributes(ssh->fs, + dir, &fileAtr, 1, ssh->ctx->heap) == WS_SUCCESS) { + if ((fileAtr.per & FILEATRB_PER_MASK_TYPE) != FILEATRB_PER_FILE) { + WLOG(WS_LOG_SFTP, "Not a file"); + ssh->error = WS_SFTP_NOT_FILE_E; + + res = naf; + if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, + res, "English", NULL, &outSz) != WS_SIZE_ONLY) { + return WS_FATAL_ERROR; + } + ret = WS_FATAL_ERROR; + } + } } - fd = WOPEN(ssh->fs, dir, m, atr.per); - if (fd < 0) { - WLOG(WS_LOG_SFTP, "Error opening file %s", dir); - res = oer; - if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, res, - "English", NULL, &outSz) != WS_SIZE_ONLY) { - return WS_FATAL_ERROR; + if (ret == WS_SUCCESS) { + /* if file permissions not set then use default */ + if (!(atr.flags & WOLFSSH_FILEATRB_PERM)) { + atr.per = 0644; + } + + fd = WOPEN(ssh->fs, dir, m, atr.per); + if (fd < 0) { + WLOG(WS_LOG_SFTP, "Error opening file %s", dir); + res = oer; + if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, res, + "English", NULL, &outSz) != WS_SIZE_ONLY) { + return WS_FATAL_ERROR; + } + ret = WS_BAD_FILE_E; } - ret = WS_BAD_FILE_E; } #ifdef WOLFSSH_STOREHANDLE @@ -4708,9 +4729,9 @@ static int PopulateAttributes(WS_SFTP_FILEATRB* atr, WSTAT_T* stats) atr->per = 0755; /* Mimic S_IFMT */ if (stats->type == FS_DIR_ENTRY_FILE) - atr->per |= 0040000; + atr->per |= FILEATRB_PER_FILE; else if (stats->type == FS_DIR_ENTRY_DIR) - atr->per |= 0100000; + atr->per |= FILEATRB_PER_DIR; else return WS_BAD_FILE_E; @@ -8481,6 +8502,14 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from, state->state = STATE_GET_CLEANUP; continue; } + if ((state->attrib.per & FILEATRB_PER_MASK_TYPE) + != FILEATRB_PER_FILE) { + WLOG(WS_LOG_SFTP, "Not a file"); + ssh->error = WS_SFTP_NOT_FILE_E; + ret = WS_FATAL_ERROR; + state->state = STATE_GET_CLEANUP; + continue; + } state->handleSz = WOLFSSH_MAX_HANDLE; state->state = STATE_GET_OPEN_REMOTE; NO_BREAK; @@ -8714,6 +8743,21 @@ int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume, case STATE_PUT_OPEN_LOCAL: WLOG(WS_LOG_SFTP, "SFTP PUT STATE: OPEN LOCAL"); #ifndef USE_WINDOWS_API + { + WS_SFTP_FILEATRB fileAtr = { 0 }; + if (SFTP_GetAttributes(ssh->fs, + from, &fileAtr, 1, ssh->ctx->heap) + == WS_SUCCESS) { + if ((fileAtr.per & FILEATRB_PER_MASK_TYPE) + != FILEATRB_PER_FILE) { + WLOG(WS_LOG_SFTP, "Not a file"); + ssh->error = WS_SFTP_NOT_FILE_E; + ret = WS_FATAL_ERROR; + state->state = STATE_PUT_CLEANUP; + continue; + } + } + } ret = WFOPEN(ssh->fs, &state->fl, from, "rb"); if (ret != 0) { WLOG(WS_LOG_SFTP, "Unable to open input file"); diff --git a/wolfssh/error.h b/wolfssh/error.h index 598ec1a48..d1fdfdd27 100644 --- a/wolfssh/error.h +++ b/wolfssh/error.h @@ -131,8 +131,9 @@ enum WS_ErrorCodes { WS_KEY_AUTH_MAGIC_E = -1090, /* OpenSSH key auth magic check fail */ WS_KEY_CHECK_VAL_E = -1091, /* OpenSSH key check value fail */ WS_KEY_FORMAT_E = -1092, /* OpenSSH key format fail */ + WS_SFTP_NOT_FILE_E = -1093, /* Not a regular file */ - WS_LAST_E = -1092 /* Update this to indicate last error */ + WS_LAST_E = -1093 /* Update this to indicate last error */ }; diff --git a/wolfssh/wolfsftp.h b/wolfssh/wolfsftp.h index b0272b2d6..8fbbdbb77 100644 --- a/wolfssh/wolfsftp.h +++ b/wolfssh/wolfsftp.h @@ -126,6 +126,13 @@ struct WS_SFTP_FILEATRB_EX { WS_SFTP_FILEATRB_EX* next; }; +#define FILEATRB_PER_MASK_TYPE 0770000 +#define FILEATRB_PER_FILE 0100000 +#define FILEATRB_PER_DEV_CHAR 0020000 +#define FILEATRB_PER_DIR 0040000 +#define FILEATRB_PER_DEV_BLOCK 0060000 +#define FILEATRB_PER_MASK_PERM 0000777 + typedef struct WS_SFTP_FILEATRB { word32 flags; word32 sz[2]; /* sz[0] being the lower and sz[1] being the upper */