add -N flag to SFTP client

pull/134/head
Jacob Barthelmeh 2018-12-27 16:15:15 -07:00
parent 915b383cd3
commit db09f672f2
4 changed files with 184 additions and 56 deletions

View File

@ -298,7 +298,7 @@ int wolfSSH_SFTP_accept(WOLFSSH* ssh)
if ((ssh->error = SFTP_ServerRecvInit(ssh)) != WS_SUCCESS) {
return WS_FATAL_ERROR;
}
ssh->connectState = SFTP_RECV;
ssh->sftpState = SFTP_RECV;
FALL_THROUGH;
/* no break */
@ -306,7 +306,7 @@ int wolfSSH_SFTP_accept(WOLFSSH* ssh)
if ((ssh->error = SFTP_ServerSendInit(ssh)) != WS_SUCCESS) {
return WS_FATAL_ERROR;
}
ssh->connectState = SFTP_DONE;
ssh->sftpState = SFTP_DONE;
WLOG(WS_LOG_SFTP, "SFTP connection established");
break;
@ -2735,33 +2735,59 @@ static int SFTP_ClientRecvInit(WOLFSSH* ssh) {
word32 version = 0;
byte buf[LENGTH_SZ + MSG_ID_SZ + UINT32_SZ];
if ((len = wolfSSH_stream_read(ssh, buf, sizeof(buf))) != sizeof(buf)) {
return len;
}
switch (ssh->sftpState) {
case SFTP_RECV:
if ((len = wolfSSH_stream_read(ssh, buf, sizeof(buf)))
!= sizeof(buf)) {
/* @TODO partial read on small packet */
return len;
}
ato32(buf, &sz);
if (sz < MSG_ID_SZ + UINT32_SZ) {
return WS_BUFFER_E;
}
ato32(buf, &sz);
if (sz < MSG_ID_SZ + UINT32_SZ) {
return WS_BUFFER_E;
}
/* expecting */
id = buf[LENGTH_SZ];
if (id != WOLFSSH_FTP_VERSION) {
WLOG(WS_LOG_SFTP, "Unexpected SFTP type received");
return WS_BUFFER_E;
}
/* expecting */
id = buf[LENGTH_SZ];
if (id != WOLFSSH_FTP_VERSION) {
WLOG(WS_LOG_SFTP, "Unexpected SFTP type received");
return WS_BUFFER_E;
}
ato32(buf + LENGTH_SZ + MSG_ID_SZ, &version);
ato32(buf + LENGTH_SZ + MSG_ID_SZ, &version);
sz = sz - MSG_ID_SZ - UINT32_SZ;
ssh->sftpExtSz = sz;
ssh->sftpState = SFTP_EXT;
FALL_THROUGH;
/* no break */
case SFTP_EXT:
/* silently ignore extensions if not supported */
if (ssh->sftpExtSz > 0) {
byte* data = (byte*)WMALLOC(ssh->sftpExtSz, ssh->ctx->heap,
DYNTYPE_BUFFER);
if (data == NULL) return WS_MEMORY_E;
if ((len = wolfSSH_stream_read(ssh, data, ssh->sftpExtSz))
<= 0) {
WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER);
return len;
}
WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER);
/* case where expecting more */
if (len < ssh->sftpExtSz) {
ssh->sftpExtSz -= len;
ssh->error = WS_WANT_READ;
return WS_FATAL_ERROR;
}
}
break;
default:
WLOG(WS_LOG_SFTP, "Unexpected SFTP connect state");
return WS_FATAL_ERROR;
/* silently ignore extensions if not supported */
sz = sz - MSG_ID_SZ - UINT32_SZ;
if (sz > 0) {
byte* data = (byte*)WMALLOC(sz, NULL, DYNTYPE_BUFFER);
if (data == NULL) return WS_MEMORY_E;
if ((len = wolfSSH_stream_read(ssh, data, sz)) != (int)sz) {
return len;
}
WFREE(data, NULL, DYNTYPE_BUFFER);
}
ssh->reqId++;
@ -2791,16 +2817,19 @@ static int SFTP_ClientSendInit(WOLFSSH* ssh) {
/* Completes SFTP connection to server
* returns WS_SFTP_COMPLETE on success
* returns WS_SUCCESS on success
*/
int wolfSSH_SFTP_connect(WOLFSSH* ssh)
{
int ret = WS_SFTP_COMPLETE;
int ret = WS_SUCCESS;
if (ssh == NULL) {
return WS_BAD_ARGUMENT;
}
if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE)
ssh->error = WS_SUCCESS;
/* check connect is done, if not call wolfSSH connect */
if (ssh->connectState < CONNECT_SERVER_CHANNEL_REQUEST_DONE) {
byte name[] = "sftp";
@ -2822,15 +2851,16 @@ int wolfSSH_SFTP_connect(WOLFSSH* ssh)
if ((ssh->error = SFTP_ClientSendInit(ssh)) != WS_SUCCESS) {
return WS_FATAL_ERROR;
}
ssh->connectState = SFTP_RECV;
ssh->sftpState = SFTP_RECV;
FALL_THROUGH;
/* no break */
case SFTP_RECV:
case SFTP_EXT:
if ((ssh->error = SFTP_ClientRecvInit(ssh)) != WS_SUCCESS) {
return WS_FATAL_ERROR;
}
ssh->connectState = SFTP_DONE;
ssh->sftpState = SFTP_DONE;
WLOG(WS_LOG_SFTP, "SFTP connection established");
break;
@ -2891,7 +2921,7 @@ int SendPacketType(WOLFSSH* ssh, byte type, byte* buf, word32 bufSz)
return WS_BAD_ARGUMENT;
}
if (ssh->connectState != SFTP_DONE) {
if (ssh->sftpState != SFTP_DONE) {
WLOG(WS_LOG_SFTP, "SFTP connection not complete, trying to finish");
ret = wolfSSH_SFTP_negotiate(ssh);
}

View File

@ -34,6 +34,7 @@
int doCmds(void);
/* static so that signal handler can access and interrupt get/put */
static WOLFSSH* ssh = NULL;
static char* workingDir;
WFILE* fin;
@ -49,6 +50,43 @@ static void myStatusCb(WOLFSSH* sshIn, long bytes, char* name)
(void)sshIn;
}
static int NonBlockSSH_connect(void)
{
int ret;
int error;
SOCKET_T sockfd;
int select_ret = 0;
ret = wolfSSH_SFTP_connect(ssh);
error = wolfSSH_get_error(ssh);
sockfd = (SOCKET_T)wolfSSH_get_fd(ssh);
while (ret != WS_SUCCESS &&
(error == WS_WANT_READ || error == WS_WANT_WRITE))
{
if (error == WS_WANT_READ)
printf("... client would read block\n");
else if (error == WS_WANT_WRITE)
printf("... client would write block\n");
select_ret = tcp_select(sockfd, 1);
if (select_ret == WS_SELECT_RECV_READY ||
select_ret == WS_SELECT_ERROR_READY)
{
ret = wolfSSH_SFTP_connect(ssh);
error = wolfSSH_get_error(ssh);
}
else if (select_ret == WS_SELECT_TIMEOUT)
error = WS_WANT_READ;
else
error = WS_FATAL_ERROR;
}
return ret;
}
#ifndef WS_NO_SIGNAL
/* for command reget and reput to handle saving offset after interrupt during
* get and put */
@ -230,6 +268,7 @@ static void ShowUsage(void)
printf(" -p <num> port to connect on, default %d\n", wolfSshPort);
printf(" -u <username> username to authenticate as (REQUIRED)\n");
printf(" -P <password> password for username, prompted if omitted\n");
printf(" -N use non blocking sockets\n");
ShowCommands();
}
@ -282,12 +321,13 @@ static int wsUserAuth(byte authType,
int doCmds()
{
byte quit = 0;
int ret;
int ret, err;
byte resume = 0;
int i;
fin = stdin ;
fout = stdout ;
while (!quit) {
char msg[WOLFSSH_MAX_FILENAME * 2];
char* pt;
@ -321,16 +361,21 @@ int doCmds()
pt = f;
}
if ((ret = wolfSSH_SFTP_MKDIR(ssh, pt, &atrb)) != WS_SUCCESS) {
if (ret == WS_PERMISSIONS) {
if (WFPUTS("Insufficient permissions\n", fout) < 0)
err_sys("fputs error");
do {
err = WS_SUCCESS;
if ((ret = wolfSSH_SFTP_MKDIR(ssh, pt, &atrb)) != WS_SUCCESS) {
err = wolfSSH_get_error(ssh);
if (ret == WS_PERMISSIONS) {
if (WFPUTS("Insufficient permissions\n", fout) < 0)
err_sys("fputs error");
}
else if (err != WS_WANT_READ && err != WS_WANT_WRITE) {
if (WFPUTS("Error writing directory\n", fout) < 0)
err_sys("fputs error");
}
}
else {
if (WFPUTS("Error writing directory\n", fout) < 0)
err_sys("fputs error");
}
}
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
&& ret != WS_SUCCESS);
XFREE(f, NULL, DYNAMIC_TYPE_TMP_BUFFER);
continue;
}
@ -486,14 +531,18 @@ int doCmds()
}
if (wolfSSH_SFTP_Put(ssh, pt, to, resume, &myStatusCb)
!= WS_SUCCESS) {
do {
ret = wolfSSH_SFTP_Put(ssh, pt, to, resume, &myStatusCb);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
&& ret != WS_SUCCESS);
if (ret != WS_SUCCESS) {
if (WFPUTS("Error pushing file\n", fout) < 0)
err_sys("fputs error");
err_sys("fputs error");
}
else {
if (WFPUTS("\n", fout) < 0) /* new line after status output */
err_sys("fputs error");
err_sys("fputs error");
}
resume = 0;
XFREE(f, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@ -527,11 +576,17 @@ int doCmds()
}
/* check directory is valid */
if ((ret = wolfSSH_SFTP_STAT(ssh, pt, &atrb)) != WS_SUCCESS) {
do {
ret = wolfSSH_SFTP_STAT(ssh, pt, &atrb);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
&& ret != WS_SUCCESS);
if (ret != WS_SUCCESS) {
if (WFPUTS("Error changing directory\n", fout) < 0)
err_sys("fputs error");
err_sys("fputs error");
}
else {
if (ret == WS_SUCCESS) {
sz = (int)WSTRLEN(pt);
XFREE(workingDir, NULL, DYNAMIC_TYPE_TMP_BUFFER);
workingDir = (char*)XMALLOC(sz + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@ -594,8 +649,14 @@ int doCmds()
}
/* update permissions */
if (wolfSSH_SFTP_CHMOD(ssh, pt, mode) != WS_SUCCESS) {
printf("unable to change path permissions\n");
do {
ret = wolfSSH_SFTP_CHMOD(ssh, pt, mode);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
&& ret != WS_SUCCESS);
if (ret != WS_SUCCESS) {
if (WFPUTS("Unable to change path permissions\n", fout) < 0)
err_sys("fputs error");
}
XFREE(f, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@ -627,7 +688,12 @@ int doCmds()
pt = f;
}
if ((ret = wolfSSH_SFTP_RMDIR(ssh, pt)) != WS_SUCCESS) {
do {
ret = wolfSSH_SFTP_RMDIR(ssh, pt);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
&& ret != WS_SUCCESS);
if (ret != WS_SUCCESS) {
if (ret == WS_PERMISSIONS) {
if (WFPUTS("Insufficient permissions\n", fout) < 0)
err_sys("fputs error");
@ -664,7 +730,12 @@ int doCmds()
pt = f;
}
if ((ret = wolfSSH_SFTP_Remove(ssh, pt)) != WS_SUCCESS) {
do {
ret = wolfSSH_SFTP_Remove(ssh, pt);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
&& ret != WS_SUCCESS);
if (ret != WS_SUCCESS) {
if (ret == WS_PERMISSIONS) {
if (WFPUTS("Insufficient permissions\n", fout) < 0)
err_sys("fputs error");
@ -735,7 +806,12 @@ int doCmds()
to = fTo;
}
if ((ret = wolfSSH_SFTP_Rename(ssh, pt, to)) != WS_SUCCESS) {
do {
ret = wolfSSH_SFTP_Rename(ssh, pt, to);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
&& ret != WS_SUCCESS);
if (ret != WS_SUCCESS) {
if (WFPUTS("Error with rename\n", fout) < 0)
err_sys("fputs error");
}
@ -747,10 +823,19 @@ int doCmds()
if ((pt = WSTRNSTR(msg, "ls", sizeof(msg))) != NULL) {
WS_SFTPNAME* tmp;
WS_SFTPNAME* current = wolfSSH_SFTP_LS(ssh, workingDir);
WS_SFTPNAME* current;
do {
current = wolfSSH_SFTP_LS(ssh, workingDir);
err = wolfSSH_get_error(ssh);
} while ((err == WS_WANT_READ || err == WS_WANT_WRITE)
&& current == NULL && err != WS_SUCCESS);
tmp = current;
while (tmp != NULL) {
printf("%s\n", tmp->fName);
if (WFPUTS(tmp->fName, fout) < 0)
err_sys("fputs error");
if (WFPUTS("\n", fout) < 0)
err_sys("fputs error");
tmp = tmp->next;
}
wolfSSH_SFTPNAME_list_free(current);
@ -799,12 +884,13 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args)
char* host = (char*)wolfSshIp;
const char* username = NULL;
const char* password = NULL;
byte nonBlock = 0;
int argc = ((func_args*)args)->argc;
char** argv = ((func_args*)args)->argv;
((func_args*)args)->return_code = 0;
while ((ch = mygetopt(argc, argv, "?h:p:u:P:")) != -1) {
while ((ch = mygetopt(argc, argv, "?h:p:u:P:N")) != -1) {
switch (ch) {
case 'h':
host = myoptarg;
@ -826,6 +912,10 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args)
password = myoptarg;
break;
case 'N':
nonBlock = 1;
break;
case '?':
ShowUsage();
exit(EXIT_SUCCESS);
@ -871,11 +961,17 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args)
if (ret != 0)
err_sys("Couldn't connect to server.");
if (nonBlock)
tcp_set_nonblocking(&sockFd);
ret = wolfSSH_set_fd(ssh, (int)sockFd);
if (ret != WS_SUCCESS)
err_sys("Couldn't set the session's socket.");
ret = wolfSSH_SFTP_connect(ssh);
if (!nonBlock)
ret = wolfSSH_SFTP_connect(ssh);
else
ret = NonBlockSSH_connect();
if (ret != WS_SUCCESS)
err_sys("Couldn't connect SFTP");

View File

@ -385,6 +385,7 @@ struct WOLFSSH {
word32 reqId;
byte sftpState;
byte sftpInt;
byte sftpExtSz; /* size of extension buffer (buffer not currently used) */
SFTP_OFST sftpOfst[WOLFSSH_MAX_SFTPOFST];
#ifdef WOLFSSH_STOREHANDLE
WS_HANDLE_LIST* handleList;

View File

@ -78,6 +78,7 @@ enum WS_SFTPStatus {
enum WS_SFTPConnectStates {
SFTP_BEGIN = 20,
SFTP_RECV,
SFTP_EXT,
SFTP_DONE,
};