mirror of https://github.com/wolfSSL/wolfssh.git
add -N flag to SFTP client
parent
915b383cd3
commit
db09f672f2
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -78,6 +78,7 @@ enum WS_SFTPStatus {
|
|||
enum WS_SFTPConnectStates {
|
||||
SFTP_BEGIN = 20,
|
||||
SFTP_RECV,
|
||||
SFTP_EXT,
|
||||
SFTP_DONE,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue