Modify the code to truely support non-blocking. Propogate the EAGAIN error
all the way up to the user interface. All code modules bug sftp.c have been completed. Functions that return an "int", or similar return LIBSSH2CHANNEL_EAGAIN to indicate some part of the call would block, in non-blocking mode. Functions that return a structure, like "LIBSSH2_CHANNEL *", return NULL and set the libssh2 error. The error can be obtained with either libssh2_session_last_error() or libssh2_session_last_errno(). Either of these will return the error code of LIBSSH2_ERROR_EAGAIN if the call would block, in non-blocking mode. The current state of a function and some variable are keep in the structures so that on the next call the operation that would block can be retried again with the same data.
Этот коммит содержится в:
родитель
9896c291e4
Коммит
4b8db8c1ab
@ -1,4 +1,4 @@
|
||||
# $Id: Makefile.am,v 1.5 2007/04/22 19:51:53 jehousley Exp $
|
||||
# $Id: Makefile.am,v 1.6 2007/06/06 12:34:06 jehousley Exp $
|
||||
|
||||
EXTRA_DIST = template.3
|
||||
|
||||
@ -10,4 +10,5 @@ dist_man_MANS = libssh2_channel_forward_accept.3 \
|
||||
libssh2_session_free.3 libssh2_poll.3 libssh2_poll_channel_read.3 \
|
||||
libssh2_sftp_read.3 libssh2_sftp_readnb.3 libssh2_sftp_readdir.3 \
|
||||
libssh2_sftp_readdirnb.3 libssh2_sftp_mkdir_ex.3 \
|
||||
libssh2_sftp_mkdirnb_ex.3
|
||||
libssh2_sftp_mkdirnb_ex.3 libssh2_session_disconnect_ex.3 \
|
||||
libssh2_channel_wait_eof.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" $Id: libssh2_channel_forward_accept.3,v 1.1 2006/12/21 14:09:12 bagder Exp $
|
||||
.\" $Id: libssh2_channel_forward_accept.3,v 1.2 2007/06/06 12:34:06 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_forward_accept 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.TH libssh2_channel_forward_accept 3 "1 June 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_forward_accept - accept a queued connection
|
||||
.SH SYNOPSIS
|
||||
@ -12,5 +12,8 @@ libssh2_channel_forward_accept - accept a queued connection
|
||||
\fBlibssh2_channel_forward_listen(3)\fP.
|
||||
.SH RETURN VALUE
|
||||
A newly allocated channel instance or NULL on failure.
|
||||
.SH ERRORS
|
||||
LIBSSH2_ERROR_EAGAIN
|
||||
Marked for non-blocking I/O but the call would block.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_channel_forward_listen(3)
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" $Id: libssh2_channel_forward_listen_ex.3,v 1.2 2007/04/12 21:30:03 dfandrich Exp $
|
||||
.\" $Id: libssh2_channel_forward_listen_ex.3,v 1.3 2007/06/06 12:34:06 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_forward_listen_ex 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.TH libssh2_channel_forward_listen_ex 3 "1 June 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_forward_listen_ex - listen to inbound connections
|
||||
.SH SYNOPSIS
|
||||
@ -36,5 +36,8 @@ rejecting further attempts.
|
||||
\fIlibssh2_channel_forward_listen(3)\fP is a macro.
|
||||
.SH RETURN VALUE
|
||||
A newly allocated LIBSSH2_LISTENER instance or NULL on failure.
|
||||
.SH ERRORS
|
||||
LIBSSH2_ERROR_EAGAIN
|
||||
Marked for non-blocking I/O but the call would block.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_channel_forward_accept(3)
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" $Id: libssh2_channel_read_ex.3,v 1.5 2007/02/23 10:20:56 bagder Exp $
|
||||
.\" $Id: libssh2_channel_read_ex.3,v 1.6 2007/06/06 12:34:06 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_read_ex 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.TH libssh2_channel_read_ex 3 "1 June 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_read_ex - read data from a channel stream
|
||||
.SH SYNOPSIS
|
||||
@ -31,6 +31,8 @@ currently defines a stream ID of 1 to be the stderr substream.
|
||||
\fIlibssh2_channel_read(3)\fP and \fIlibssh2_channel_read_stderr(3)\fP are
|
||||
macros.
|
||||
.SH RETURN VALUE
|
||||
Actual number of bytes read or negative on failure.
|
||||
Actual number of bytes read or negative on failure. It returns
|
||||
LIBSSH2CHANNEL_EAGAIN when it would otherwise block. While
|
||||
LIBSSH2CHANNEL_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
.SH "SEE ALSO"
|
||||
.BR libssh2_poll_channel_read(3)
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" $Id: libssh2_channel_readnb_ex.3,v 1.2 2007/02/23 10:20:56 bagder Exp $
|
||||
.\" $Id: libssh2_channel_readnb_ex.3,v 1.3 2007/06/06 12:34:06 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_read_ex 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.TH libssh2_channel_read_ex 3 "1 June 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_read_ex - read data from a channel stream
|
||||
.SH SYNOPSIS
|
||||
|
19
docs/libssh2_channel_wait_eof.3
Обычный файл
19
docs/libssh2_channel_wait_eof.3
Обычный файл
@ -0,0 +1,19 @@
|
||||
.\" $Id: libssh2_channel_wait_eof.3,v 1.1 2007/06/06 12:34:06 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_wait_eof 3 "1 June 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_wait_eof - wait for the remote to reply to an EOF request
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel);
|
||||
|
||||
.SH DESCRIPTION
|
||||
Wait for the remote end to acknowledge an EOF request.
|
||||
|
||||
.SH RETURN VALUE
|
||||
Return 0 on success or negative on failure. It returns
|
||||
LIBSSH2CHANNEL_EAGAIN when it would otherwise block. While
|
||||
LIBSSH2CHANNEL_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_channel_send_eof(3), libssh2_channel_eof(3)
|
@ -1,19 +1,19 @@
|
||||
.\" $Id: libssh2_channel_write_ex.3,v 1.1 2007/02/23 10:20:56 bagder Exp $
|
||||
.\" $Id: libssh2_channel_write_ex.3,v 1.2 2007/06/06 12:34:06 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_write_ex 3 "6 Feb 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.TH libssh2_channel_write_ex 3 "1 June 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_write_ex - write data to a channel stream blocking
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
char *buf, size_t buflen);
|
||||
size_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
int libssh2_channel_write(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
size_t libssh2_channel_write(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
|
||||
int libssh2_channel_write_stderr(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
size_t libssh2_channel_write_stderr(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
.SH DESCRIPTION
|
||||
Write data to a channel stream. All channel streams have one standard I/O
|
||||
substream (stream_id == 0), and may have up to 2^32 extended data streams as
|
||||
@ -32,6 +32,8 @@ defines a stream ID of 1 to be the stderr substream.
|
||||
macros.
|
||||
.SH RETURN VALUE
|
||||
Actual number of bytes written or negative on failure.
|
||||
LIBSSH2CHANNEL_EAGAIN when it would otherwise block. While
|
||||
LIBSSH2CHANNEL_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
.SH "SEE ALSO"
|
||||
.BR libssh2_channel_open_session(3)
|
||||
.BR libssh2_channel_read(3)
|
||||
|
20
docs/libssh2_session_disconnect_ex.3
Обычный файл
20
docs/libssh2_session_disconnect_ex.3
Обычный файл
@ -0,0 +1,20 @@
|
||||
.\" $Id: libssh2_session_disconnect_ex.3,v 1.1 2007/06/06 12:34:07 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_session_disconnect_ex 3 "1 June 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_disconnect_ex - terminate transport layer
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int ibssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang);
|
||||
.SH DESCRIPTION
|
||||
Terminates the transport layer connection with the remote host.
|
||||
Note that all authentication and connection layer objects become unusable
|
||||
at this point and should be explicitly freed prior to disconnection.
|
||||
.SH RETURN VALUE
|
||||
0 on success, \-1 on failure
|
||||
.SH ERRORS
|
||||
LIBSSH2_ERROR_EAGAIN
|
||||
Marked for non-blocking I/O but the call would block.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_session_init(3)
|
@ -1,6 +1,6 @@
|
||||
.\" $Id: libssh2_session_init.3,v 1.2 2007/04/12 21:30:03 dfandrich Exp $
|
||||
.\" $Id: libssh2_session_init.3,v 1.3 2007/06/06 12:34:07 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_session_init 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.TH libssh2_session_init 3 "1 June 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_init - initializes an SSH session object
|
||||
.SH SYNOPSIS
|
||||
@ -24,6 +24,9 @@ This method must be called first, prior to configuring session options or
|
||||
starting up an SSH session with a remote server.
|
||||
.SH RETURN VALUE
|
||||
Pointer to a newly allocated LIBSSH2_SESSION instance, or NULL on errors.
|
||||
.SH ERRORS
|
||||
LIBSSH2_ERROR_EAGAIN
|
||||
Marked for non-blocking I/O but the call would block.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_session_free(3),
|
||||
.BI libssh2_session_startup(3)
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" $Id: libssh2_session_startup.3,v 1.2 2007/01/02 05:47:00 gusarov Exp $
|
||||
.\" $Id: libssh2_session_startup.3,v 1.3 2007/06/06 12:34:07 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_session_startup 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.TH libssh2_session_startup 3 "1 June 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_startup - begin transport layer
|
||||
.SH SYNOPSIS
|
||||
@ -11,6 +11,27 @@ int libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
|
||||
Begin transport layer protocol negotiation with the connected host.
|
||||
.SH RETURN VALUE
|
||||
0 on success, \-1 on failure
|
||||
.SH ERRORS
|
||||
LIBSSH2_ERROR_SOCKET_NONE
|
||||
Bad socket provided.
|
||||
.br
|
||||
LIBSSH2_ERROR_BANNER_SEND
|
||||
Error sending banner to remote host.
|
||||
.br
|
||||
LIBSSH2_ERROR_KEX_FAILURE
|
||||
Unable to exchange encryption keys.
|
||||
.br
|
||||
LIBSSH2_ERROR_SOCKET_SEND
|
||||
Unable to ask for ssh-userauth service.
|
||||
.br
|
||||
LIBSSH2_ERROR_SOCKET_DISCONNECT
|
||||
Connection was lost.
|
||||
.br
|
||||
LIBSSH2_ERROR_PROTO
|
||||
Invalid response received from server.
|
||||
.br
|
||||
LIBSSH2_ERROR_EAGAIN
|
||||
Marked for non-blocking I/O but the call would block.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_session_free(3),
|
||||
.BI libssh2_session_init(3)
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" $Id: libssh2_sftp_init.3,v 1.2 2007/04/22 17:18:03 jehousley Exp $
|
||||
.\" $Id: libssh2_sftp_init.3,v 1.3 2007/06/06 12:34:07 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_sftp_init 3 "23 Jan 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.TH libssh2_sftp_init 3 "1 June 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_sftp_init -
|
||||
.SH SYNOPSIS
|
||||
@ -17,5 +17,8 @@ session is complete, it must be destroyed using the
|
||||
\fIlibssh2_sftp_shutdown(3)\fP function.
|
||||
.SH RETURN VALUE
|
||||
A pointer to the newly allocated SFTP instance or NULL on failure.
|
||||
.SH ERRORS
|
||||
LIBSSH2_ERROR_EAGAIN
|
||||
Marked for non-blocking I/O but the call would block.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_sftp_shutdown(3), libssh2_sftp_open_ex(3)
|
||||
|
@ -3,6 +3,7 @@ AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
# samples
|
||||
noinst_PROGRAMS = ssh2 \
|
||||
scp scp_nonblock \
|
||||
scp_write scp_write_nonblock \
|
||||
sftp sftp_nonblock \
|
||||
sftp_write sftp_write_nonblock \
|
||||
sftp_mkdir sftp_mkdir_nonblock \
|
||||
@ -18,6 +19,10 @@ scp_SOURCES = scp.c
|
||||
|
||||
scp_nonblock_SOURCES = scp_nonblock.c
|
||||
|
||||
scp_write_SOURCES = scp_write.c
|
||||
|
||||
scp_write_nonblock_SOURCES = scp_write_nonblock.c
|
||||
|
||||
sftp_SOURCES = sftp.c
|
||||
|
||||
sftp_nonblock_SOURCES = sftp_nonblock.c
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: scp.c,v 1.6 2007/04/26 23:59:14 gknauf Exp $
|
||||
* $Id: scp.c,v 1.7 2007/06/06 12:34:08 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do a simple SCP transfer.
|
||||
*/
|
||||
@ -19,6 +19,9 @@
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
@ -31,140 +34,142 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *scppath=(char *)"/tmp/TEST";
|
||||
struct stat fileinfo;
|
||||
int rc;
|
||||
off_t got=0;
|
||||
unsigned long hostaddr;
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *scppath=(char *)"/tmp/TEST";
|
||||
struct stat fileinfo;
|
||||
int rc;
|
||||
off_t got=0;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
if (argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if (argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if (argc > 4) {
|
||||
scppath = argv[4];
|
||||
}
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = htonl(0x7F000001);
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* trace transport layer stuff*/
|
||||
libssh2_trace(session, LIBSSH2_TRACE_TRANS);
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
fprintf(stderr, "Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
fprintf(stderr, "\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
if(argc > 1) {
|
||||
username = argv[1];
|
||||
}
|
||||
if(argc > 2) {
|
||||
password = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
scppath = argv[3];
|
||||
}
|
||||
/* Request a file via SCP */
|
||||
channel = libssh2_scp_recv(session, scppath, &fileinfo);
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
/* Request a file via SCP */
|
||||
channel = libssh2_scp_recv(session, scppath, &fileinfo);
|
||||
|
||||
if (!channel) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
if (!channel) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
|
||||
while(got < fileinfo.st_size) {
|
||||
char mem[1024];
|
||||
int amount=sizeof(mem);
|
||||
while(got < fileinfo.st_size) {
|
||||
char mem[1024];
|
||||
int amount=sizeof(mem);
|
||||
|
||||
if((fileinfo.st_size -got) < amount) {
|
||||
amount = fileinfo.st_size -got;
|
||||
}
|
||||
if((fileinfo.st_size -got) < amount) {
|
||||
amount = fileinfo.st_size -got;
|
||||
}
|
||||
|
||||
rc = libssh2_channel_read(channel, mem, amount);
|
||||
if(rc == amount) {
|
||||
write(2, mem, rc);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "libssh2_channel_read() failed: %d\n",
|
||||
rc);
|
||||
break;
|
||||
}
|
||||
got += rc;
|
||||
}
|
||||
rc = libssh2_channel_read(channel, mem, amount);
|
||||
if(rc == amount) {
|
||||
write(1, mem, rc);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "libssh2_channel_read() failed: %d\n", rc);
|
||||
break;
|
||||
}
|
||||
got += rc;
|
||||
}
|
||||
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
fprintf(stderr, "all done\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: scp_nonblock.c,v 1.3 2007/04/26 23:59:14 gknauf Exp $
|
||||
* $Id: scp_nonblock.c,v 1.4 2007/06/06 12:34:08 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do SCP transfers in a non-blocking manner.
|
||||
*/
|
||||
@ -19,6 +19,9 @@
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
@ -31,172 +34,183 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *scppath=(char *)"/tmp/TEST";
|
||||
struct stat fileinfo;
|
||||
int rc;
|
||||
off_t got=0;
|
||||
|
||||
unsigned long hostaddr;
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *scppath=(char *)"/tmp/TEST";
|
||||
struct stat fileinfo;
|
||||
int rc;
|
||||
off_t got=0;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = htonl(0x7F000001);
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We set the socket non-blocking. We do it after the connect just to
|
||||
simplify the example code. */
|
||||
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
if (argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if (argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if (argc > 4) {
|
||||
scppath = argv[4];
|
||||
}
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We set the socket non-blocking. We do it after the connect just to
|
||||
simplify the example code. */
|
||||
#ifdef F_SETFL
|
||||
/* FIXME: this can/should be done in a more portable manner */
|
||||
rc = fcntl(sock, F_GETFL, 0);
|
||||
fcntl(sock, F_SETFL, rc | O_NONBLOCK);
|
||||
/* FIXME: this can/should be done in a more portable manner */
|
||||
rc = fcntl(sock, F_GETFL, 0);
|
||||
fcntl(sock, F_SETFL, rc | O_NONBLOCK);
|
||||
#else
|
||||
#error "add support for setting the socket non-blocking here"
|
||||
#endif
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(argc > 1) {
|
||||
username = argv[1];
|
||||
}
|
||||
if(argc > 2) {
|
||||
password = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
scppath = argv[3];
|
||||
}
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
/* Request a file via SCP */
|
||||
channel = libssh2_scp_recv(session, scppath, &fileinfo);
|
||||
|
||||
if (!channel) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
fprintf(stderr, "libssh2_scp_recv() is done, now receive data!\n");
|
||||
|
||||
while(got < fileinfo.st_size) {
|
||||
char mem[1000];
|
||||
|
||||
struct timeval timeout;
|
||||
int rc;
|
||||
fd_set fd;
|
||||
|
||||
do {
|
||||
int amount=sizeof(mem);
|
||||
|
||||
if((fileinfo.st_size -got) < amount) {
|
||||
amount = fileinfo.st_size -got;
|
||||
}
|
||||
|
||||
/* loop until we block */
|
||||
rc = libssh2_channel_readnb(channel, mem, amount);
|
||||
if(rc > 0) {
|
||||
write(2, mem, rc);
|
||||
got += rc;
|
||||
}
|
||||
} while (rc > 0);
|
||||
|
||||
if(rc == LIBSSH2CHANNEL_EAGAIN) {
|
||||
/* this is due to blocking that would occur otherwise
|
||||
so we loop on this condition */
|
||||
|
||||
timeout.tv_sec = 10;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&fd);
|
||||
|
||||
FD_SET(sock, &fd);
|
||||
|
||||
rc = select(sock+1, &fd, &fd, NULL, &timeout);
|
||||
if(rc <= 0) {
|
||||
/* negative is error
|
||||
0 is timeout */
|
||||
fprintf(stderr, "SCP timed out: %d\n", rc);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session,
|
||||
"Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
|
||||
/* Create a session instance */
|
||||
session = libssh2_session_init();
|
||||
if (!session)
|
||||
return -1;
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are non-blocking */
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
while ((rc = libssh2_session_startup(session, sock)) == LIBSSH2_ERROR_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
while ((rc = libssh2_userauth_password(session, username, password)) == LIBSSH2CHANNEL_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
while ((rc = libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) == LIBSSH2CHANNEL_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
/* Request a file via SCP */
|
||||
fprintf(stderr, "libssh2_scp_recv()!\n");
|
||||
do {
|
||||
channel = libssh2_scp_recv(session, scppath, &fileinfo);
|
||||
|
||||
if ((!channel) && (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} while (!channel);
|
||||
fprintf(stderr, "libssh2_scp_recv() is done, now receive data!\n");
|
||||
|
||||
while(got < fileinfo.st_size) {
|
||||
char mem[1000];
|
||||
|
||||
struct timeval timeout;
|
||||
int rc;
|
||||
fd_set fd;
|
||||
|
||||
do {
|
||||
int amount=sizeof(mem);
|
||||
|
||||
if ((fileinfo.st_size -got) < amount) {
|
||||
amount = fileinfo.st_size - got;
|
||||
}
|
||||
|
||||
/* loop until we block */
|
||||
rc = libssh2_channel_read(channel, mem, amount);
|
||||
if (rc > 0) {
|
||||
write(1, mem, rc);
|
||||
got += rc;
|
||||
}
|
||||
} while (rc > 0);
|
||||
|
||||
if (rc == LIBSSH2CHANNEL_EAGAIN) {
|
||||
/* this is due to blocking that would occur otherwise
|
||||
so we loop on this condition */
|
||||
|
||||
timeout.tv_sec = 10;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&fd);
|
||||
|
||||
FD_SET(sock, &fd);
|
||||
|
||||
rc = select(sock+1, &fd, &fd, NULL, &timeout);
|
||||
if (rc <= 0) {
|
||||
/* negative is error
|
||||
0 is timeout */
|
||||
fprintf(stderr, "SCP timed out: %d\n", rc);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
fprintf(stderr, "all done\n");
|
||||
return 0;
|
||||
}
|
||||
|
201
example/simple/scp_write.c
Обычный файл
201
example/simple/scp_write.c
Обычный файл
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* $Id: scp_write.c,v 1.1 2007/06/06 12:34:08 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do a simple SCP transfer.
|
||||
*/
|
||||
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_config.h>
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long hostaddr;
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *loclfile=(char *)"scp_write.c";
|
||||
char *scppath=(char *)"/tmp/TEST";
|
||||
FILE *local;
|
||||
int rc;
|
||||
char mem[1024];
|
||||
size_t nread;
|
||||
char *ptr;
|
||||
struct stat fileinfo;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
if (argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if (argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if(argc > 4) {
|
||||
loclfile = argv[4];
|
||||
}
|
||||
if (argc > 5) {
|
||||
scppath = argv[5];
|
||||
}
|
||||
|
||||
local = fopen(loclfile, "rb");
|
||||
if (!local) {
|
||||
fprintf(stderr, "Can't local file %s\n", loclfile);
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
stat(loclfile, &fileinfo);
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
fprintf(stderr, "Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
fprintf(stderr, "\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
//libssh2_trace(session, 0xFFFF);
|
||||
|
||||
/* Request a file via SCP */
|
||||
channel = libssh2_scp_send(session, scppath, 0x1FF & fileinfo.st_mode, (unsigned long)fileinfo.st_size);
|
||||
|
||||
if (!channel) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
fprintf(stderr, "SCP session waiting to send file\n");
|
||||
do {
|
||||
nread = fread(mem, 1, sizeof(mem), local);
|
||||
if (nread <= 0) {
|
||||
/* end of file */
|
||||
break;
|
||||
}
|
||||
ptr = mem;
|
||||
|
||||
do {
|
||||
/* write data in a loop until we block */
|
||||
rc = libssh2_channel_write(channel, ptr, nread);
|
||||
ptr += rc;
|
||||
nread -= nread;
|
||||
} while (rc > 0);
|
||||
} while (1);
|
||||
|
||||
fprintf(stderr, "Sending EOF\n");
|
||||
libssh2_channel_send_eof(channel);
|
||||
|
||||
fprintf(stderr, "Waiting for EOF\n");
|
||||
libssh2_channel_wait_eof(channel);
|
||||
|
||||
fprintf(stderr, "Waiting for channel to close\n");
|
||||
libssh2_channel_wait_closed(channel);
|
||||
|
||||
// fprintf(stderr, "Closing channel\n");
|
||||
// libssh2_channel_close(channel);
|
||||
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
fprintf(stderr, "all done\n");
|
||||
return 0;
|
||||
}
|
222
example/simple/scp_write_nonblock.c
Обычный файл
222
example/simple/scp_write_nonblock.c
Обычный файл
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* $Id: scp_write_nonblock.c,v 1.1 2007/06/06 12:34:08 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do a simple SCP transfer.
|
||||
*/
|
||||
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_config.h>
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long hostaddr;
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *loclfile=(char *)"scp_write.c";
|
||||
char *scppath=(char *)"/tmp/TEST";
|
||||
FILE *local;
|
||||
int rc;
|
||||
char mem[1024];
|
||||
size_t nread;
|
||||
char *ptr;
|
||||
struct stat fileinfo;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
if (argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if (argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if(argc > 4) {
|
||||
loclfile = argv[4];
|
||||
}
|
||||
if (argc > 5) {
|
||||
scppath = argv[5];
|
||||
}
|
||||
|
||||
local = fopen(loclfile, "rb");
|
||||
if (!local) {
|
||||
fprintf(stderr, "Can't local file %s\n", loclfile);
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
stat(loclfile, &fileinfo);
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We set the socket non-blocking. We do it after the connect just to
|
||||
simplify the example code. */
|
||||
#ifdef F_SETFL
|
||||
/* FIXME: this can/should be done in a more portable manner */
|
||||
rc = fcntl(sock, F_GETFL, 0);
|
||||
fcntl(sock, F_SETFL, rc | O_NONBLOCK);
|
||||
#else
|
||||
#error "add support for setting the socket non-blocking here"
|
||||
#endif
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are non-blocking */
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
while ((rc = libssh2_session_startup(session, sock))
|
||||
== LIBSSH2_ERROR_EAGAIN);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
while ((rc = libssh2_userauth_password(session, username, password)) == LIBSSH2CHANNEL_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
while ((rc = libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) == LIBSSH2CHANNEL_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
// libssh2_trace(session, 0xFF7D);
|
||||
|
||||
/* Request a file via SCP */
|
||||
do {
|
||||
channel = libssh2_scp_send(session, scppath, 0x1FF & fileinfo.st_mode, (unsigned long)fileinfo.st_size);
|
||||
|
||||
if ((!channel) && (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} while (!channel);
|
||||
|
||||
fprintf(stderr, "SCP session waiting to send file\n");
|
||||
do {
|
||||
nread = fread(mem, 1, sizeof(mem), local);
|
||||
if (nread <= 0) {
|
||||
/* end of file */
|
||||
break;
|
||||
}
|
||||
ptr = mem;
|
||||
|
||||
do {
|
||||
/* write data in a loop until we block */
|
||||
while ((rc = libssh2_channel_write(channel, ptr, nread)) == LIBSSH2CHANNEL_EAGAIN);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "ERROR %d\n", rc);
|
||||
}
|
||||
ptr += rc;
|
||||
nread -= rc;
|
||||
} while (nread > 0);
|
||||
} while (1);
|
||||
|
||||
fprintf(stderr, "Sending EOF\n");
|
||||
while (libssh2_channel_send_eof(channel) == LIBSSH2CHANNEL_EAGAIN);
|
||||
|
||||
fprintf(stderr, "Waiting for EOF\n");
|
||||
while (libssh2_channel_wait_eof(channel) == LIBSSH2CHANNEL_EAGAIN);
|
||||
|
||||
fprintf(stderr, "Waiting for channel to close\n");
|
||||
while (libssh2_channel_wait_closed(channel) == LIBSSH2CHANNEL_EAGAIN);
|
||||
|
||||
// fprintf(stderr, "Closing channel\n");
|
||||
// while (libssh2_channel_close(channel) == LIBSSH2CHANNEL_EAGAIN);
|
||||
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
|
||||
shutdown:
|
||||
|
||||
while ((rc = libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing")) == LIBSSH2CHANNEL_EAGAIN);
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
fprintf(stderr, "all done\n");
|
||||
return 0;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: sftp.c,v 1.7 2007/04/26 23:59:14 gknauf Exp $
|
||||
* $Id: sftp.c,v 1.8 2007/06/06 12:34:08 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP transfers.
|
||||
*
|
||||
@ -94,6 +94,9 @@ int main(int argc, char *argv[])
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are blocking */
|
||||
libssh2_session_set_blocking(session, 1);
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
@ -103,22 +106,25 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Since we have not set non-blocking, tell libssh2 we are blocking */
|
||||
libssh2_session_set_blocking(session, 1);
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
fprintf(stderr, "Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
@ -127,7 +133,7 @@ int main(int argc, char *argv[])
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
fprintf(stderr, "\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
@ -141,7 +147,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Since we have not set non-blocking, tell libssh2 we are blocking */
|
||||
libssh2_sftp_set_blocking(sftp_session, 1);
|
||||
libssh2_session_set_blocking(session, 1);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_open()!\n");
|
||||
/* Request a file via SFTP */
|
||||
@ -160,7 +166,7 @@ int main(int argc, char *argv[])
|
||||
fprintf(stderr, "libssh2_sftp_read()!\n");
|
||||
rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem));
|
||||
if (rc > 0) {
|
||||
write(2, mem, rc);
|
||||
write(1, mem, rc);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -181,6 +187,6 @@ int main(int argc, char *argv[])
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
fprintf(stderr, "all done\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: sftp_RW_nonblock.c,v 1.3 2007/04/26 23:59:15 gknauf Exp $
|
||||
* $Id: sftp_RW_nonblock.c,v 1.4 2007/06/06 12:34:08 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP transfers in a non-blocking manner.
|
||||
*
|
||||
@ -106,6 +106,8 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: sftp_mkdir.c,v 1.3 2007/04/26 23:59:15 gknauf Exp $
|
||||
* $Id: sftp_mkdir.c,v 1.4 2007/06/06 12:34:08 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP mkdir
|
||||
*
|
||||
@ -138,7 +138,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Since we have not set non-blocking, tell libssh2 we are blocking */
|
||||
libssh2_sftp_set_blocking(sftp_session, 1);
|
||||
libssh2_session_set_blocking(session, 1);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_mkdir()!\n");
|
||||
/* Make a directory via SFTP */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: sftp_mkdir_nonblock.c,v 1.3 2007/04/26 23:59:15 gknauf Exp $
|
||||
* $Id: sftp_mkdir_nonblock.c,v 1.4 2007/06/06 12:34:09 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP non-blocking mkdir.
|
||||
*
|
||||
@ -148,7 +148,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are non-blocking */
|
||||
libssh2_sftp_set_blocking(sftp_session, 0);
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_mkdirnb()!\n");
|
||||
/* Make a directory via SFTP */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: sftp_nonblock.c,v 1.7 2007/04/26 23:59:15 gknauf Exp $
|
||||
* $Id: sftp_nonblock.c,v 1.8 2007/06/06 12:34:09 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP non-blocking transfers.
|
||||
*
|
||||
@ -40,159 +40,162 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long hostaddr;
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *sftppath=(char *)"/tmp/TEST";
|
||||
int rc;
|
||||
LIBSSH2_SFTP *sftp_session;
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||
|
||||
unsigned long hostaddr;
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *sftppath=(char *)"/tmp/TEST";
|
||||
int rc;
|
||||
LIBSSH2_SFTP *sftp_session;
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
|
||||
if(argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if(argc > 4) {
|
||||
sftppath = argv[4];
|
||||
}
|
||||
/*
|
||||
* The application code is responsible for creating the socket
|
||||
* and establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We set the socket non-blocking. We do it after the connect just to
|
||||
simplify the example code. */
|
||||
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
|
||||
if (argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if (argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if (argc > 4) {
|
||||
sftppath = argv[4];
|
||||
}
|
||||
/*
|
||||
* The application code is responsible for creating the socket
|
||||
* and establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We set the socket non-blocking. We do it after the connect just to
|
||||
simplify the example code. */
|
||||
#ifdef F_SETFL
|
||||
/* FIXME: this can/should be done in a more portable manner */
|
||||
rc = fcntl(sock, F_GETFL, 0);
|
||||
fcntl(sock, F_SETFL, rc | O_NONBLOCK);
|
||||
/* FIXME: this can/should be done in a more portable manner */
|
||||
rc = fcntl(sock, F_GETFL, 0);
|
||||
fcntl(sock, F_SETFL, rc | O_NONBLOCK);
|
||||
#else
|
||||
#error "add support for setting the socket non-blocking here"
|
||||
#endif
|
||||
|
||||
/* Create a session instance */
|
||||
session = libssh2_session_init();
|
||||
if (!session)
|
||||
return -1;
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are non-blocking */
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
while ((rc = libssh2_session_startup(session, sock)) == LIBSSH2_ERROR_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
while ((rc = libssh2_userauth_password(session, username, password)) == LIBSSH2CHANNEL_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
while ((rc = libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) == LIBSSH2CHANNEL_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_init()!\n");
|
||||
do {
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_init()!\n");
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
|
||||
if (!sftp_session) {
|
||||
fprintf(stderr, "Unable to init SFTP session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are non-blocking */
|
||||
libssh2_sftp_set_blocking(sftp_session, 0);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_open()!\n");
|
||||
/* Request a file via SFTP */
|
||||
sftp_handle =
|
||||
libssh2_sftp_open(sftp_session, sftppath, LIBSSH2_FXF_READ, 0);
|
||||
|
||||
if (!sftp_handle) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
goto shutdown;
|
||||
}
|
||||
fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
|
||||
do {
|
||||
char mem[1024];
|
||||
|
||||
/* loop until we fail */
|
||||
fprintf(stderr, "libssh2_sftp_readnb()!\n");
|
||||
if ((!sftp_session) && (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
|
||||
fprintf(stderr, "Unable to init SFTP session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} while (!sftp_session);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_open()!\n");
|
||||
/* Request a file via SFTP */
|
||||
sftp_handle =
|
||||
libssh2_sftp_open(sftp_session, sftppath, LIBSSH2_FXF_READ, 0);
|
||||
|
||||
if (!sftp_handle) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
goto shutdown;
|
||||
}
|
||||
fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
|
||||
do {
|
||||
char mem[1024];
|
||||
|
||||
/* loop until we fail */
|
||||
fprintf(stderr, "libssh2_sftp_readnb()!\n");
|
||||
while ((rc = libssh2_sftp_readnb(sftp_handle, mem, sizeof(mem))) == LIBSSH2SFTP_EAGAIN) {
|
||||
;
|
||||
}
|
||||
if (rc > 0) {
|
||||
write(2, mem, rc);
|
||||
} else {
|
||||
break;
|
||||
if (rc > 0) {
|
||||
write(1, mem, rc);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
} while (1);
|
||||
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
|
||||
shutdown:
|
||||
|
||||
while ((rc = libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing")) == LIBSSH2_ERROR_EAGAIN);
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
fprintf(stderr, "all done\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: sftp_write.c,v 1.3 2007/04/26 23:59:15 gknauf Exp $
|
||||
* $Id: sftp_write.c,v 1.4 2007/06/06 12:34:09 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP write transfers.
|
||||
*
|
||||
@ -37,47 +37,47 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long hostaddr;
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
unsigned long hostaddr;
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *loclfile=(char *)"sftp_write.c";
|
||||
char *sftppath=(char *)"/tmp/TEST";
|
||||
int rc;
|
||||
char *sftppath=(char *)"/tmp/TEST";
|
||||
int rc;
|
||||
FILE *local;
|
||||
LIBSSH2_SFTP *sftp_session;
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||
LIBSSH2_SFTP *sftp_session;
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||
char mem[1024];
|
||||
size_t nread;
|
||||
char *ptr;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
|
||||
if(argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if(argc > 4) {
|
||||
loclfile = argv[4];
|
||||
}
|
||||
if(argc > 5) {
|
||||
sftppath = argv[5];
|
||||
}
|
||||
if(argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if(argc > 4) {
|
||||
loclfile = argv[4];
|
||||
}
|
||||
if(argc > 5) {
|
||||
sftppath = argv[5];
|
||||
}
|
||||
|
||||
local = fopen(loclfile, "rb");
|
||||
if (!local) {
|
||||
@ -85,90 +85,95 @@ int main(int argc, char *argv[])
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/*
|
||||
* The application code is responsible for creating the socket
|
||||
* and establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
/*
|
||||
* The application code is responsible for creating the socket
|
||||
* and establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
/* Since we have set non-blocking, tell libssh2 we are blocking */
|
||||
libssh2_session_set_blocking(session, 1);
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_init()!\n");
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
//libssh2_trace(session, 0xFFFF);
|
||||
|
||||
if (!sftp_session) {
|
||||
fprintf(stderr, "Unable to init SFTP session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
fprintf(stderr, "libssh2_sftp_init()!\n");
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
|
||||
/* Since we have not set non-blocking, tell libssh2 we are blocking */
|
||||
libssh2_sftp_set_blocking(sftp_session, 1);
|
||||
if (!sftp_session) {
|
||||
fprintf(stderr, "Unable to init SFTP session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* Since we have not set non-blocking, tell libssh2 we are blocking */
|
||||
libssh2_session_set_blocking(session, 1);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_open()!\n");
|
||||
/* Request a file via SFTP */
|
||||
sftp_handle =
|
||||
fprintf(stderr, "libssh2_sftp_open()!\n");
|
||||
/* Request a file via SFTP */
|
||||
sftp_handle =
|
||||
libssh2_sftp_open(sftp_session, sftppath,
|
||||
LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT,
|
||||
LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
|
||||
LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
|
||||
LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
|
||||
|
||||
if (!sftp_handle) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
goto shutdown;
|
||||
}
|
||||
fprintf(stderr, "libssh2_sftp_open() is done, now send data!\n");
|
||||
do {
|
||||
if (!sftp_handle) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
goto shutdown;
|
||||
}
|
||||
fprintf(stderr, "libssh2_sftp_open() is done, now send data!\n");
|
||||
do {
|
||||
nread = fread(mem, 1, sizeof(mem), local);
|
||||
if (nread <= 0) {
|
||||
/* end of file */
|
||||
@ -182,24 +187,24 @@ int main(int argc, char *argv[])
|
||||
ptr += rc;
|
||||
nread -= nread;
|
||||
} while (rc > 0);
|
||||
} while (1);
|
||||
} while (1);
|
||||
|
||||
fclose(local);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: sftp_write_nonblock.c,v 1.3 2007/04/26 23:59:15 gknauf Exp $
|
||||
* $Id: sftp_write_nonblock.c,v 1.4 2007/06/06 12:34:09 jehousley Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP non-blocking write transfers.
|
||||
*
|
||||
@ -53,29 +53,29 @@ int main(int argc, char *argv[])
|
||||
char mem[1024];
|
||||
size_t nread;
|
||||
char *ptr;
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
|
||||
if(argc > 2) {
|
||||
|
||||
if (argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
if (argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if(argc > 4) {
|
||||
if (argc > 4) {
|
||||
loclfile = argv[4];
|
||||
}
|
||||
if(argc > 5) {
|
||||
if (argc > 5) {
|
||||
sftppath = argv[5];
|
||||
}
|
||||
|
||||
@ -90,18 +90,18 @@ int main(int argc, char *argv[])
|
||||
* and establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* We set the socket non-blocking. We do it after the connect just to
|
||||
simplify the example code. */
|
||||
simplify the example code. */
|
||||
#ifdef F_SETFL
|
||||
/* FIXME: this can/should be done in a more portable manner */
|
||||
rc = fcntl(sock, F_GETFL, 0);
|
||||
@ -109,69 +109,77 @@ int main(int argc, char *argv[])
|
||||
#else
|
||||
#error "add support for setting the socket non-blocking here"
|
||||
#endif
|
||||
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
if (!session)
|
||||
return -1;
|
||||
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are non-blocking */
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
while ((rc = libssh2_session_startup(session, sock))
|
||||
== LIBSSH2_ERROR_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
while ((rc = libssh2_userauth_password(session, username, password)) == LIBSSH2CHANNEL_EAGAIN);
|
||||
if (rc) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
while ((rc = libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) == LIBSSH2CHANNEL_EAGAIN);
|
||||
if (rc) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_init()!\n");
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
|
||||
if (!sftp_session) {
|
||||
fprintf(stderr, "Unable to init SFTP session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
do {
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
|
||||
if ((!sftp_session) && (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
|
||||
fprintf(stderr, "Unable to init SFTP session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} while (!sftp_session);
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are non-blocking */
|
||||
libssh2_sftp_set_blocking(sftp_session, 0);
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_open()!\n");
|
||||
/* Request a file via SFTP */
|
||||
sftp_handle =
|
||||
libssh2_sftp_open(sftp_session, sftppath,
|
||||
LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT,
|
||||
LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
|
||||
LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
|
||||
LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
|
||||
LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
|
||||
LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
|
||||
|
||||
if (!sftp_handle) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
@ -195,16 +203,16 @@ int main(int argc, char *argv[])
|
||||
nread -= nread;
|
||||
} while (rc > 0);
|
||||
} while (1);
|
||||
|
||||
|
||||
fclose(local);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
|
||||
shutdown:
|
||||
|
||||
while ((rc = libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing")) == LIBSSH2_ERROR_EAGAIN);
|
||||
libssh2_session_free(session);
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
@ -212,6 +220,6 @@ int main(int argc, char *argv[])
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: sftpdir.c,v 1.4 2007/04/26 23:59:15 gknauf Exp $
|
||||
* $Id: sftpdir.c,v 1.5 2007/06/06 12:34:09 jehousley Exp $
|
||||
*
|
||||
* Sample doing an SFTP directory listing.
|
||||
*
|
||||
@ -138,7 +138,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Since we have not set non-blocking, tell libssh2 we are blocking */
|
||||
libssh2_sftp_set_blocking(sftp_session, 1);
|
||||
libssh2_session_set_blocking(session, 1);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_opendir()!\n");
|
||||
/* Request a dir listing via SFTP */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: sftpdir_nonblock.c,v 1.4 2007/04/26 23:59:15 gknauf Exp $
|
||||
* $Id: sftpdir_nonblock.c,v 1.5 2007/06/06 12:34:09 jehousley Exp $
|
||||
*
|
||||
* Sample doing an SFTP directory listing.
|
||||
*
|
||||
@ -148,7 +148,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are non-blocking */
|
||||
libssh2_sftp_set_blocking(sftp_session, 0);
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_opendir()!\n");
|
||||
/* Request a dir listing via SFTP */
|
||||
|
@ -76,7 +76,7 @@ typedef long long libssh2_int64_t;
|
||||
#endif
|
||||
|
||||
#define LIBSSH2_VERSION "0.15-CVS"
|
||||
#define LIBSSH2_APINO 200507211326
|
||||
#define LIBSSH2_APINO 200706012030
|
||||
|
||||
/* Part of every banner, user specified or not */
|
||||
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
|
||||
@ -222,6 +222,7 @@ typedef struct _LIBSSH2_POLLFD {
|
||||
#define SSH_DISCONNECT_ILLEGAL_USER_NAME 15
|
||||
|
||||
/* Error Codes (defined by libssh2) */
|
||||
#define LIBSSH2_ERROR_NONE 0
|
||||
#define LIBSSH2_ERROR_SOCKET_NONE -1
|
||||
#define LIBSSH2_ERROR_BANNER_NONE -2
|
||||
#define LIBSSH2_ERROR_BANNER_SEND -3
|
||||
@ -258,6 +259,7 @@ typedef struct _LIBSSH2_POLLFD {
|
||||
#define LIBSSH2_ERROR_INVAL -34
|
||||
#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35
|
||||
#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36
|
||||
#define LIBSSH2_ERROR_EAGAIN -37
|
||||
|
||||
/* Session API */
|
||||
LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), LIBSSH2_FREE_FUNC((*my_free)), LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract);
|
||||
@ -277,6 +279,7 @@ LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_
|
||||
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs);
|
||||
LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
|
||||
LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
|
||||
LIBSSH2_API int libssh2_session_last_errno(LIBSSH2_SESSION *session);
|
||||
|
||||
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
|
||||
|
||||
@ -351,50 +354,45 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const
|
||||
#define libssh2_channel_exec(channel, command) libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))
|
||||
#define libssh2_channel_subsystem(channel, subsystem) libssh2_channel_process_startup((channel), "subsystem", sizeof("subsystem") - 1, (subsystem), strlen(subsystem))
|
||||
|
||||
LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel,
|
||||
int stream_id, char *buf,
|
||||
size_t buflen);
|
||||
LIBSSH2_API int libssh2_channel_readnb_ex(LIBSSH2_CHANNEL *channel,
|
||||
int stream_id, char *buf,
|
||||
size_t buflen);
|
||||
LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel,
|
||||
int stream_id, char *buf,
|
||||
size_t buflen);
|
||||
#define libssh2_channel_read(channel, buf, buflen) \
|
||||
libssh2_channel_read_ex((channel), 0, (buf), (buflen))
|
||||
#define libssh2_channel_read_stderr(channel, buf, buflen) \
|
||||
libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
||||
|
||||
/* This is a public error code from libssh2_channel_read() that is returned
|
||||
when it would otherwise block. */
|
||||
#define LIBSSH2CHANNEL_EAGAIN -2
|
||||
|
||||
#define libssh2_channel_read(channel, buf, buflen) \
|
||||
libssh2_channel_read_ex((channel), 0, (buf), (buflen))
|
||||
#define libssh2_channel_read_stderr(channel, buf, buflen) libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
||||
#define libssh2_channel_readnb(channel, buf, buflen) \
|
||||
libssh2_channel_readnb_ex((channel), 0, (buf), (buflen))
|
||||
|
||||
LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended);
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial);
|
||||
#define libssh2_channel_window_read(channel) libssh2_channel_window_read_ex((channel), NULL, NULL)
|
||||
#define libssh2_channel_window_read(channel) \
|
||||
libssh2_channel_window_read_ex((channel), NULL, NULL)
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force);
|
||||
|
||||
LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel,
|
||||
int stream_id, const char *buf,
|
||||
size_t buflen);
|
||||
LIBSSH2_API int libssh2_channel_writenb_ex(LIBSSH2_CHANNEL *channel,
|
||||
int stream_id, const char *buf,
|
||||
size_t buflen);
|
||||
LIBSSH2_API size_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel,
|
||||
int stream_id, const char *buf,
|
||||
size_t buflen);
|
||||
|
||||
#define libssh2_channel_write(channel, buf, buflen) \
|
||||
libssh2_channel_write_ex((channel), 0, (buf), (buflen))
|
||||
#define libssh2_channel_writenb(channel, buf, buflen) \
|
||||
libssh2_channel_writenb_ex((channel), 0, (buf), (buflen))
|
||||
#define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
||||
libssh2_channel_write_ex((channel), 0, (buf), (buflen))
|
||||
#define libssh2_channel_write_stderr(channel, buf, buflen) \
|
||||
libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, unsigned long *window_size_initial);
|
||||
#define libssh2_channel_window_write(channel) libssh2_channel_window_write_ex((channel), NULL)
|
||||
|
||||
LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session, int blocking);
|
||||
LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION* session);
|
||||
|
||||
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
|
||||
LIBSSH2_API int libssh2_channel_get_blocking(LIBSSH2_CHANNEL *channel);
|
||||
|
||||
LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
|
||||
LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, int ignore_mode);
|
||||
/* libssh2_channel_ignore_extended_data() is defined below for BC with version 0.1
|
||||
* Future uses should use libssh2_channel_handle_extended_data() directly
|
||||
* if LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read (FIFO) from the standard data channel
|
||||
@ -411,6 +409,7 @@ LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel);
|
||||
|
||||
LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel);
|
||||
|
@ -166,8 +166,10 @@ struct _LIBSSH2_SFTP_ATTRIBUTES {
|
||||
#define LIBSSH2_FX_NO_MEDIA 13
|
||||
#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14
|
||||
#define LIBSSH2_FX_QUOTA_EXCEEDED 15
|
||||
#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16
|
||||
#define LIBSSH2_FX_LOCK_CONFlICT 17
|
||||
#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16 /* Initial mis-spelling */
|
||||
#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16
|
||||
#define LIBSSH2_FX_LOCK_CONFlICT 17 /* Initial mis-spelling */
|
||||
#define LIBSSH2_FX_LOCK_CONFLICT 17
|
||||
#define LIBSSH2_FX_DIR_NOT_EMPTY 18
|
||||
#define LIBSSH2_FX_NOT_A_DIRECTORY 19
|
||||
#define LIBSSH2_FX_INVALID_FILENAME 20
|
||||
@ -244,9 +246,6 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, un
|
||||
#define libssh2_sftp_readlink(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_READLINK)
|
||||
#define libssh2_sftp_realpath(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_REALPATH)
|
||||
|
||||
LIBSSH2_API void libssh2_sftp_set_blocking(LIBSSH2_SFTP *session, int blocking);
|
||||
LIBSSH2_API int libssh2_sftp_get_blocking(LIBSSH2_SFTP *session);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
1878
src/channel.c
1878
src/channel.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
1409
src/kex.c
1409
src/kex.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@ -65,6 +65,8 @@
|
||||
#endif
|
||||
|
||||
#include "libssh2.h"
|
||||
#include "libssh2_publickey.h"
|
||||
#include "libssh2_sftp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@ -115,6 +117,112 @@ typedef struct _LIBSSH2_PACKET LIBSSH2_PACKET;
|
||||
typedef struct _LIBSSH2_PACKET_BRIGADE LIBSSH2_PACKET_BRIGADE;
|
||||
typedef struct _LIBSSH2_CHANNEL_BRIGADE LIBSSH2_CHANNEL_BRIGADE;
|
||||
|
||||
typedef int libssh2pack_t;
|
||||
|
||||
typedef enum {
|
||||
libssh2_NB_state_idle = 0,
|
||||
libssh2_NB_state_allocated,
|
||||
libssh2_NB_state_created,
|
||||
libssh2_NB_state_sent,
|
||||
libssh2_NB_state_sent1,
|
||||
libssh2_NB_state_sent2,
|
||||
libssh2_NB_state_sent3,
|
||||
libssh2_NB_state_sent4,
|
||||
libssh2_NB_state_sent5,
|
||||
libssh2_NB_state_sent6,
|
||||
libssh2_NB_state_sent7,
|
||||
libssh2_NB_state_jump1,
|
||||
libssh2_NB_state_jump2,
|
||||
libssh2_NB_state_jump3
|
||||
} libssh2_nonblocking_states;
|
||||
|
||||
typedef struct packet_require_state_t {
|
||||
libssh2_nonblocking_states state;
|
||||
time_t start;
|
||||
} packet_require_state_t;
|
||||
|
||||
typedef struct packet_requirev_state_t {
|
||||
time_t start;
|
||||
} packet_requirev_state_t;
|
||||
|
||||
typedef struct kmdhgGPsha1kex_state_t {
|
||||
libssh2_nonblocking_states state;
|
||||
unsigned char *e_packet;
|
||||
unsigned char *s_packet;
|
||||
unsigned char *tmp;
|
||||
unsigned char h_sig_comp[SHA_DIGEST_LENGTH];
|
||||
unsigned char c;
|
||||
unsigned long e_packet_len;
|
||||
unsigned long s_packet_len;
|
||||
unsigned long tmp_len;
|
||||
_libssh2_bn_ctx *ctx;
|
||||
_libssh2_bn *x;
|
||||
_libssh2_bn *e;
|
||||
_libssh2_bn *f;
|
||||
_libssh2_bn *k;
|
||||
unsigned char *s;
|
||||
unsigned char *f_value;
|
||||
unsigned char *k_value;
|
||||
unsigned char *h_sig;
|
||||
unsigned long f_value_len;
|
||||
unsigned long k_value_len;
|
||||
unsigned long h_sig_len;
|
||||
libssh2_sha1_ctx exchange_hash;
|
||||
packet_require_state_t req_state;
|
||||
libssh2_nonblocking_states burn_state;
|
||||
} kmdhgGPsha1kex_state_t;
|
||||
|
||||
typedef struct key_exchange_state_low_t {
|
||||
libssh2_nonblocking_states state;
|
||||
packet_require_state_t req_state;
|
||||
kmdhgGPsha1kex_state_t exchange_state;
|
||||
_libssh2_bn *p; /* SSH2 defined value (p_value) */
|
||||
_libssh2_bn *g; /* SSH2 defined value (2) */
|
||||
unsigned char request[13];
|
||||
unsigned char *data;
|
||||
unsigned long request_len;
|
||||
unsigned long data_len;
|
||||
} key_exchange_state_low_t;
|
||||
|
||||
typedef struct key_exchange_state_t {
|
||||
libssh2_nonblocking_states state;
|
||||
packet_require_state_t req_state;
|
||||
key_exchange_state_low_t key_state_low;
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
unsigned char *oldlocal;
|
||||
unsigned long oldlocal_len;
|
||||
} key_exchange_state_t;
|
||||
|
||||
#define FwdNotReq "Forward not requested"
|
||||
|
||||
typedef struct packet_queue_listener_state_t {
|
||||
libssh2_nonblocking_states state;
|
||||
unsigned char packet[17 + (sizeof(FwdNotReq) - 1)];
|
||||
unsigned char *host;
|
||||
unsigned char *shost;
|
||||
uint32_t sender_channel;
|
||||
uint32_t initial_window_size;
|
||||
uint32_t packet_size;
|
||||
uint32_t port;
|
||||
uint32_t sport;
|
||||
uint32_t host_len;
|
||||
uint32_t shost_len;
|
||||
} packet_queue_listener_state_t;
|
||||
|
||||
#define X11FwdUnAvil "X11 Forward Unavailable"
|
||||
|
||||
typedef struct packet_x11_open_state_t {
|
||||
libssh2_nonblocking_states state;
|
||||
unsigned char packet[17 + (sizeof(X11FwdUnAvil) - 1)];
|
||||
unsigned char *shost;
|
||||
uint32_t sender_channel;
|
||||
uint32_t initial_window_size;
|
||||
uint32_t packet_size;
|
||||
uint32_t sport;
|
||||
uint32_t shost_len;
|
||||
} packet_x11_open_state_t;
|
||||
|
||||
struct _LIBSSH2_PACKET {
|
||||
unsigned char type;
|
||||
|
||||
@ -153,13 +261,12 @@ struct _LIBSSH2_CHANNEL {
|
||||
unsigned char *channel_type;
|
||||
unsigned channel_type_len;
|
||||
|
||||
int blocking;
|
||||
|
||||
/* channel's program exit status */
|
||||
int exit_status;
|
||||
|
||||
libssh2_channel_data local, remote;
|
||||
unsigned long adjust_queue; /* Amount of bytes to be refunded to receive window (but not yet sent) */
|
||||
/* Amount of bytes to be refunded to receive window (but not yet sent) */
|
||||
unsigned long adjust_queue;
|
||||
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
@ -167,6 +274,68 @@ struct _LIBSSH2_CHANNEL {
|
||||
|
||||
void *abstract;
|
||||
LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
|
||||
|
||||
/* State variables used in libssh2_channel_setenv_ex() */
|
||||
libssh2_nonblocking_states setenv_state;
|
||||
unsigned char *setenv_packet;
|
||||
unsigned long setenv_packet_len;
|
||||
unsigned char setenv_local_channel[4];
|
||||
packet_requirev_state_t setenv_packet_requirev_state;
|
||||
|
||||
/* State variables used in libssh2_channel_request_pty_ex() */
|
||||
libssh2_nonblocking_states reqPTY_state;
|
||||
unsigned char *reqPTY_packet;
|
||||
unsigned long reqPTY_packet_len;
|
||||
unsigned char reqPTY_local_channel[4];
|
||||
packet_requirev_state_t reqPTY_packet_requirev_state;
|
||||
|
||||
/* State variables used in libssh2_channel_x11_req_ex() */
|
||||
libssh2_nonblocking_states reqX11_state;
|
||||
unsigned char *reqX11_packet;
|
||||
unsigned long reqX11_packet_len;
|
||||
unsigned char reqX11_local_channel[4];
|
||||
packet_requirev_state_t reqX11_packet_requirev_state;
|
||||
|
||||
/* State variables used in libssh2_channel_process_startup() */
|
||||
libssh2_nonblocking_states process_state;
|
||||
unsigned char *process_packet;
|
||||
unsigned long process_packet_len;
|
||||
unsigned char process_local_channel[4];
|
||||
packet_requirev_state_t process_packet_requirev_state;
|
||||
|
||||
/* State variables used in libssh2_channel_flush_ex() */
|
||||
libssh2_nonblocking_states flush_state;
|
||||
unsigned long flush_refund_bytes;
|
||||
unsigned long flush_flush_bytes;
|
||||
|
||||
/* State variables used in libssh2_channel_read_ex() */
|
||||
libssh2_nonblocking_states read_state;
|
||||
LIBSSH2_PACKET *read_packet;
|
||||
LIBSSH2_PACKET *read_next;
|
||||
int read_block;
|
||||
int read_bytes_read;
|
||||
uint32_t read_local_id;
|
||||
|
||||
/* State variables used in libssh2_channel_write_ex() */
|
||||
libssh2_nonblocking_states write_state;
|
||||
unsigned char *write_packet;
|
||||
unsigned char *write_s;
|
||||
unsigned long write_packet_len;
|
||||
unsigned long write_bufwrote;
|
||||
size_t write_bufwrite;
|
||||
|
||||
/* State variables used in libssh2_channel_close() */
|
||||
libssh2_nonblocking_states close_state;
|
||||
unsigned char close_packet[5];
|
||||
|
||||
/* State variables used in libssh2_channel_wait_closedeof() */
|
||||
libssh2_nonblocking_states wait_eof_state;
|
||||
|
||||
/* State variables used in libssh2_channel_wait_closed() */
|
||||
libssh2_nonblocking_states wait_closed_state;
|
||||
|
||||
/* State variables used in libssh2_channel_handle_extended_data2() */
|
||||
libssh2_nonblocking_states extData2_state;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_CHANNEL_BRIGADE {
|
||||
@ -184,6 +353,11 @@ struct _LIBSSH2_LISTENER {
|
||||
int queue_maxsize;
|
||||
|
||||
LIBSSH2_LISTENER *prev, *next;
|
||||
|
||||
/* State variables used in libssh2_channel_forward_cancel() */
|
||||
libssh2_nonblocking_states chanFwdCncl_state;
|
||||
unsigned char *chanFwdCncl_data;
|
||||
size_t chanFwdCncl_data_len;
|
||||
};
|
||||
|
||||
typedef struct _libssh2_endpoint_data {
|
||||
@ -246,6 +420,123 @@ struct transportpacket {
|
||||
unsigned long osent; /* number of bytes already sent */
|
||||
};
|
||||
|
||||
struct _LIBSSH2_PUBLICKEY {
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
unsigned long version;
|
||||
|
||||
/* State variables used in libssh2_publickey_packet_receive() */
|
||||
libssh2_nonblocking_states receive_state;
|
||||
unsigned char *receive_packet;
|
||||
unsigned long receive_packet_len;
|
||||
|
||||
/* State variables used in libssh2_publickey_add_ex() */
|
||||
libssh2_nonblocking_states add_state;
|
||||
unsigned char *add_packet;
|
||||
unsigned char *add_s;
|
||||
|
||||
/* State variables used in libssh2_publickey_remove_ex() */
|
||||
libssh2_nonblocking_states remove_state;
|
||||
unsigned char *remove_packet;
|
||||
unsigned char *remove_s;
|
||||
|
||||
/* State variables used in libssh2_publickey_list_fetch() */
|
||||
libssh2_nonblocking_states listFetch_state;
|
||||
unsigned char *listFetch_s;
|
||||
unsigned char listFetch_buffer[12];
|
||||
unsigned char *listFetch_data;
|
||||
unsigned long listFetch_data_len;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
sftp_read_idle = 0,
|
||||
sftp_read_packet_allocated,
|
||||
sftp_read_packet_created,
|
||||
sftp_read_packet_sent
|
||||
} libssh2_sftp_read_state;
|
||||
|
||||
typedef enum {
|
||||
sftp_readdir_idle = 0,
|
||||
sftp_readdir_packet_created,
|
||||
sftp_readdir_packet_sent
|
||||
} libssh2_sftp_readdir_state;
|
||||
|
||||
typedef enum {
|
||||
sftp_write_idle = 0,
|
||||
sftp_write_packet_created,
|
||||
sftp_write_packet_sent
|
||||
} libssh2_sftp_write_state;
|
||||
|
||||
typedef enum {
|
||||
sftp_mkdir_idle = 0,
|
||||
sftp_mkdir_packet_created,
|
||||
sftp_mkdir_packet_sent
|
||||
} libssh2_sftp_mkdir_state;
|
||||
|
||||
struct _LIBSSH2_SFTP_HANDLE {
|
||||
LIBSSH2_SFTP *sftp;
|
||||
LIBSSH2_SFTP_HANDLE *prev, *next;
|
||||
|
||||
char *handle;
|
||||
int handle_len;
|
||||
|
||||
char handle_type;
|
||||
|
||||
union _libssh2_sftp_handle_data {
|
||||
struct _libssh2_sftp_handle_file_data {
|
||||
libssh2_uint64_t offset;
|
||||
} file;
|
||||
struct _libssh2_sftp_handle_dir_data {
|
||||
unsigned long names_left;
|
||||
void *names_packet;
|
||||
char *next_name;
|
||||
} dir;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_SFTP {
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
|
||||
unsigned long request_id, version;
|
||||
|
||||
LIBSSH2_PACKET_BRIGADE packets;
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *handles;
|
||||
|
||||
unsigned long last_errno;
|
||||
|
||||
/* Holder for partial packet, use in libssh2_sftp_packet_read() */
|
||||
unsigned char *partial_packet; /* The data */
|
||||
unsigned long partial_len; /* Desired number of bytes */
|
||||
unsigned long partial_received; /* Bytes received so far */
|
||||
|
||||
/* Time that libssh2_sftp_packet_requirev() started reading */
|
||||
time_t requirev_start;
|
||||
|
||||
/* State variables used in _libssh2_sftp_read() */
|
||||
libssh2_sftp_read_state read_state;
|
||||
unsigned char *read_packet;
|
||||
unsigned long read_request_id;
|
||||
size_t read_total_read;
|
||||
|
||||
/* State variables used in _libssh2_sftp_readdir() */
|
||||
libssh2_sftp_readdir_state readdir_state;
|
||||
unsigned char *readdir_packet;
|
||||
unsigned long readdir_request_id;
|
||||
|
||||
/* State variables used in _libssh2_sftp_write() */
|
||||
libssh2_sftp_write_state write_state;
|
||||
unsigned char *write_packet;
|
||||
unsigned long write_request_id;
|
||||
|
||||
/* State variables used in _libssh2_sftp_mkdir() */
|
||||
libssh2_sftp_mkdir_state mkdir_state;
|
||||
unsigned char *mkdir_packet;
|
||||
unsigned long mkdir_request_id;
|
||||
|
||||
};
|
||||
|
||||
#define LIBSSH2_SCP_RESPONSE_BUFLEN 256
|
||||
|
||||
struct _LIBSSH2_SESSION {
|
||||
/* Memory management callbacks */
|
||||
void *abstract;
|
||||
@ -319,6 +610,134 @@ struct _LIBSSH2_SESSION {
|
||||
#ifdef LIBSSH2DEBUG
|
||||
int showmask; /* what debug/trace messages to display */
|
||||
#endif
|
||||
|
||||
/* State variables used in libssh2_banner_send() */
|
||||
libssh2_nonblocking_states banner_TxRx_state;
|
||||
char banner_TxRx_banner[256];
|
||||
ssize_t banner_TxRx_total_send;
|
||||
|
||||
/* State variables used in libssh2_kexinit() */
|
||||
libssh2_nonblocking_states kexinit_state;
|
||||
unsigned char *kexinit_data;
|
||||
size_t kexinit_data_len;
|
||||
|
||||
/* State variables used in libssh2_session_startup() */
|
||||
libssh2_nonblocking_states startup_state;
|
||||
unsigned char *startup_data;
|
||||
unsigned long startup_data_len;
|
||||
unsigned char startup_service[sizeof("ssh-userauth") + 5 - 1];
|
||||
unsigned long startup_service_length;
|
||||
packet_require_state_t startup_req_state;
|
||||
key_exchange_state_t startup_key_state;
|
||||
|
||||
/* State variables used in libssh2_session_disconnect_ex() */
|
||||
libssh2_nonblocking_states disconnect_state;
|
||||
unsigned char *disconnect_data;
|
||||
unsigned long disconnect_data_len;
|
||||
|
||||
/* State variables used in libssh2_packet_read() */
|
||||
libssh2_nonblocking_states readPack_state;
|
||||
int readPack_encrypted;
|
||||
|
||||
/*
|
||||
* State variables used in libssh2_userauth_list(),
|
||||
* libssh2_userauth_password_ex(), libssh2_userauth_hostbased_fromfile_ex(),
|
||||
* libssh2_userauth_publickey_fromfile_ex(),
|
||||
* libssh2_userauth_keyboard_interactive_ex
|
||||
*/
|
||||
libssh2_nonblocking_states userauth_state;
|
||||
unsigned char *userauth_data;
|
||||
unsigned char userauth_data0;
|
||||
unsigned long userauth_data_len;
|
||||
char *userauth_newpw;
|
||||
int userauth_newpw_len;
|
||||
unsigned char *userauth_packet;
|
||||
unsigned long userauth_packet_len;
|
||||
unsigned char *userauth_method;
|
||||
unsigned long userauth_method_len;
|
||||
unsigned char *userauth_s;
|
||||
unsigned char *userauth_b;
|
||||
unsigned int userauth_auth_name_len;
|
||||
char *userauth_auth_name;
|
||||
unsigned userauth_auth_instruction_len;
|
||||
char *userauth_auth_instruction;
|
||||
unsigned int userauth_num_prompts;
|
||||
int userauth_auth_failure;
|
||||
LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_prompts;
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE *userauth_responses;
|
||||
packet_requirev_state_t userauth_packet_requirev_state;
|
||||
|
||||
/* State variables used in libssh2_channel_open_ex() */
|
||||
libssh2_nonblocking_states open_state;
|
||||
packet_requirev_state_t open_packet_requirev_state;
|
||||
LIBSSH2_CHANNEL *open_channel;
|
||||
unsigned char *open_packet;
|
||||
unsigned long open_packet_len;
|
||||
unsigned char *open_data;
|
||||
unsigned long open_data_len;
|
||||
unsigned long open_local_channel;
|
||||
|
||||
/* State variables used in libssh2_channel_direct_tcpip_ex() */
|
||||
libssh2_nonblocking_states direct_state;
|
||||
unsigned char *direct_message;
|
||||
unsigned long direct_host_len;
|
||||
unsigned long direct_shost_len;
|
||||
unsigned long direct_message_len;
|
||||
|
||||
/* State variables used in libssh2_channel_forward_listen_ex() */
|
||||
libssh2_nonblocking_states fwdLstn_state;
|
||||
unsigned char *fwdLstn_packet;
|
||||
unsigned long fwdLstn_host_len;
|
||||
unsigned long fwdLstn_packet_len;
|
||||
packet_requirev_state_t fwdLstn_packet_requirev_state;
|
||||
|
||||
/* State variables used in libssh2_publickey_init() */
|
||||
libssh2_nonblocking_states pkeyInit_state;
|
||||
LIBSSH2_PUBLICKEY *pkeyInit_pkey;
|
||||
LIBSSH2_CHANNEL *pkeyInit_channel;
|
||||
unsigned char *pkeyInit_data;
|
||||
unsigned long pkeyInit_data_len;
|
||||
|
||||
/* State variables used in libssh2_packet_add() */
|
||||
libssh2_nonblocking_states packAdd_state;
|
||||
LIBSSH2_PACKET *packAdd_packet;
|
||||
LIBSSH2_CHANNEL *packAdd_channel;
|
||||
unsigned long packAdd_data_head;
|
||||
key_exchange_state_t packAdd_key_state;
|
||||
packet_queue_listener_state_t packAdd_Qlstn_state;
|
||||
packet_x11_open_state_t packAdd_x11open_state;
|
||||
|
||||
/* State variables used in fullpacket() */
|
||||
libssh2_nonblocking_states fullpacket_state;
|
||||
int fullpacket_macstate;
|
||||
int fullpacket_payload_len;
|
||||
libssh2pack_t fullpacket_packet_type;
|
||||
|
||||
/* State variables used in libssh2_sftp_init() */
|
||||
libssh2_nonblocking_states sftpInit_state;
|
||||
LIBSSH2_SFTP *sftpInit_sftp;
|
||||
LIBSSH2_CHANNEL *sftpInit_channel;
|
||||
unsigned char sftpInit_buffer[9]; /* sftp_header(5){excludes request_id} + version_id(4) */
|
||||
|
||||
/* State variables used in libssh2_scp_recv() */
|
||||
libssh2_nonblocking_states scpRecv_state;
|
||||
unsigned char *scpRecv_command;
|
||||
unsigned long scpRecv_command_len;
|
||||
unsigned char scpRecv_response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned long scpRecv_response_len;
|
||||
long scpRecv_mode;
|
||||
long scpRecv_size;
|
||||
long scpRecv_mtime;
|
||||
long scpRecv_atime;
|
||||
LIBSSH2_CHANNEL *scpRecv_channel;
|
||||
|
||||
/* State variables used in libssh2_scp_send_ex() */
|
||||
libssh2_nonblocking_states scpSend_state;
|
||||
unsigned char *scpSend_command;
|
||||
unsigned long scpSend_command_len;
|
||||
unsigned char scpSend_response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned long scpSend_response_len;
|
||||
LIBSSH2_CHANNEL *scpSend_channel;
|
||||
};
|
||||
|
||||
/* session.state bits */
|
||||
@ -342,7 +761,7 @@ struct _LIBSSH2_KEX_METHOD {
|
||||
const char *name;
|
||||
|
||||
/* Key exchange, populates session->* and returns 0 on success, non-0 on error */
|
||||
int (*exchange_keys)(LIBSSH2_SESSION *session);
|
||||
int (*exchange_keys)(LIBSSH2_SESSION *session, key_exchange_state_low_t *key_state);
|
||||
|
||||
long flags;
|
||||
};
|
||||
@ -451,7 +870,7 @@ static inline void _libssh2_debug(LIBSSH2_SESSION *session, int context,
|
||||
session->err_code = errcode; \
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_DEBUG_ENABLED */
|
||||
#endif /* ! LIBSSH2DEBUG */
|
||||
|
||||
|
||||
#define LIBSSH2_SOCKET_UNKNOWN 1
|
||||
@ -527,59 +946,43 @@ void libssh2_htonu32(unsigned char *buf, unsigned long val);
|
||||
void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t val);
|
||||
|
||||
#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when
|
||||
waiting for more data to arrive */
|
||||
waiting for more data to arrive */
|
||||
int libssh2_waitsocket(LIBSSH2_SESSION *session, long seconds);
|
||||
|
||||
|
||||
/* CAUTION: some of these error codes are returned in the public API and is
|
||||
there known with other #defined names from the public header file. They
|
||||
should not be changed. */
|
||||
typedef int libssh2pack_t;
|
||||
|
||||
#define PACKET_TIMEOUT -7
|
||||
#define PACKET_BADUSE -6
|
||||
#define PACKET_TIMEOUT -7
|
||||
#define PACKET_BADUSE -6
|
||||
#define PACKET_COMPRESS -5
|
||||
#define PACKET_TOOBIG -4
|
||||
#define PACKET_ENOMEM -3
|
||||
#define PACKET_EAGAIN -2
|
||||
#define PACKET_FAIL -1
|
||||
#define PACKET_NONE 0
|
||||
#define PACKET_TOOBIG -4
|
||||
#define PACKET_ENOMEM -3
|
||||
#define PACKET_EAGAIN -2
|
||||
#define PACKET_FAIL -1
|
||||
#define PACKET_NONE 0
|
||||
|
||||
libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session);
|
||||
|
||||
int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket);
|
||||
#define libssh2_packet_ask(session, packet_type, data, data_len, poll_socket) \
|
||||
libssh2_packet_ask_ex((session), (packet_type), (data), (data_len), 0, NULL, 0, (poll_socket))
|
||||
int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type,
|
||||
unsigned char **data, unsigned long *data_len,
|
||||
unsigned long match_ofs,
|
||||
const unsigned char *match_buf,
|
||||
unsigned long match_len, int poll_socket);
|
||||
|
||||
int libssh2_packet_askv_ex(LIBSSH2_SESSION *session, const unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket);
|
||||
#define libssh2_packet_askv(session, packet_types, data, data_len, poll_socket) \
|
||||
libssh2_packet_askv_ex((session), (packet_types), (data), (data_len), 0, NULL, 0, (poll_socket))
|
||||
int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
|
||||
#define libssh2_packet_require(session, packet_type, data, data_len) \
|
||||
libssh2_packet_require_ex((session), (packet_type), (data), (data_len), 0, NULL, 0)
|
||||
int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, const unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
|
||||
#define libssh2_packet_requirev(session, packet_types, data, data_len) \
|
||||
libssh2_packet_requirev_ex((session), (packet_types), (data), (data_len), 0, NULL, 0)
|
||||
int libssh2_packet_burn(LIBSSH2_SESSION *session);
|
||||
int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, packet_require_state_t *state);
|
||||
int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, const unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, packet_requirev_state_t *state);
|
||||
int libssh2_packet_burn(LIBSSH2_SESSION *session, libssh2_nonblocking_states *state);
|
||||
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len);
|
||||
int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, size_t datalen, int macstate);
|
||||
int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange);
|
||||
int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange, key_exchange_state_t *state);
|
||||
unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session);
|
||||
LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id);
|
||||
ssize_t _libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel,
|
||||
int stream_id, char *buf, size_t buflen);
|
||||
#define _libssh2_channel_read(channel, buf, buflen) \
|
||||
_libssh2_channel_read_ex((channel), 0, (buf), (buflen))
|
||||
#undef libssh2_channel_read /* never use this internally */
|
||||
#define libssh2_channel_read fix this code
|
||||
|
||||
int _libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel,
|
||||
int stream_id,
|
||||
const char *buf, size_t buflen);
|
||||
#define _libssh2_channel_write(channel, buf, buflen) \
|
||||
_libssh2_channel_write_ex((channel), 0, (buf), (buflen))
|
||||
|
||||
/* this is the lib-internal set blocking function */
|
||||
int _libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
|
||||
int _libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking);
|
||||
|
||||
/* Let crypt.c/hostkey.c/comp.c/mac.c expose their method structs */
|
||||
const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void);
|
||||
|
@ -201,7 +201,7 @@ void _libssh2_debug(LIBSSH2_SESSION *session, int context,
|
||||
if (context < 1 || context > 8) {
|
||||
context = 0;
|
||||
}
|
||||
if(!(session->showmask & (1<<context))) {
|
||||
if (!(session->showmask & (1<<context))) {
|
||||
/* no such output asked for */
|
||||
return;
|
||||
}
|
||||
|
1391
src/packet.c
1391
src/packet.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
686
src/publickey.c
686
src/publickey.c
@ -38,11 +38,6 @@
|
||||
#include "libssh2_priv.h"
|
||||
#include "libssh2_publickey.h"
|
||||
|
||||
struct _LIBSSH2_PUBLICKEY {
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
unsigned long version;
|
||||
};
|
||||
|
||||
#define LIBSSH2_PUBLICKEY_VERSION 2
|
||||
|
||||
/* Numericised response codes -- Not IETF standard, just a local representation */
|
||||
@ -95,7 +90,9 @@ static const LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_status_codes[] = {
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_START "Publickey Subsystem Error: \""
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_MID "\" Server Resports: \""
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_END "\""
|
||||
static void libssh2_publickey_status_error(const LIBSSH2_PUBLICKEY *pkey, LIBSSH2_SESSION *session, int status, const unsigned char *message, int message_len)
|
||||
static void
|
||||
libssh2_publickey_status_error(const LIBSSH2_PUBLICKEY *pkey, LIBSSH2_SESSION *session, int status,
|
||||
const unsigned char *message, int message_len)
|
||||
{
|
||||
const char *status_text;
|
||||
int status_text_len;
|
||||
@ -139,34 +136,52 @@ static void libssh2_publickey_status_error(const LIBSSH2_PUBLICKEY *pkey, LIBSSH
|
||||
/* {{{ libssh2_publickey_packet_receive
|
||||
* Read a packet from the subsystem
|
||||
*/
|
||||
static int libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY *pkey, unsigned char **data, unsigned long *data_len)
|
||||
static int
|
||||
libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY *pkey, unsigned char **data, unsigned long *data_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char buffer[4];
|
||||
unsigned long packet_len;
|
||||
unsigned char *packet;
|
||||
int rc;
|
||||
|
||||
if (_libssh2_channel_read(channel, (char *)buffer, 4) != 4) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid response from publickey subsystem", 0);
|
||||
return -1;
|
||||
if (pkey->receive_state == libssh2_NB_state_idle) {
|
||||
rc = libssh2_channel_read_ex(channel, 0, (char *)buffer, 4);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
else if (rc != 4) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid response from publickey subsystem", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pkey->receive_packet_len = libssh2_ntohu32(buffer);
|
||||
pkey->receive_packet = LIBSSH2_ALLOC(session, pkey->receive_packet_len);
|
||||
if (!pkey->receive_packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate publickey response buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pkey->receive_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
packet_len = libssh2_ntohu32(buffer);
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate publickey response buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
if (pkey->receive_state == libssh2_NB_state_sent) {
|
||||
rc = libssh2_channel_read_ex(channel, 0, (char *)pkey->receive_packet, pkey->receive_packet_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
else if (rc != pkey->receive_packet_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for publickey subsystem response packet", 0);
|
||||
LIBSSH2_FREE(session, pkey->receive_packet);
|
||||
pkey->receive_packet = NULL;
|
||||
pkey->receive_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_libssh2_channel_read(channel, (char *)packet, packet_len) != packet_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for publickey subsystem response packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
*data = pkey->receive_packet;
|
||||
*data_len = pkey->receive_packet_len;
|
||||
}
|
||||
|
||||
*data = packet;
|
||||
*data_len = packet_len;
|
||||
|
||||
pkey->receive_state = libssh2_NB_state_idle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -214,9 +229,14 @@ static int libssh2_publickey_response_success(LIBSSH2_PUBLICKEY *pkey)
|
||||
unsigned char *data, *s;
|
||||
unsigned long data_len;
|
||||
int response;
|
||||
int rc;
|
||||
|
||||
while (1) {
|
||||
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
|
||||
rc = libssh2_publickey_packet_receive(pkey, &data, &data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
|
||||
return -1;
|
||||
}
|
||||
@ -278,114 +298,182 @@ static int libssh2_publickey_response_success(LIBSSH2_PUBLICKEY *pkey)
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session)
|
||||
{
|
||||
LIBSSH2_PUBLICKEY *pkey = NULL;
|
||||
LIBSSH2_CHANNEL *channel = NULL;
|
||||
/* 19 = packet_len(4) + version_len(4) + "version"(7) + version_num(4) */
|
||||
unsigned char buffer[19];
|
||||
/* packet_len(4) +
|
||||
version_len(4) +
|
||||
"version"(7) +
|
||||
version_num(4) */
|
||||
unsigned char *s, *data = NULL;
|
||||
unsigned long data_len;
|
||||
unsigned char *s;
|
||||
int response;
|
||||
int rc;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Initializing publickey subsystem");
|
||||
|
||||
channel = libssh2_channel_open_session(session);
|
||||
if (!channel) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
if (libssh2_channel_subsystem(channel, "publickey")) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
if (session->pkeyInit_state == libssh2_NB_state_idle) {
|
||||
session->pkeyInit_data = NULL;
|
||||
session->pkeyInit_pkey = NULL;
|
||||
session->pkeyInit_channel = NULL;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Initializing publickey subsystem");
|
||||
|
||||
session->pkeyInit_state = libssh2_NB_state_allocated;
|
||||
}
|
||||
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
|
||||
|
||||
pkey = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
|
||||
if (!pkey) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new publickey structure", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
pkey->channel = channel;
|
||||
pkey->version = 0;
|
||||
|
||||
s = buffer;
|
||||
libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("version") - 1); s += 4;
|
||||
memcpy(s, "version", sizeof("version") - 1); s += sizeof("version") - 1;
|
||||
libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION); s += 4;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey version packet advertising version %d support", (int)LIBSSH2_PUBLICKEY_VERSION);
|
||||
if ((s - buffer) != libssh2_channel_write(channel, (char*)buffer, (s - buffer))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey version packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
s = data;
|
||||
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
switch (response) {
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
|
||||
/* Error */
|
||||
{
|
||||
unsigned long status, descr_len, lang_len;
|
||||
unsigned char *descr, *lang;
|
||||
|
||||
status = libssh2_ntohu32(s); s += 4;
|
||||
descr_len = libssh2_ntohu32(s); s += 4;
|
||||
descr = s; s += descr_len;
|
||||
lang_len = libssh2_ntohu32(s); s += 4;
|
||||
lang = s; s += lang_len;
|
||||
|
||||
if (s > data + data_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
libssh2_publickey_status_error(NULL, session, status, descr, descr_len);
|
||||
if (session->pkeyInit_state == libssh2_NB_state_allocated) {
|
||||
do {
|
||||
session->pkeyInit_channel = libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
|
||||
LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT,
|
||||
NULL, 0);
|
||||
if (!session->pkeyInit_channel && (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN)) {
|
||||
/* The error state is already set, so leave it */
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block to startup channel", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (!session->pkeyInit_channel && (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
|
||||
/* What we want */
|
||||
pkey->version = libssh2_ntohu32(s);
|
||||
if (pkey->version > LIBSSH2_PUBLICKEY_VERSION) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Truncating remote publickey version from %lu", pkey->version);
|
||||
pkey->version = LIBSSH2_PUBLICKEY_VERSION;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Enabling publickey subsystem version %lu", pkey->version);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return pkey;
|
||||
default:
|
||||
/* Unknown/Unexpected */
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
data = NULL;
|
||||
} while (!session->pkeyInit_channel);
|
||||
|
||||
session->pkeyInit_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
if (session->pkeyInit_state == libssh2_NB_state_sent) {
|
||||
rc = libssh2_channel_process_startup(session->pkeyInit_channel, "subsystem", sizeof("subsystem") - 1,
|
||||
"publickey", strlen("publickey"));
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block starting publickkey subsystem", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
session->pkeyInit_state = libssh2_NB_state_sent1;
|
||||
}
|
||||
|
||||
if (session->pkeyInit_state == libssh2_NB_state_sent1) {
|
||||
rc = libssh2_channel_handle_extended_data2(session->pkeyInit_channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block starting publickkey subsystem", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session->pkeyInit_pkey = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
|
||||
if (!session->pkeyInit_pkey) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new publickey structure", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
memset(session->pkeyInit_pkey, 0, sizeof(LIBSSH2_PUBLICKEY));
|
||||
session->pkeyInit_pkey->channel = session->pkeyInit_channel;
|
||||
session->pkeyInit_pkey->version = 0;
|
||||
|
||||
s = buffer;
|
||||
libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("version") - 1); s += 4;
|
||||
memcpy(s, "version", sizeof("version") - 1); s += sizeof("version") - 1;
|
||||
libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION); s += 4;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey version packet advertising version %d support",
|
||||
(int)LIBSSH2_PUBLICKEY_VERSION);
|
||||
|
||||
session->pkeyInit_state = libssh2_NB_state_sent2;
|
||||
}
|
||||
|
||||
if (session->pkeyInit_state == libssh2_NB_state_sent2) {
|
||||
rc = libssh2_channel_write_ex(session->pkeyInit_channel, 0, (char*)buffer, (s - buffer));
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending publickkey version packet", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if ((s - buffer) != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey version packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
session->pkeyInit_state = libssh2_NB_state_sent3;
|
||||
}
|
||||
|
||||
if (session->pkeyInit_state == libssh2_NB_state_sent3) {
|
||||
while (1) {
|
||||
rc = libssh2_publickey_packet_receive(session->pkeyInit_pkey, &session->pkeyInit_data, &session->pkeyInit_data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response from publickey subsystem", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
s = session->pkeyInit_data;
|
||||
if ((response = libssh2_publickey_response_id(&s, session->pkeyInit_data_len)) < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
switch (response) {
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
|
||||
/* Error */
|
||||
{
|
||||
unsigned long status, descr_len, lang_len;
|
||||
unsigned char *descr, *lang;
|
||||
|
||||
status = libssh2_ntohu32(s); s += 4;
|
||||
descr_len = libssh2_ntohu32(s); s += 4;
|
||||
descr = s; s += descr_len;
|
||||
lang_len = libssh2_ntohu32(s); s += 4;
|
||||
lang = s; s += lang_len;
|
||||
|
||||
if (s > session->pkeyInit_data + session->pkeyInit_data_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
libssh2_publickey_status_error(NULL, session, status, descr, descr_len);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
|
||||
/* What we want */
|
||||
session->pkeyInit_pkey->version = libssh2_ntohu32(s);
|
||||
if (session->pkeyInit_pkey->version > LIBSSH2_PUBLICKEY_VERSION) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Truncating remote publickey version from %lu",
|
||||
session->pkeyInit_pkey->version);
|
||||
session->pkeyInit_pkey->version = LIBSSH2_PUBLICKEY_VERSION;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Enabling publickey subsystem version %lu",
|
||||
session->pkeyInit_pkey->version);
|
||||
LIBSSH2_FREE(session, session->pkeyInit_data);
|
||||
session->pkeyInit_data = NULL;
|
||||
session->pkeyInit_state = libssh2_NB_state_idle;
|
||||
return session->pkeyInit_pkey;
|
||||
|
||||
default:
|
||||
/* Unknown/Unexpected */
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
|
||||
"Unexpected publickey subsystem response, ignoring", 0);
|
||||
LIBSSH2_FREE(session, session->pkeyInit_data);
|
||||
session->pkeyInit_data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached except by direct goto */
|
||||
err_exit:
|
||||
if (channel) {
|
||||
libssh2_channel_close(channel);
|
||||
session->pkeyInit_state = libssh2_NB_state_sent4;
|
||||
if (session->pkeyInit_channel) {
|
||||
rc = libssh2_channel_close(session->pkeyInit_channel);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block closing channel", 0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (pkey) {
|
||||
LIBSSH2_FREE(session, pkey);
|
||||
if (session->pkeyInit_pkey) {
|
||||
LIBSSH2_FREE(session, session->pkeyInit_pkey);
|
||||
session->pkeyInit_pkey = NULL;
|
||||
}
|
||||
if (data) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
if (session->pkeyInit_data) {
|
||||
LIBSSH2_FREE(session, session->pkeyInit_data);
|
||||
session->pkeyInit_data = NULL;
|
||||
}
|
||||
session->pkeyInit_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
/* }}} */
|
||||
@ -393,178 +481,233 @@ LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session)
|
||||
/* {{{ libssh2_publickey_add_ex
|
||||
* Add a new public key entry
|
||||
*/
|
||||
LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len, char overwrite,
|
||||
unsigned long num_attrs, const libssh2_publickey_attribute attrs[])
|
||||
LIBSSH2_API int
|
||||
libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len, char overwrite, unsigned long num_attrs,
|
||||
const libssh2_publickey_attribute attrs[])
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *packet = NULL, *s;
|
||||
/* 19 = packet_len(4) + add_len(4) + "add"(3) + name_len(4) + {name} blob_len(4) + {blob} */
|
||||
unsigned long i, packet_len = 19 + name_len + blob_len;
|
||||
unsigned char *comment = NULL;
|
||||
unsigned long comment_len = 0;
|
||||
/* packet_len(4) +
|
||||
add_len(4) +
|
||||
"add"(3) +
|
||||
name_len(4) +
|
||||
{name}
|
||||
blob_len(4) +
|
||||
{blob} */
|
||||
int rc;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s pubickey", name);
|
||||
if (pkey->add_state == libssh2_NB_state_idle) {
|
||||
pkey->add_packet = NULL;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s pubickey", name);
|
||||
|
||||
if (pkey->version == 1) {
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
/* Search for a comment attribute */
|
||||
if (attrs[i].name_len == (sizeof("comment") - 1) &&
|
||||
strncmp(attrs[i].name, "comment", sizeof("comment") - 1) == 0) {
|
||||
comment = (unsigned char *)attrs[i].value;
|
||||
comment_len = attrs[i].value_len;
|
||||
break;
|
||||
if (pkey->version == 1) {
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
/* Search for a comment attribute */
|
||||
if (attrs[i].name_len == (sizeof("comment") - 1) &&
|
||||
strncmp(attrs[i].name, "comment", sizeof("comment") - 1) == 0) {
|
||||
comment = (unsigned char *)attrs[i].value;
|
||||
comment_len = attrs[i].value_len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
packet_len += 4 + comment_len;
|
||||
} else {
|
||||
packet_len += 5; /* overwrite(1) + attribute_count(4) */
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
|
||||
/* name_len(4) + value_len(4) + mandatory(1) */
|
||||
}
|
||||
}
|
||||
packet_len += 4 + comment_len;
|
||||
} else {
|
||||
packet_len += 5; /* overwrite(1) + attribute_count(4) */
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
|
||||
/* name_len(4) + value_len(4) + mandatory(1) */
|
||||
}
|
||||
}
|
||||
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"add\" packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = packet;
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("add") - 1); s += 4;
|
||||
memcpy(s, "add", sizeof("add") - 1); s += sizeof("add") - 1;
|
||||
if (pkey->version == 1) {
|
||||
libssh2_htonu32(s, comment_len); s += 4;
|
||||
if (comment) {
|
||||
memcpy(s, comment, comment_len); s += comment_len;
|
||||
pkey->add_packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!pkey->add_packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"add\" packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
libssh2_htonu32(s, name_len); s += 4;
|
||||
memcpy(s, name, name_len); s += name_len;
|
||||
libssh2_htonu32(s, blob_len); s += 4;
|
||||
memcpy(s, blob, blob_len); s += blob_len;
|
||||
} else {
|
||||
/* Version == 2 */
|
||||
pkey->add_s = pkey->add_packet;
|
||||
libssh2_htonu32(pkey->add_s, packet_len - 4); pkey->add_s += 4;
|
||||
libssh2_htonu32(pkey->add_s, sizeof("add") - 1); pkey->add_s += 4;
|
||||
memcpy(pkey->add_s, "add", sizeof("add") - 1); pkey->add_s += sizeof("add") - 1;
|
||||
if (pkey->version == 1) {
|
||||
libssh2_htonu32(pkey->add_s, comment_len); pkey->add_s += 4;
|
||||
if (comment) {
|
||||
memcpy(pkey->add_s, comment, comment_len); pkey->add_s += comment_len;
|
||||
}
|
||||
|
||||
libssh2_htonu32(s, name_len); s += 4;
|
||||
memcpy(s, name, name_len); s += name_len;
|
||||
libssh2_htonu32(s, blob_len); s += 4;
|
||||
memcpy(s, blob, blob_len); s += blob_len;
|
||||
*(s++) = overwrite ? 0xFF : 0;
|
||||
libssh2_htonu32(s, num_attrs); s += 4;
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
libssh2_htonu32(s, attrs[i].name_len); s += 4;
|
||||
memcpy(s, attrs[i].name, attrs[i].name_len); s += attrs[i].name_len;
|
||||
libssh2_htonu32(s, attrs[i].value_len); s += 4;
|
||||
memcpy(s, attrs[i].value, attrs[i].value_len); s += attrs[i].value_len;
|
||||
*(s++) = attrs[i].mandatory ? 0xFF : 0;
|
||||
libssh2_htonu32(pkey->add_s, name_len); pkey->add_s += 4;
|
||||
memcpy(pkey->add_s, name, name_len); pkey->add_s += name_len;
|
||||
libssh2_htonu32(pkey->add_s, blob_len); pkey->add_s += 4;
|
||||
memcpy(pkey->add_s, blob, blob_len); pkey->add_s += blob_len;
|
||||
} else {
|
||||
/* Version == 2 */
|
||||
|
||||
libssh2_htonu32(pkey->add_s, name_len); pkey->add_s += 4;
|
||||
memcpy(pkey->add_s, name, name_len); pkey->add_s += name_len;
|
||||
libssh2_htonu32(pkey->add_s, blob_len); pkey->add_s += 4;
|
||||
memcpy(pkey->add_s, blob, blob_len); pkey->add_s += blob_len;
|
||||
*(pkey->add_s++) = overwrite ? 0xFF : 0;
|
||||
libssh2_htonu32(pkey->add_s, num_attrs); pkey->add_s += 4;
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
libssh2_htonu32(pkey->add_s, attrs[i].name_len); pkey->add_s += 4;
|
||||
memcpy(pkey->add_s, attrs[i].name, attrs[i].name_len); pkey->add_s += attrs[i].name_len;
|
||||
libssh2_htonu32(pkey->add_s, attrs[i].value_len); pkey->add_s += 4;
|
||||
memcpy(pkey->add_s, attrs[i].value, attrs[i].value_len); pkey->add_s += attrs[i].value_len;
|
||||
*(pkey->add_s++) = attrs[i].mandatory ? 0xFF : 0;
|
||||
}
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld",
|
||||
name, blob_len, num_attrs);
|
||||
|
||||
pkey->add_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (pkey->add_state == libssh2_NB_state_created) {
|
||||
rc = libssh2_channel_write_ex(channel, 0, (char *)pkey->add_packet, (pkey->add_s - pkey->add_packet));
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
else if ((pkey->add_s - pkey->add_packet) != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey add packet", 0);
|
||||
LIBSSH2_FREE(session, pkey->add_packet);
|
||||
pkey->add_packet = NULL;
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, pkey->add_packet);
|
||||
pkey->add_packet = NULL;
|
||||
|
||||
pkey->add_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
|
||||
"Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld",
|
||||
name, blob_len, num_attrs);
|
||||
if ((s - packet) != libssh2_channel_write(channel, (char *)packet, (s - packet))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey add packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
rc = libssh2_publickey_response_success(pkey);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
packet = NULL;
|
||||
|
||||
return libssh2_publickey_response_success(pkey);
|
||||
|
||||
pkey->add_state = libssh2_NB_state_idle;
|
||||
|
||||
return rc;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_remove_ex
|
||||
* Remove an existing publickey so that authentication can no longer be performed using it
|
||||
*/
|
||||
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len)
|
||||
LIBSSH2_API int
|
||||
libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *s, *packet = NULL;
|
||||
/* 22 = packet_len(4) + remove_len(4) + "remove"(6) + name_len(4) + {name} + blob_len(4) + {blob} */
|
||||
unsigned long packet_len = 22 + name_len + blob_len;
|
||||
/* packet_len(4) +
|
||||
remove_len(4) +
|
||||
"remove"(6) +
|
||||
name_len(4) +
|
||||
{name}
|
||||
blob_len(4) +
|
||||
{blob} */
|
||||
int rc;
|
||||
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"remove\" packet", 0);
|
||||
return -1;
|
||||
if (pkey->remove_state == libssh2_NB_state_idle) {
|
||||
pkey->remove_packet = NULL;
|
||||
|
||||
pkey->remove_packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!pkey->remove_packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"remove\" packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pkey->remove_s = pkey->remove_packet;
|
||||
libssh2_htonu32(pkey->remove_s, packet_len - 4); pkey->remove_s += 4;
|
||||
libssh2_htonu32(pkey->remove_s, sizeof("remove") - 1); pkey->remove_s += 4;
|
||||
memcpy(pkey->remove_s, "remove", sizeof("remove") - 1); pkey->remove_s += sizeof("remove") - 1;
|
||||
libssh2_htonu32(pkey->remove_s, name_len); pkey->remove_s += 4;
|
||||
memcpy(pkey->remove_s, name, name_len); pkey->remove_s += name_len;
|
||||
libssh2_htonu32(pkey->remove_s, blob_len); pkey->remove_s += 4;
|
||||
memcpy(pkey->remove_s, blob, blob_len); pkey->remove_s += blob_len;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"remove\" packet: type=%s blob_len=%ld", name, blob_len);
|
||||
|
||||
pkey->remove_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (pkey->remove_state == libssh2_NB_state_created) {
|
||||
rc = libssh2_channel_write_ex(channel, 0, (char *)pkey->remove_packet, (pkey->remove_s - pkey->remove_packet));
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
else if ((pkey->remove_s - pkey->remove_packet) != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey remove packet", 0);
|
||||
LIBSSH2_FREE(session, pkey->remove_packet);
|
||||
pkey->remove_packet = NULL;
|
||||
pkey->remove_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, pkey->remove_packet);
|
||||
pkey->remove_packet = NULL;
|
||||
|
||||
pkey->remove_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
s = packet;
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("remove") - 1); s += 4;
|
||||
memcpy(s, "remove", sizeof("remove") - 1); s += sizeof("remove") - 1;
|
||||
libssh2_htonu32(s, name_len); s += 4;
|
||||
memcpy(s, name, name_len); s += name_len;
|
||||
libssh2_htonu32(s, blob_len); s += 4;
|
||||
memcpy(s, blob, blob_len); s += blob_len;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"remove\" packet: type=%s blob_len=%ld", name, blob_len);
|
||||
if ((s - packet) != libssh2_channel_write(channel, (char *)packet, (s - packet))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey remove packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
rc = libssh2_publickey_response_success(pkey);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
packet = NULL;
|
||||
|
||||
return libssh2_publickey_response_success(pkey);
|
||||
|
||||
pkey->remove_state = libssh2_NB_state_idle;
|
||||
|
||||
return rc;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_list_fetch
|
||||
* Fetch a list of supported public key from a server
|
||||
*/
|
||||
LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list)
|
||||
LIBSSH2_API int
|
||||
libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
libssh2_publickey_list *list = NULL;
|
||||
unsigned char *s, buffer[12], *data = NULL;
|
||||
unsigned long buffer_len = 12, keys = 0, max_keys = 0, data_len, i;
|
||||
/* packet_len(4) +
|
||||
list_len(4) +
|
||||
"list"(4) */
|
||||
unsigned long buffer_len = 12, keys = 0, max_keys = 0, i;
|
||||
/* 12 = packet_len(4) + list_len(4) + "list"(4) */
|
||||
int response;
|
||||
int rc;
|
||||
|
||||
s = buffer;
|
||||
libssh2_htonu32(s, buffer_len - 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("list") - 1); s += 4;
|
||||
memcpy(s, "list", sizeof("list") - 1); s += sizeof("list") - 1;
|
||||
if (pkey->listFetch_state == libssh2_NB_state_idle) {
|
||||
pkey->listFetch_data = NULL;
|
||||
|
||||
pkey->listFetch_s = pkey->listFetch_buffer;
|
||||
libssh2_htonu32(pkey->listFetch_s, buffer_len - 4); pkey->listFetch_s += 4;
|
||||
libssh2_htonu32(pkey->listFetch_s, sizeof("list") - 1); pkey->listFetch_s += 4;
|
||||
memcpy(pkey->listFetch_s, "list", sizeof("list") - 1); pkey->listFetch_s += sizeof("list") - 1;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"list\" packet");
|
||||
if ((s - buffer) != libssh2_channel_write(channel, (char *)buffer, (s - buffer))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet", 0);
|
||||
return -1;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"list\" packet");
|
||||
|
||||
pkey->listFetch_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (pkey->listFetch_state == libssh2_NB_state_created) {
|
||||
rc = libssh2_channel_write_ex(channel, 0, (char *)pkey->listFetch_buffer, (pkey->listFetch_s - pkey->listFetch_buffer));
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
else if ((pkey->listFetch_s - pkey->listFetch_buffer) != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet", 0);
|
||||
pkey->listFetch_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pkey->listFetch_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
|
||||
rc = libssh2_publickey_packet_receive(pkey, &pkey->listFetch_data, &pkey->listFetch_data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
s = data;
|
||||
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
|
||||
pkey->listFetch_s = pkey->listFetch_data;
|
||||
if ((response = libssh2_publickey_response_id(&pkey->listFetch_s, pkey->listFetch_data_len)) < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
@ -576,21 +719,23 @@ LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned l
|
||||
unsigned long status, descr_len, lang_len;
|
||||
unsigned char *descr, *lang;
|
||||
|
||||
status = libssh2_ntohu32(s); s += 4;
|
||||
descr_len = libssh2_ntohu32(s); s += 4;
|
||||
descr = s; s += descr_len;
|
||||
lang_len = libssh2_ntohu32(s); s += 4;
|
||||
lang = s; s += lang_len;
|
||||
status = libssh2_ntohu32(pkey->listFetch_s); pkey->listFetch_s += 4;
|
||||
descr_len = libssh2_ntohu32(pkey->listFetch_s); pkey->listFetch_s += 4;
|
||||
descr = pkey->listFetch_s; pkey->listFetch_s += descr_len;
|
||||
lang_len = libssh2_ntohu32(pkey->listFetch_s); pkey->listFetch_s += 4;
|
||||
lang = pkey->listFetch_s; pkey->listFetch_s += lang_len;
|
||||
|
||||
if (s > data + data_len) {
|
||||
if (pkey->listFetch_s > pkey->listFetch_data + pkey->listFetch_data_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, pkey->listFetch_data);
|
||||
pkey->listFetch_data = NULL;
|
||||
*pkey_list = list;
|
||||
*num_keys = keys;
|
||||
pkey->listFetch_state = libssh2_NB_state_idle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -613,7 +758,7 @@ LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned l
|
||||
if (pkey->version == 1) {
|
||||
unsigned long comment_len;
|
||||
|
||||
comment_len = libssh2_ntohu32(s); s += 4;
|
||||
comment_len = libssh2_ntohu32(pkey->listFetch_s); pkey->listFetch_s += 4;
|
||||
if (comment_len) {
|
||||
list[keys].num_attrs = 1;
|
||||
list[keys].attrs = LIBSSH2_ALLOC(session, sizeof(libssh2_publickey_attribute));
|
||||
@ -623,26 +768,26 @@ LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned l
|
||||
}
|
||||
list[keys].attrs[0].name = "comment";
|
||||
list[keys].attrs[0].name_len = sizeof("comment") - 1;
|
||||
list[keys].attrs[0].value = (char *)s;
|
||||
list[keys].attrs[0].value = (char *)pkey->listFetch_s;
|
||||
list[keys].attrs[0].value_len = comment_len;
|
||||
list[keys].attrs[0].mandatory = 0;
|
||||
|
||||
s += comment_len;
|
||||
pkey->listFetch_s += comment_len;
|
||||
} else {
|
||||
list[keys].num_attrs = 0;
|
||||
list[keys].attrs = NULL;
|
||||
}
|
||||
list[keys].name_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].name = s; s += list[keys].name_len;
|
||||
list[keys].blob_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].blob = s; s += list[keys].blob_len;
|
||||
list[keys].name_len = libssh2_ntohu32(pkey->listFetch_s); pkey->listFetch_s += 4;
|
||||
list[keys].name = pkey->listFetch_s; pkey->listFetch_s += list[keys].name_len;
|
||||
list[keys].blob_len = libssh2_ntohu32(pkey->listFetch_s); pkey->listFetch_s += 4;
|
||||
list[keys].blob = pkey->listFetch_s; pkey->listFetch_s += list[keys].blob_len;
|
||||
} else {
|
||||
/* Version == 2 */
|
||||
list[keys].name_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].name = s; s += list[keys].name_len;
|
||||
list[keys].blob_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].blob = s; s += list[keys].blob_len;
|
||||
list[keys].num_attrs = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].name_len = libssh2_ntohu32(pkey->listFetch_s); pkey->listFetch_s += 4;
|
||||
list[keys].name = pkey->listFetch_s; pkey->listFetch_s += list[keys].name_len;
|
||||
list[keys].blob_len = libssh2_ntohu32(pkey->listFetch_s); pkey->listFetch_s += 4;
|
||||
list[keys].blob = pkey->listFetch_s; pkey->listFetch_s += list[keys].blob_len;
|
||||
list[keys].num_attrs = libssh2_ntohu32(pkey->listFetch_s); pkey->listFetch_s += 4;
|
||||
if (list[keys].num_attrs) {
|
||||
list[keys].attrs = LIBSSH2_ALLOC(session, list[keys].num_attrs * sizeof(libssh2_publickey_attribute));
|
||||
if (!list[keys].attrs) {
|
||||
@ -650,37 +795,44 @@ LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned l
|
||||
goto err_exit;
|
||||
}
|
||||
for(i = 0; i < list[keys].num_attrs; i++) {
|
||||
list[keys].attrs[i].name_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].attrs[i].name = (char *)s; s += list[keys].attrs[i].name_len;
|
||||
list[keys].attrs[i].value_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].attrs[i].value = (char *)s; s += list[keys].attrs[i].value_len;
|
||||
list[keys].attrs[i].name_len = libssh2_ntohu32(pkey->listFetch_s);
|
||||
pkey->listFetch_s += 4;
|
||||
list[keys].attrs[i].name = (char *)pkey->listFetch_s;
|
||||
pkey->listFetch_s += list[keys].attrs[i].name_len;
|
||||
list[keys].attrs[i].value_len = libssh2_ntohu32(pkey->listFetch_s);
|
||||
pkey->listFetch_s += 4;
|
||||
list[keys].attrs[i].value = (char *)pkey->listFetch_s;
|
||||
pkey->listFetch_s += list[keys].attrs[i].value_len;
|
||||
list[keys].attrs[i].mandatory = 0; /* actually an ignored value */
|
||||
}
|
||||
} else {
|
||||
list[keys].attrs = NULL;
|
||||
}
|
||||
}
|
||||
list[keys].packet = data; /* To be FREEd in libssh2_publickey_list_free() */
|
||||
list[keys].packet = pkey->listFetch_data; /* To be FREEd in libssh2_publickey_list_free() */
|
||||
keys++;
|
||||
|
||||
list[keys].packet = NULL; /* Terminate the list */
|
||||
data = NULL;
|
||||
pkey->listFetch_data = NULL;
|
||||
break;
|
||||
default:
|
||||
/* Unknown/Unexpected */
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, pkey->listFetch_data);
|
||||
pkey->listFetch_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only reached via explicit goto */
|
||||
err_exit:
|
||||
if (data) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
if (pkey->listFetch_data) {
|
||||
LIBSSH2_FREE(session, pkey->listFetch_data);
|
||||
pkey->listFetch_data = NULL;
|
||||
}
|
||||
if (list) {
|
||||
libssh2_publickey_list_free(pkey, list);
|
||||
}
|
||||
pkey->listFetch_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
895
src/scp.c
895
src/scp.c
@ -39,392 +39,631 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LIBSSH2_SCP_RESPONSE_BUFLEN 256
|
||||
|
||||
/* {{{ libssh2_scp_recv
|
||||
* [BLOCKING]
|
||||
* Open a channel and request a remote file via SCP
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session,
|
||||
const char *path,
|
||||
struct stat *sb)
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb)
|
||||
{
|
||||
int path_len = strlen(path);
|
||||
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned long command_len = path_len + sizeof("scp -f "), response_len;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
long mode = 0, size = 0, mtime = 0, atime = 0;
|
||||
int rc;
|
||||
|
||||
if (sb) {
|
||||
command_len++;
|
||||
}
|
||||
|
||||
command = LIBSSH2_ALLOC(session, command_len);
|
||||
if (!command) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a command buffer for scp session", 0);
|
||||
return NULL;
|
||||
}
|
||||
if (sb) {
|
||||
memcpy(command, "scp -pf ", sizeof("scp -pf ") - 1);
|
||||
memcpy(command + sizeof("scp -pf ") - 1, path, path_len);
|
||||
} else {
|
||||
memcpy(command, "scp -f ", sizeof("scp -f ") - 1);
|
||||
memcpy(command + sizeof("scp -f ") - 1, path, path_len);
|
||||
}
|
||||
command[command_len - 1] = '\0';
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP receive");
|
||||
/* Allocate a channel */
|
||||
if ((channel = libssh2_channel_open_session(session)) == NULL) {
|
||||
LIBSSH2_FREE(session, command);
|
||||
return NULL;
|
||||
}
|
||||
/* Use blocking I/O for negotiation phase */
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
|
||||
/* Request SCP for the desired file */
|
||||
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
||||
LIBSSH2_FREE(session, command);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
LIBSSH2_FREE(session, command);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
|
||||
/* SCP ACK */
|
||||
response[0] = '\0';
|
||||
if (libssh2_channel_write(channel, response, 1) != 1) {
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Parse SCP response */
|
||||
response_len = 0;
|
||||
while (sb && (response_len < LIBSSH2_SCP_RESPONSE_BUFLEN)) {
|
||||
unsigned char *s, *p;
|
||||
int rc;
|
||||
|
||||
rc = _libssh2_channel_read(channel, response + response_len, 1);
|
||||
if(rc <= 0) {
|
||||
/* Timeout, give up */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Timed out waiting for SCP response", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
response_len++;
|
||||
|
||||
if (response[0] != 'T') {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response, missing Time data", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
if (session->scpRecv_state == libssh2_NB_state_idle) {
|
||||
session->scpRecv_mode = 0;
|
||||
session->scpRecv_size = 0;
|
||||
session->scpRecv_mtime = 0;
|
||||
session->scpRecv_atime = 0;
|
||||
|
||||
session->scpRecv_command_len = path_len + sizeof("scp -f ");
|
||||
|
||||
if (sb) {
|
||||
session->scpRecv_command_len++;
|
||||
}
|
||||
|
||||
if ((response_len > 1) &&
|
||||
((response[response_len-1] < '0') || (response[response_len-1] > '9')) &&
|
||||
(response[response_len-1] != ' ') &&
|
||||
(response[response_len-1] != '\r') &&
|
||||
(response[response_len-1] != '\n')) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response", 0);
|
||||
libssh2_channel_free(channel);
|
||||
session->scpRecv_command = LIBSSH2_ALLOC(session, session->scpRecv_command_len);
|
||||
if (!session->scpRecv_command) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a command buffer for SCP session", 0);
|
||||
return NULL;
|
||||
}
|
||||
if (sb) {
|
||||
memcpy(session->scpRecv_command, "scp -pf ", sizeof("scp -pf ") - 1);
|
||||
memcpy(session->scpRecv_command + sizeof("scp -pf ") - 1, path, path_len);
|
||||
} else {
|
||||
memcpy(session->scpRecv_command, "scp -f ", sizeof("scp -f ") - 1);
|
||||
memcpy(session->scpRecv_command + sizeof("scp -f ") - 1, path, path_len);
|
||||
}
|
||||
session->scpRecv_command[session->scpRecv_command_len - 1] = '\0';
|
||||
|
||||
if ((response_len < 9) || (response[response_len-1] != '\n')) {
|
||||
if (response_len == LIBSSH2_SCP_RESPONSE_BUFLEN) {
|
||||
/* You had your chance */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Unterminated response from SCP server", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP receive");
|
||||
|
||||
session->scpRecv_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_created) {
|
||||
/* Allocate a channel */
|
||||
do {
|
||||
session->scpRecv_channel = libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
|
||||
LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT,
|
||||
NULL, 0);
|
||||
if (!session->scpRecv_channel) {
|
||||
if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
|
||||
LIBSSH2_FREE(session, session->scpRecv_command);
|
||||
session->scpRecv_command = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
else if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block starting up channel", 0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* Way too short to be an SCP response, or not done yet, short circuit */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We're guaranteed not to go under response_len == 0 by the logic above */
|
||||
while ((response[response_len-1] == '\r') || (response[response_len-1] == '\n')) response_len--;
|
||||
response[response_len] = '\0';
|
||||
|
||||
if (response_len < 8) {
|
||||
/* EOL came too soon */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = response + 1;
|
||||
|
||||
p = strchr(s, ' ');
|
||||
if (!p || ((p - s) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mtime", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*(p++) = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
mtime = strtol(s, NULL, 10);
|
||||
if (errno) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid mtime", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
s = strchr(p, ' ');
|
||||
if (!s || ((s - p) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mtime.usec", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Ignore mtime.usec */
|
||||
s++;
|
||||
p = strchr(s, ' ');
|
||||
if (!p || ((p - s) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short or malformed", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*(p++) = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
atime = strtol(s, NULL, 10);
|
||||
if (errno) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid atime", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* SCP ACK */
|
||||
response[0] = '\0';
|
||||
if (libssh2_channel_write(channel, response, 1) != 1) {
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mtime = %ld, atime = %ld", mtime, atime);
|
||||
|
||||
/* We *should* check that atime.usec is valid, but why let that stop use? */
|
||||
break;
|
||||
} while (!session->scpRecv_channel);
|
||||
|
||||
session->scpRecv_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
response_len = 0;
|
||||
while (response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
|
||||
char *s, *p, *e = NULL;
|
||||
|
||||
if (_libssh2_channel_read(channel, response + response_len, 1) <= 0) {
|
||||
/* Timeout, give up */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Timed out waiting for SCP response", 0);
|
||||
libssh2_channel_free(channel);
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent) {
|
||||
/* Request SCP for the desired file */
|
||||
rc = libssh2_channel_process_startup(session->scpRecv_channel, "exec", sizeof("exec") - 1, (char *)session->scpRecv_command, session->scpRecv_command_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block requesting SCP startup", 0);
|
||||
return NULL;
|
||||
}
|
||||
response_len++;
|
||||
|
||||
if (response[0] != 'C') {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((response_len > 1) &&
|
||||
(response[response_len-1] != '\r') &&
|
||||
(response[response_len-1] != '\n') &&
|
||||
((response[response_len-1] < 32) || (response[response_len-1] > 126))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((response_len < 7) || (response[response_len-1] != '\n')) {
|
||||
if (response_len == LIBSSH2_SCP_RESPONSE_BUFLEN) {
|
||||
/* You had your chance */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Unterminated response from SCP server", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
/* Way too short to be an SCP response, or not done yet, short circuit */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We're guaranteed not to go under response_len == 0 by the logic above */
|
||||
while ((response[response_len-1] == '\r') || (response[response_len-1] == '\n')) response_len--;
|
||||
response[response_len] = '\0';
|
||||
|
||||
if (response_len < 6) {
|
||||
/* EOL came too soon */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = response + 1;
|
||||
|
||||
p = strchr(s, ' ');
|
||||
if (!p || ((p - s) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mode", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*(p++) = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
mode = strtol(s, &e, 8);
|
||||
if ((e && *e) || errno) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid mode", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = strchr(p, ' ');
|
||||
if (!s || ((s - p) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short or malformed", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*(s++) = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
size = strtol(p, &e, 10);
|
||||
if ((e && *e) || errno) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid size", 0);
|
||||
libssh2_channel_free(channel);
|
||||
else if (rc) {
|
||||
LIBSSH2_FREE(session, session->scpRecv_command);
|
||||
session->scpRecv_command = NULL;
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
LIBSSH2_FREE(session, session->scpRecv_command);
|
||||
session->scpRecv_command = NULL;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
|
||||
/* SCP ACK */
|
||||
response[0] = '\0';
|
||||
if (libssh2_channel_write(channel, response, 1) != 1) {
|
||||
libssh2_channel_free(channel);
|
||||
session->scpRecv_response[0] = '\0';
|
||||
|
||||
session->scpRecv_state = libssh2_NB_state_sent1;
|
||||
}
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent1) {
|
||||
rc = libssh2_channel_write_ex(session->scpRecv_channel, 0, (char *)session->scpRecv_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending initial wakeup", 0);
|
||||
return NULL;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mod = 0%lo size = %ld", mode, size);
|
||||
else if (rc != 1) {
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Parse SCP response */
|
||||
session->scpRecv_response_len = 0;
|
||||
|
||||
session->scpRecv_state = libssh2_NB_state_sent2;
|
||||
}
|
||||
|
||||
if ((session->scpRecv_state == libssh2_NB_state_sent2) || (session->scpRecv_state == libssh2_NB_state_sent3)) {
|
||||
while (sb && (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN)) {
|
||||
unsigned char *s, *p;
|
||||
|
||||
/* We *should* check that basename is valid, but why let that stop us? */
|
||||
break;
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent2) {
|
||||
rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
|
||||
(char *)session->scpRecv_response + session->scpRecv_response_len, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for SCP response", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc <= 0) {
|
||||
/* Timeout, give up */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Timed out waiting for SCP response", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
session->scpRecv_response_len++;
|
||||
|
||||
if (session->scpRecv_response[0] != 'T') {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response, missing Time data", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((session->scpRecv_response_len > 1) &&
|
||||
((session->scpRecv_response[session->scpRecv_response_len-1] < '0') ||
|
||||
(session->scpRecv_response[session->scpRecv_response_len-1] > '9')) &&
|
||||
(session->scpRecv_response[session->scpRecv_response_len-1] != ' ') &&
|
||||
(session->scpRecv_response[session->scpRecv_response_len-1] != '\r') &&
|
||||
(session->scpRecv_response[session->scpRecv_response_len-1] != '\n')) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((session->scpRecv_response_len < 9) || (session->scpRecv_response[session->scpRecv_response_len-1] != '\n')) {
|
||||
if (session->scpRecv_response_len == LIBSSH2_SCP_RESPONSE_BUFLEN) {
|
||||
/* You had your chance */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Unterminated response from SCP server", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
/* Way too short to be an SCP response, or not done yet, short circuit */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We're guaranteed not to go under response_len == 0 by the logic above */
|
||||
while ((session->scpRecv_response[session->scpRecv_response_len-1] == '\r') || (session->scpRecv_response[session->scpRecv_response_len-1] == '\n')) session->scpRecv_response_len--;
|
||||
session->scpRecv_response[session->scpRecv_response_len] = '\0';
|
||||
|
||||
if (session->scpRecv_response_len < 8) {
|
||||
/* EOL came too soon */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = session->scpRecv_response + 1;
|
||||
|
||||
p = (unsigned char *)strchr((char *)s, ' ');
|
||||
if (!p || ((p - s) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mtime", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*(p++) = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
session->scpRecv_mtime = strtol((char *)s, NULL, 10);
|
||||
if (errno) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid mtime", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
s = (unsigned char *)strchr((char *)p, ' ');
|
||||
if (!s || ((s - p) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mtime.usec", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Ignore mtime.usec */
|
||||
s++;
|
||||
p = (unsigned char *)strchr((char *)s, ' ');
|
||||
if (!p || ((p - s) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short or malformed", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*(p++) = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
session->scpRecv_atime = strtol((char *)s, NULL, 10);
|
||||
if (errno) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid atime", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* SCP ACK */
|
||||
session->scpRecv_response[0] = '\0';
|
||||
|
||||
session->scpRecv_state = libssh2_NB_state_sent3;
|
||||
}
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent3) {
|
||||
rc = libssh2_channel_write_ex(session->scpRecv_channel, 0, (char *)session->scpRecv_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting to send SCP ACK", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc != 1) {
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mtime = %ld, atime = %ld", session->scpRecv_mtime, session->scpRecv_atime);
|
||||
|
||||
/* We *should* check that atime.usec is valid, but why let that stop use? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
session->scpRecv_state = libssh2_NB_state_sent4;
|
||||
}
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent4) {
|
||||
session->scpRecv_response_len = 0;
|
||||
|
||||
session->scpRecv_state = libssh2_NB_state_sent5;
|
||||
}
|
||||
|
||||
if ((session->scpRecv_state == libssh2_NB_state_sent5) || (session->scpRecv_state == libssh2_NB_state_sent6)) {
|
||||
while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
|
||||
char *s, *p, *e = NULL;
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent5) {
|
||||
rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
|
||||
(char *)session->scpRecv_response + session->scpRecv_response_len, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for SCP response", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc <= 0) {
|
||||
/* Timeout, give up */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Timed out waiting for SCP response", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
session->scpRecv_response_len++;
|
||||
|
||||
if (session->scpRecv_response[0] != 'C') {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((session->scpRecv_response_len > 1) &&
|
||||
(session->scpRecv_response[session->scpRecv_response_len-1] != '\r') &&
|
||||
(session->scpRecv_response[session->scpRecv_response_len-1] != '\n') &&
|
||||
((session->scpRecv_response[session->scpRecv_response_len-1] < 32) ||
|
||||
(session->scpRecv_response[session->scpRecv_response_len-1] > 126))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((session->scpRecv_response_len < 7) || (session->scpRecv_response[session->scpRecv_response_len-1] != '\n')) {
|
||||
if (session->scpRecv_response_len == LIBSSH2_SCP_RESPONSE_BUFLEN) {
|
||||
/* You had your chance */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Unterminated response from SCP server", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
/* Way too short to be an SCP response, or not done yet, short circuit */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We're guaranteed not to go under response_len == 0 by the logic above */
|
||||
while ((session->scpRecv_response[session->scpRecv_response_len-1] == '\r') ||
|
||||
(session->scpRecv_response[session->scpRecv_response_len-1] == '\n')) {
|
||||
session->scpRecv_response_len--;
|
||||
}
|
||||
session->scpRecv_response[session->scpRecv_response_len] = '\0';
|
||||
|
||||
if (session->scpRecv_response_len < 6) {
|
||||
/* EOL came too soon */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = (char *)session->scpRecv_response + 1;
|
||||
|
||||
p = strchr(s, ' ');
|
||||
if (!p || ((p - s) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mode", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*(p++) = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
session->scpRecv_mode = strtol(s, &e, 8);
|
||||
if ((e && *e) || errno) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid mode", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = strchr(p, ' ');
|
||||
if (!s || ((s - p) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short or malformed",
|
||||
0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*(s++) = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
session->scpRecv_size = strtol(p, &e, 10);
|
||||
if ((e && *e) || errno) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid size", 0);
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* SCP ACK */
|
||||
session->scpRecv_response[0] = '\0';
|
||||
|
||||
session->scpRecv_state = libssh2_NB_state_sent6;
|
||||
}
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent6) {
|
||||
rc = libssh2_channel_write_ex(session->scpRecv_channel, 0, (char *)session->scpRecv_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending SCP ACK", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc != 1) {
|
||||
libssh2_channel_free(session->scpRecv_channel);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mode = 0%lo size = %ld", session->scpRecv_mode, session->scpRecv_size);
|
||||
|
||||
/* We *should* check that basename is valid, but why let that stop us? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
session->scpRecv_state = libssh2_NB_state_sent7;
|
||||
}
|
||||
|
||||
if (sb) {
|
||||
memset(sb, 0, sizeof(struct stat));
|
||||
|
||||
sb->st_mtime = mtime;
|
||||
sb->st_atime = atime;
|
||||
sb->st_size = size;
|
||||
sb->st_mode = mode;
|
||||
sb->st_mtime = session->scpRecv_mtime;
|
||||
sb->st_atime = session->scpRecv_atime;
|
||||
sb->st_size = session->scpRecv_size;
|
||||
sb->st_mode = session->scpRecv_mode;
|
||||
}
|
||||
/* Revert to non-blocking and let the data BEGIN! */
|
||||
libssh2_channel_set_blocking(channel, 0);
|
||||
|
||||
return channel;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return session->scpRecv_channel;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_scp_send_ex
|
||||
* Send a file using SCP
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime)
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *
|
||||
libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime)
|
||||
{
|
||||
int path_len = strlen(path);
|
||||
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned long response_len, command_len = path_len + sizeof("scp -t ");
|
||||
unsigned const char *base;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
int rc;
|
||||
|
||||
if (mtime || atime) {
|
||||
command_len++;
|
||||
if (session->scpSend_state == libssh2_NB_state_idle) {
|
||||
session->scpSend_command_len = path_len + sizeof("scp -t ");
|
||||
|
||||
if (mtime || atime) {
|
||||
session->scpSend_command_len++;
|
||||
}
|
||||
|
||||
session->scpSend_command = LIBSSH2_ALLOC(session, session->scpSend_command_len);
|
||||
if (!session->scpSend_command) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a command buffer for scp session", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mtime || atime) {
|
||||
memcpy(session->scpSend_command, "scp -pt ", sizeof("scp -pt ") - 1);
|
||||
memcpy(session->scpSend_command + sizeof("scp -pt ") - 1, path, path_len);
|
||||
} else {
|
||||
memcpy(session->scpSend_command, "scp -t ", sizeof("scp -t ") - 1);
|
||||
memcpy(session->scpSend_command + sizeof("scp -t ") - 1, path, path_len);
|
||||
}
|
||||
session->scpSend_command[session->scpSend_command_len - 1] = '\0';
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP send");
|
||||
/* Allocate a channel */
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (session->scpSend_state == libssh2_NB_state_created) {
|
||||
session->scpSend_channel = libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
|
||||
LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
|
||||
if (!session->scpSend_channel) {
|
||||
if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
|
||||
/* previous call set libssh2_session_last_error(), pass it through */
|
||||
LIBSSH2_FREE(session, session->scpSend_command);
|
||||
session->scpSend_command = NULL;
|
||||
session->scpSend_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
else if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block starting up channel", 0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
command = LIBSSH2_ALLOC(session, command_len);
|
||||
if (!command) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a command buffer for scp session", 0);
|
||||
return NULL;
|
||||
if (session->scpSend_state == libssh2_NB_state_sent) {
|
||||
/* Request SCP for the desired file */
|
||||
rc = libssh2_channel_process_startup(session->scpSend_channel, "exec", sizeof("exec") - 1,
|
||||
(char *)session->scpSend_command, session->scpSend_command_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block requesting SCP startup", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc) {
|
||||
/* previous call set libssh2_session_last_error(), pass it through */
|
||||
LIBSSH2_FREE(session, session->scpSend_command);
|
||||
session->scpSend_command = NULL;
|
||||
libssh2_channel_free(session->scpSend_channel);
|
||||
session->scpSend_channel = NULL;
|
||||
session->scpSend_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
LIBSSH2_FREE(session, session->scpSend_command);
|
||||
session->scpSend_command = NULL;
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_sent1;
|
||||
}
|
||||
|
||||
if (mtime || atime) {
|
||||
memcpy(command, "scp -pt ", sizeof("scp -pt ") - 1);
|
||||
memcpy(command + sizeof("scp -pt ") - 1, path, path_len);
|
||||
} else {
|
||||
memcpy(command, "scp -t ", sizeof("scp -t ") - 1);
|
||||
memcpy(command + sizeof("scp -t ") - 1, path, path_len);
|
||||
}
|
||||
command[command_len - 1] = '\0';
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP send");
|
||||
/* Allocate a channel */
|
||||
if ((channel = libssh2_channel_open_session(session)) == NULL) {
|
||||
/* previous call set libssh2_session_last_error(), pass it through */
|
||||
LIBSSH2_FREE(session, command);
|
||||
return NULL;
|
||||
}
|
||||
/* Use blocking I/O for negotiation phase */
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
|
||||
/* Request SCP for the desired file */
|
||||
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
||||
/* previous call set libssh2_session_last_error(), pass it through */
|
||||
LIBSSH2_FREE(session, command);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
LIBSSH2_FREE(session, command);
|
||||
|
||||
/* Wait for ACK */
|
||||
if ((_libssh2_channel_read(channel, response, 1) <= 0) || (response[0] != 0)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
if (session->scpSend_state == libssh2_NB_state_sent1) {
|
||||
/* Wait for ACK */
|
||||
rc = libssh2_channel_read_ex(session->scpSend_channel, 0, (char *)session->scpSend_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response from remote", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
|
||||
libssh2_channel_free(session->scpSend_channel);
|
||||
session->scpSend_channel = NULL;
|
||||
session->scpSend_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mtime || atime) {
|
||||
/* Send mtime and atime to be used for file */
|
||||
session->scpSend_response_len = snprintf((char *)session->scpSend_response, LIBSSH2_SCP_RESPONSE_BUFLEN,
|
||||
"T%ld 0 %ld 0\n", mtime, atime);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", session->scpSend_response);
|
||||
}
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_sent2;
|
||||
}
|
||||
|
||||
/* Send mtime and atime to be used for file */
|
||||
if (mtime || atime) {
|
||||
response_len = snprintf(response, LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime, atime);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", response);
|
||||
|
||||
if (libssh2_channel_write(channel, response, response_len) != response_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send time data for SCP file", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
if (session->scpSend_state == libssh2_NB_state_sent2) {
|
||||
rc = libssh2_channel_write_ex(session->scpSend_channel, 0, (char *)session->scpSend_response,
|
||||
session->scpSend_response_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending time data for SCP file", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc != session->scpSend_response_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send time data for SCP file", 0);
|
||||
libssh2_channel_free(session->scpSend_channel);
|
||||
session->scpSend_channel = NULL;
|
||||
session->scpSend_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_sent3;
|
||||
}
|
||||
/* Wait for ACK */
|
||||
if ((_libssh2_channel_read(channel, response, 1) <= 0) || (response[0] != 0)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
|
||||
if (session->scpSend_state == libssh2_NB_state_sent3) {
|
||||
/* Wait for ACK */
|
||||
rc = libssh2_channel_read_ex(session->scpSend_channel, 0, (char *)session->scpSend_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
|
||||
libssh2_channel_free(session->scpSend_channel);
|
||||
session->scpSend_channel = NULL;
|
||||
session->scpSend_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_sent4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send mode, size, and basename */
|
||||
base = strrchr(path, '/');
|
||||
if (base) {
|
||||
base++;
|
||||
} else {
|
||||
base = path;
|
||||
if (session->scpSend_state == libssh2_NB_state_sent2) {
|
||||
session->scpSend_state = libssh2_NB_state_sent4;
|
||||
}
|
||||
}
|
||||
|
||||
response_len = snprintf(response, LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode, (unsigned long)size, base);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", response);
|
||||
if (libssh2_channel_write(channel, response, response_len) != response_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send core file data for SCP file", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
if (session->scpSend_state == libssh2_NB_state_sent4) {
|
||||
/* Send mode, size, and basename */
|
||||
base = (unsigned char *)strrchr(path, '/');
|
||||
if (base) {
|
||||
base++;
|
||||
} else {
|
||||
base = (unsigned char *)path;
|
||||
}
|
||||
|
||||
session->scpSend_response_len = snprintf((char *)session->scpSend_response, LIBSSH2_SCP_RESPONSE_BUFLEN,
|
||||
"C0%o %lu %s\n", mode, (unsigned long)size, base);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", session->scpSend_response);
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_sent5;
|
||||
}
|
||||
|
||||
if (session->scpSend_state == libssh2_NB_state_sent5) {
|
||||
rc = libssh2_channel_write_ex(session->scpSend_channel, 0, (char *)session->scpSend_response,
|
||||
session->scpSend_response_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block send core file data for SCP file", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc != session->scpSend_response_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send core file data for SCP file", 0);
|
||||
libssh2_channel_free(session->scpSend_channel);
|
||||
session->scpSend_channel = NULL;
|
||||
session->scpSend_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_sent6;
|
||||
}
|
||||
|
||||
/* Wait for ACK */
|
||||
if ((_libssh2_channel_read(channel, response, 1) <= 0) || (response[0] != 0)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
|
||||
libssh2_channel_free(channel);
|
||||
rc = libssh2_channel_read_ex(session->scpSend_channel, 0, (char *)session->scpSend_response, 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
|
||||
libssh2_channel_free(session->scpSend_channel);
|
||||
session->scpSend_channel = NULL;
|
||||
session->scpSend_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_idle;
|
||||
|
||||
/* Ready to start, switch to non-blocking and let calling app send file */
|
||||
libssh2_channel_set_blocking(channel, 0);
|
||||
|
||||
return channel;
|
||||
return session->scpSend_channel;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
607
src/session.c
607
src/session.c
@ -41,6 +41,7 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
#include <sys/time.h>
|
||||
@ -76,17 +77,24 @@ static LIBSSH2_REALLOC_FUNC(libssh2_default_realloc)
|
||||
/* {{{ libssh2_banner_receive
|
||||
* Wait for a hello from the remote host
|
||||
* Allocate a buffer and store the banner in session->remote.banner
|
||||
* Returns: 0 on success, 1 on failure
|
||||
* Returns: 0 on success, PACKET_EAGAIN if read would block, 1 on failure
|
||||
*/
|
||||
static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
{
|
||||
char banner[256];
|
||||
int banner_len = 0;
|
||||
int ret;
|
||||
int banner_len;
|
||||
|
||||
while ((banner_len < (int)sizeof(banner)) &&
|
||||
((banner_len == 0) || (banner[banner_len-1] != '\n'))) {
|
||||
if (session->banner_TxRx_state == libssh2_NB_state_idle) {
|
||||
banner_len = 0;
|
||||
|
||||
session->banner_TxRx_state = libssh2_NB_state_created;
|
||||
} else {
|
||||
banner_len = session->banner_TxRx_total_send;
|
||||
}
|
||||
|
||||
while ((banner_len < (int)sizeof(session->banner_TxRx_banner)) &&
|
||||
((banner_len == 0) || (session->banner_TxRx_banner[banner_len-1] != '\n'))) {
|
||||
char c = '\0';
|
||||
int ret;
|
||||
|
||||
ret = recv(session->socket_fd, &c, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
|
||||
@ -96,20 +104,28 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
case WSAEWOULDBLOCK:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
|
||||
case WSAENOTSOCK:
|
||||
errno = EBADF;
|
||||
break;
|
||||
|
||||
case WSAENOTCONN:
|
||||
case WSAECONNABORTED:
|
||||
errno = WSAENOTCONN;
|
||||
break;
|
||||
|
||||
case WSAEINTR:
|
||||
errno = EINTR;
|
||||
break;
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
if (errno != EAGAIN) {
|
||||
/* Some kinda error, but don't break for non-blocking issues */
|
||||
if (errno == EAGAIN) {
|
||||
session->banner_TxRx_total_send = banner_len;
|
||||
return PACKET_EAGAIN;
|
||||
} else {
|
||||
/* Some kinda error */
|
||||
session->banner_TxRx_state = libssh2_NB_state_idle;
|
||||
session->banner_TxRx_total_send = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -118,17 +134,24 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
|
||||
if (c == '\0') {
|
||||
/* NULLs are not allowed in SSH banners */
|
||||
session->banner_TxRx_state = libssh2_NB_state_idle;
|
||||
session->banner_TxRx_total_send = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
banner[banner_len++] = c;
|
||||
session->banner_TxRx_banner[banner_len++] = c;
|
||||
}
|
||||
|
||||
while (banner_len &&
|
||||
((banner[banner_len-1] == '\n') || (banner[banner_len-1] == '\r'))) {
|
||||
((session->banner_TxRx_banner[banner_len-1] == '\n') ||
|
||||
(session->banner_TxRx_banner[banner_len-1] == '\r'))) {
|
||||
banner_len--;
|
||||
}
|
||||
|
||||
/* From this point on, we are done here */
|
||||
session->banner_TxRx_state = libssh2_NB_state_idle;
|
||||
session->banner_TxRx_total_send = 0;
|
||||
|
||||
if (!banner_len) return 1;
|
||||
|
||||
session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
|
||||
@ -136,7 +159,7 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Error allocating space for remote banner", 0);
|
||||
return 1;
|
||||
}
|
||||
memcpy(session->remote.banner, banner, banner_len);
|
||||
memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len);
|
||||
session->remote.banner[banner_len] = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s", session->remote.banner);
|
||||
return 0;
|
||||
@ -145,38 +168,179 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
|
||||
/* {{{ libssh2_banner_send
|
||||
* Send the default banner, or the one set via libssh2_setopt_string
|
||||
*
|
||||
* Returns PACKET_EAGAIN if it would block - and if it does so, you should
|
||||
* call this function again as soon as it is likely that more data can be
|
||||
* sent, and this function should then be called with the same argument set
|
||||
* (same data pointer and same data_len) until zero or failure is returned.
|
||||
*/
|
||||
static int libssh2_banner_send(LIBSSH2_SESSION *session)
|
||||
{
|
||||
char *banner = (char *)LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF;
|
||||
int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1;
|
||||
|
||||
if (session->local.banner) {
|
||||
/* setopt_string will have given us our \r\n characters */
|
||||
banner_len = strlen((char *)session->local.banner);
|
||||
banner = (char *)session->local.banner;
|
||||
}
|
||||
ssize_t ret;
|
||||
#ifdef LIBSSH2DEBUG
|
||||
{
|
||||
/* Hack and slash to avoid sending CRLF in debug output */
|
||||
char banner_dup[256];
|
||||
|
||||
if (banner_len < 256) {
|
||||
memcpy(banner_dup, banner, banner_len - 2);
|
||||
banner_dup[banner_len - 2] = '\0';
|
||||
} else {
|
||||
memcpy(banner_dup, banner, 255);
|
||||
banner[255] = '\0';
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s", banner_dup);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (send(session->socket_fd, banner, banner_len, LIBSSH2_SOCKET_SEND_FLAGS(session)) == banner_len) ? 0 : 1;
|
||||
if (session->banner_TxRx_state == libssh2_NB_state_idle) {
|
||||
if (session->local.banner) {
|
||||
/* setopt_string will have given us our \r\n characters */
|
||||
banner_len = strlen((char *)session->local.banner);
|
||||
banner = (char *)session->local.banner;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2DEBUG
|
||||
/* Hack and slash to avoid sending CRLF in debug output */
|
||||
if (banner_len < 256) {
|
||||
memcpy(banner_dup, banner, banner_len - 2);
|
||||
banner_dup[banner_len - 2] = '\0';
|
||||
} else {
|
||||
memcpy(banner_dup, banner, 255);
|
||||
banner[255] = '\0';
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s", banner_dup);
|
||||
#endif
|
||||
|
||||
session->banner_TxRx_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
ret = send(session->socket_fd, banner+session->banner_TxRx_total_send, banner_len-session->banner_TxRx_total_send,
|
||||
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
|
||||
if (ret != (banner_len-session->banner_TxRx_total_send)) {
|
||||
if ((ret > 0 ) || ((ret == -1) && (errno == EAGAIN))) {
|
||||
/* the whole packet could not be sent, save the what was */
|
||||
session->banner_TxRx_total_send += ret;
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
session->banner_TxRx_state = libssh2_NB_state_idle;
|
||||
session->banner_TxRx_total_send = 0;
|
||||
return PACKET_FAIL;
|
||||
}
|
||||
|
||||
/* Set the state back to idle */
|
||||
session->banner_TxRx_state = libssh2_NB_state_idle;
|
||||
session->banner_TxRx_total_send = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/*
|
||||
* _libssh2_nonblock() sets the given socket to either blocking or
|
||||
* non-blocking mode based on the 'nonblock' boolean argument. This function
|
||||
* is copied from the libcurl sources with permission.
|
||||
*/
|
||||
static int _libssh2_nonblock(int sockfd, /* operate on this */
|
||||
int nonblock /* TRUE or FALSE */)
|
||||
{
|
||||
#undef SETBLOCK
|
||||
#define SETBLOCK 0
|
||||
#ifdef HAVE_O_NONBLOCK
|
||||
/* most recent unix versions */
|
||||
int flags;
|
||||
|
||||
flags = fcntl(sockfd, F_GETFL, 0);
|
||||
if (nonblock)
|
||||
return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
|
||||
else
|
||||
return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
|
||||
#undef SETBLOCK
|
||||
#define SETBLOCK 1
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
|
||||
/* older unix versions */
|
||||
int flags;
|
||||
|
||||
flags = nonblock;
|
||||
return ioctl(sockfd, FIONBIO, &flags);
|
||||
#undef SETBLOCK
|
||||
#define SETBLOCK 2
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
|
||||
/* Windows? */
|
||||
unsigned long flags;
|
||||
flags = nonblock;
|
||||
|
||||
return ioctlsocket(sockfd, FIONBIO, &flags);
|
||||
#undef SETBLOCK
|
||||
#define SETBLOCK 3
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
|
||||
/* presumably for Amiga */
|
||||
return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
|
||||
#undef SETBLOCK
|
||||
#define SETBLOCK 4
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
|
||||
/* BeOS */
|
||||
long b = nonblock ? 1 : 0;
|
||||
return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
|
||||
#undef SETBLOCK
|
||||
#define SETBLOCK 5
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DISABLED_NONBLOCKING
|
||||
return 0; /* returns success */
|
||||
#undef SETBLOCK
|
||||
#define SETBLOCK 6
|
||||
#endif
|
||||
|
||||
#if (SETBLOCK == 0)
|
||||
#error "no non-blocking method was found/used/set"
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* _libssh2_get_socket_nonblocking() gets the given blocking or non-blocking
|
||||
* state of the socket.
|
||||
*/
|
||||
static int _libssh2_get_socket_nonblocking(int sockfd) /* operate on this */
|
||||
{
|
||||
#undef GETBLOCK
|
||||
#define GETBLOCK 0
|
||||
#ifdef HAVE_O_NONBLOCK
|
||||
/* most recent unix versions */
|
||||
int flags;
|
||||
|
||||
if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1) {
|
||||
/* Assume blocking on error */
|
||||
return 1;
|
||||
}
|
||||
return (flags & O_NONBLOCK);
|
||||
#undef GETBLOCK
|
||||
#define GETBLOCK 1
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0)
|
||||
/* BeOS */
|
||||
long b;
|
||||
if (getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) {
|
||||
/* Assume blocking on error */
|
||||
return 1;
|
||||
}
|
||||
return (int)b;
|
||||
#undef GETBLOCK
|
||||
#define GETBLOCK 5
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DISABLED_NONBLOCKING
|
||||
return 1; /* returns blocking */
|
||||
#undef GETBLOCK
|
||||
#define GETBLOCK 6
|
||||
#endif
|
||||
|
||||
#if (GETBLOCK == 0)
|
||||
#error "no non-blocking method was found/used/get"
|
||||
#endif
|
||||
}
|
||||
|
||||
/* {{{ libssh2_banner_set
|
||||
* Set the local banner
|
||||
*/
|
||||
@ -195,15 +359,13 @@ LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner)
|
||||
|
||||
session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3);
|
||||
if (!session->local.banner) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for local banner", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for local banner", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(session->local.banner, banner, banner_len);
|
||||
session->local.banner[banner_len] = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
"Setting local Banner: %s", session->local.banner);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s", session->local.banner);
|
||||
session->local.banner[banner_len++] = '\r';
|
||||
session->local.banner[banner_len++] = '\n';
|
||||
session->local.banner[banner_len++] = '\0';
|
||||
@ -229,12 +391,15 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
|
||||
LIBSSH2_REALLOC_FUNC((*local_realloc)) = libssh2_default_realloc;
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
if (my_alloc)
|
||||
local_alloc = my_alloc;
|
||||
if (my_free)
|
||||
local_free = my_free;
|
||||
if (my_realloc)
|
||||
if (my_alloc) {
|
||||
local_alloc = my_alloc;
|
||||
}
|
||||
if (my_free) {
|
||||
local_free = my_free;
|
||||
}
|
||||
if (my_realloc) {
|
||||
local_realloc = my_realloc;
|
||||
}
|
||||
|
||||
session = local_alloc(sizeof(LIBSSH2_SESSION), abstract);
|
||||
if (session) {
|
||||
@ -243,8 +408,7 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
|
||||
session->free = local_free;
|
||||
session->realloc = local_realloc;
|
||||
session->abstract = abstract;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
"New session resource allocated");
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "New session resource allocated");
|
||||
libssh2_crypto_init ();
|
||||
}
|
||||
return session;
|
||||
@ -255,9 +419,7 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
|
||||
* Set (or reset) a callback function
|
||||
* Returns the prior address
|
||||
*/
|
||||
LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session,
|
||||
int cbtype,
|
||||
void *callback)
|
||||
LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback)
|
||||
{
|
||||
void *oldcb;
|
||||
|
||||
@ -303,75 +465,129 @@ LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session,
|
||||
*/
|
||||
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
|
||||
{
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
unsigned char service[sizeof("ssh-userauth") + 5 - 1];
|
||||
unsigned long service_length;
|
||||
int rc;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
"session_startup for socket %d", socket);
|
||||
/* FIXME: on some platforms (like win32) sockets are unsigned */
|
||||
if (socket < 0) {
|
||||
/* Did we forget something? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
|
||||
"Bad socket provided", 0);
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
"session_startup for socket %d", socket);
|
||||
/* FIXME: on some platforms (like win32) sockets are unsigned */
|
||||
if (socket < 0) {
|
||||
/* Did we forget something? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE, "Bad socket provided", 0);
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
}
|
||||
session->socket_fd = socket;
|
||||
|
||||
session->socket_block = !_libssh2_get_socket_nonblocking(session->socket_fd);
|
||||
if (session->socket_block) {
|
||||
/*
|
||||
* Since we can't be sure that we are in blocking or there
|
||||
* was an error detecting the state, so set to blocking to
|
||||
* be sure
|
||||
*/
|
||||
_libssh2_nonblock(session->socket_fd, 0);
|
||||
}
|
||||
|
||||
session->startup_state = libssh2_NB_state_created;
|
||||
}
|
||||
session->socket_fd = socket;
|
||||
|
||||
|
||||
/* TODO: Liveness check */
|
||||
if (libssh2_banner_send(session)) {
|
||||
/* Unable to send banner? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND,
|
||||
"Error sending banner to remote host", 0);
|
||||
return LIBSSH2_ERROR_BANNER_SEND;
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_created) {
|
||||
rc = libssh2_banner_send(session);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending banner to remote host", 0);
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
else if (rc) {
|
||||
/* Unable to send banner? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND, "Error sending banner to remote host", 0);
|
||||
return LIBSSH2_ERROR_BANNER_SEND;
|
||||
}
|
||||
|
||||
session->startup_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
if (libssh2_banner_receive(session)) {
|
||||
/* Unable to receive banner from remote */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE,
|
||||
"Timeout waiting for banner", 0);
|
||||
return LIBSSH2_ERROR_BANNER_NONE;
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_sent) {
|
||||
rc = libssh2_banner_receive(session);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for banner", 0);
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
else if (rc) {
|
||||
/* Unable to receive banner from remote */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE, "Timeout waiting for banner", 0);
|
||||
return LIBSSH2_ERROR_BANNER_NONE;
|
||||
}
|
||||
|
||||
session->startup_state = libssh2_NB_state_sent1;
|
||||
}
|
||||
|
||||
rc = libssh2_kex_exchange(session, 0);
|
||||
if(rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
|
||||
"Unable to exchange encryption keys", 0);
|
||||
return LIBSSH2_ERROR_KEX_FAILURE;
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_sent1) {
|
||||
rc = libssh2_kex_exchange(session, 0, &session->startup_key_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block exchanging encryption keys", 0);
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to exchange encryption keys", 0);
|
||||
return LIBSSH2_ERROR_KEX_FAILURE;
|
||||
}
|
||||
|
||||
session->startup_state = libssh2_NB_state_sent2;
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
|
||||
"Requesting userauth service");
|
||||
/* Request the userauth service */
|
||||
service[0] = SSH_MSG_SERVICE_REQUEST;
|
||||
libssh2_htonu32(service + 1, sizeof("ssh-userauth") - 1);
|
||||
memcpy(service + 5, "ssh-userauth", sizeof("ssh-userauth") - 1);
|
||||
if (libssh2_packet_write(session, service,
|
||||
sizeof("ssh-userauth") + 5 - 1)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to ask for ssh-userauth service", 0);
|
||||
return LIBSSH2_ERROR_SOCKET_SEND;
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_sent2) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Requesting userauth service");
|
||||
|
||||
/* Request the userauth service */
|
||||
session->startup_service[0] = SSH_MSG_SERVICE_REQUEST;
|
||||
libssh2_htonu32(session->startup_service + 1, sizeof("ssh-userauth") - 1);
|
||||
memcpy(session->startup_service + 5, "ssh-userauth", sizeof("ssh-userauth") - 1);
|
||||
|
||||
session->startup_state = libssh2_NB_state_sent3;
|
||||
}
|
||||
|
||||
rc = libssh2_packet_require(session, SSH_MSG_SERVICE_ACCEPT, &data,
|
||||
&data_len);
|
||||
if(rc) {
|
||||
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_sent3) {
|
||||
rc = libssh2_packet_write(session, session->startup_service, sizeof("ssh-userauth") + 5 - 1);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block asking for ssh-userauth service", 0);
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to ask for ssh-userauth service", 0);
|
||||
return LIBSSH2_ERROR_SOCKET_SEND;
|
||||
}
|
||||
|
||||
session->startup_state = libssh2_NB_state_sent4;
|
||||
}
|
||||
service_length = libssh2_ntohu32(data + 1);
|
||||
|
||||
if ((service_length != (sizeof("ssh-userauth") - 1)) ||
|
||||
strncmp("ssh-userauth", (char *)data + 5, service_length)) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Invalid response received from server", 0);
|
||||
return LIBSSH2_ERROR_PROTO;
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_sent4) {
|
||||
rc = libssh2_packet_require_ex(session, SSH_MSG_SERVICE_ACCEPT, &session->startup_data, &session->startup_data_len,
|
||||
0, NULL, 0, &session->startup_req_state);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
else if (rc) {
|
||||
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
||||
}
|
||||
session->startup_service_length = libssh2_ntohu32(session->startup_data + 1);
|
||||
|
||||
if ((session->startup_service_length != (sizeof("ssh-userauth") - 1)) ||
|
||||
strncmp("ssh-userauth", (char *)session->startup_data + 5, session->startup_service_length)) {
|
||||
LIBSSH2_FREE(session, session->startup_data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PROTO, "Invalid response received from server", 0);
|
||||
return LIBSSH2_ERROR_PROTO;
|
||||
}
|
||||
LIBSSH2_FREE(session, session->startup_data);
|
||||
|
||||
session->startup_state = libssh2_NB_state_idle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
return 0;
|
||||
|
||||
/* just for safety return some error */
|
||||
return LIBSSH2_ERROR_INVAL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -506,42 +722,53 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
*/
|
||||
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang)
|
||||
{
|
||||
unsigned char *s, *data;
|
||||
unsigned long data_len, descr_len = 0, lang_len = 0;
|
||||
unsigned char *s;
|
||||
unsigned long descr_len = 0, lang_len = 0;
|
||||
int rc;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnecting: reason=%d, desc=%s, lang=%s", reason, description, lang);
|
||||
if (description) {
|
||||
descr_len = strlen(description);
|
||||
}
|
||||
if (lang) {
|
||||
lang_len = strlen(lang);
|
||||
}
|
||||
data_len = descr_len + lang_len + 13; /* packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
|
||||
if (session->disconnect_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnecting: reason=%d, desc=%s, lang=%s", reason, description, lang);
|
||||
if (description) {
|
||||
descr_len = strlen(description);
|
||||
}
|
||||
if (lang) {
|
||||
lang_len = strlen(lang);
|
||||
}
|
||||
/* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
|
||||
session->disconnect_data_len = descr_len + lang_len + 13;
|
||||
|
||||
s = data = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!data) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for disconnect packet", 0);
|
||||
return -1;
|
||||
s = session->disconnect_data = LIBSSH2_ALLOC(session, session->disconnect_data_len);
|
||||
if (!session->disconnect_data) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for disconnect packet", 0);
|
||||
session->disconnect_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(s++) = SSH_MSG_DISCONNECT;
|
||||
libssh2_htonu32(s, reason); s += 4;
|
||||
|
||||
libssh2_htonu32(s, descr_len); s += 4;
|
||||
if (description) {
|
||||
memcpy(s, description, descr_len);
|
||||
s += descr_len;
|
||||
}
|
||||
|
||||
libssh2_htonu32(s, lang_len); s += 4;
|
||||
if (lang) {
|
||||
memcpy(s, lang, lang_len);
|
||||
s += lang_len;
|
||||
}
|
||||
|
||||
session->disconnect_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
*(s++) = SSH_MSG_DISCONNECT;
|
||||
libssh2_htonu32(s, reason); s += 4;
|
||||
|
||||
libssh2_htonu32(s, descr_len); s += 4;
|
||||
if (description) {
|
||||
memcpy(s, description, descr_len);
|
||||
s += descr_len;
|
||||
rc = libssh2_packet_write(session, session->disconnect_data, session->disconnect_data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
|
||||
libssh2_htonu32(s, lang_len); s += 4;
|
||||
if (lang) {
|
||||
memcpy(s, lang, lang_len);
|
||||
s += lang_len;
|
||||
}
|
||||
|
||||
libssh2_packet_write(session, data, data_len);
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, session->disconnect_data);
|
||||
session->disconnect_state = libssh2_NB_state_idle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -560,38 +787,48 @@ LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int me
|
||||
switch(method_type) {
|
||||
case LIBSSH2_METHOD_KEX:
|
||||
method = session->kex;
|
||||
break;
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_HOSTKEY:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->hostkey;
|
||||
break;
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_CRYPT_CS:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->local.crypt;
|
||||
break;
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_CRYPT_SC:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->remote.crypt;
|
||||
break;
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_MAC_CS:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->local.mac;
|
||||
break;
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_MAC_SC:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->remote.mac;
|
||||
break;
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_COMP_CS:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->local.comp;
|
||||
break;
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_COMP_SC:
|
||||
method = (LIBSSH2_KEX_METHOD*)session->remote.comp;
|
||||
break;
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_LANG_CS:
|
||||
return "";
|
||||
break;
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_LANG_SC:
|
||||
return "";
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid parameter specified for method_type", 0);
|
||||
return NULL;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!method) {
|
||||
@ -618,8 +855,7 @@ LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session)
|
||||
* Otherwise it is assumed to be owned by libssh2
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg,
|
||||
int *errmsg_len, int want_buf)
|
||||
libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf)
|
||||
{
|
||||
/* No error to report */
|
||||
if (!session->err_code) {
|
||||
@ -670,6 +906,16 @@ libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg,
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_session_last_error
|
||||
* Returns error code
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_session_last_errno(LIBSSH2_SESSION *session)
|
||||
{
|
||||
return session->err_code;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_session_flag
|
||||
* Set/Get session flags
|
||||
* Passing flag==0 will avoid changing session->flags while still returning its current value
|
||||
@ -686,6 +932,45 @@ LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int val
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ _libssh2_session_set_blocking
|
||||
* Set a session's blocking mode on or off, return the previous status
|
||||
* when this function is called.
|
||||
*/
|
||||
int _libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking)
|
||||
{
|
||||
int bl = session->socket_block;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Setting blocking mode on session %d", blocking);
|
||||
if (blocking == session->socket_block) {
|
||||
/* avoid if already correct */
|
||||
return bl;
|
||||
}
|
||||
session->socket_block = blocking;
|
||||
|
||||
_libssh2_nonblock(session->socket_fd, !blocking);
|
||||
|
||||
return bl;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_session_set_blocking
|
||||
* Set a channel's blocking mode on or off, similar to a socket's
|
||||
* fcntl(fd, F_SETFL, O_NONBLOCK); type command
|
||||
*/
|
||||
LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking)
|
||||
{
|
||||
(void)_libssh2_session_set_blocking(session, blocking);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_session_get_blocking
|
||||
* Returns a session's blocking mode on or off
|
||||
*/
|
||||
LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION *session)
|
||||
{
|
||||
return session->socket_block;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll_channel_read
|
||||
* Returns 0 if no data is waiting on channel,
|
||||
* non-0 if data is available
|
||||
@ -696,8 +981,10 @@ LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended
|
||||
LIBSSH2_PACKET *packet = session->packets.head;
|
||||
|
||||
while (packet) {
|
||||
if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) && (extended == 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
|
||||
((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (extended != 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
|
||||
if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) && (extended == 0) &&
|
||||
(channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
|
||||
((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (extended != 0) &&
|
||||
(channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
|
||||
/* Found data waiting to be read */
|
||||
return 1;
|
||||
}
|
||||
@ -731,8 +1018,7 @@ static inline int libssh2_poll_listener_queued(LIBSSH2_LISTENER *listener)
|
||||
/* {{{ libssh2_poll
|
||||
* Poll sockets, channels, and listeners for activity
|
||||
*/
|
||||
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
|
||||
long timeout)
|
||||
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
|
||||
{
|
||||
long timeout_remaining;
|
||||
unsigned int i, active_fds;
|
||||
@ -743,7 +1029,7 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
|
||||
function doesn't provide a session struct so we can't easily use
|
||||
the user-provided malloc replacement here... I suggest we modify
|
||||
the proto to make it possible. */
|
||||
|
||||
|
||||
/* Setup sockets for polling */
|
||||
for(i = 0; i < nfds; i++) {
|
||||
fds[i].revents = 0;
|
||||
@ -753,20 +1039,24 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
|
||||
sockets[i].events = fds[i].events;
|
||||
sockets[i].revents = 0;
|
||||
break;
|
||||
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
sockets[i].fd = fds[i].fd.channel->session->socket_fd;
|
||||
sockets[i].events = POLLIN;
|
||||
sockets[i].revents = 0;
|
||||
if (!session) session = fds[i].fd.channel->session;
|
||||
break;
|
||||
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
sockets[i].fd = fds[i].fd.listener->session->socket_fd;
|
||||
sockets[i].events = POLLIN;
|
||||
sockets[i].revents = 0;
|
||||
if (!session) session = fds[i].fd.listener->session;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
|
||||
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
|
||||
"Invalid descriptor passed to libssh2_poll()", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -791,18 +1081,22 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
|
||||
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
|
||||
}
|
||||
break;
|
||||
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
|
||||
if (fds[i].fd.channel->session->socket_fd > maxfd) maxfd = fds[i].fd.channel->session->socket_fd;
|
||||
if (!session) session = fds[i].fd.channel->session;
|
||||
break;
|
||||
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
|
||||
if (fds[i].fd.listener->session->socket_fd > maxfd) maxfd = fds[i].fd.listener->session->socket_fd;
|
||||
if (!session) session = fds[i].fd.listener->session;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
|
||||
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
|
||||
"Invalid descriptor passed to libssh2_poll()", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -845,6 +1139,7 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
|
||||
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
break;
|
||||
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want a connection */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* No connections known of yet */
|
||||
@ -955,12 +1250,14 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
|
||||
active_fds++;
|
||||
}
|
||||
break;
|
||||
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.channel->session) > 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if (FD_ISSET(fds[i].fd.listener->session->socket_fd, &rfds)) {
|
||||
/* Spin session until no data available */
|
||||
|
413
src/sftp.c
413
src/sftp.c
@ -74,73 +74,6 @@
|
||||
#define SSH_FXP_EXTENDED 200
|
||||
#define SSH_FXP_EXTENDED_REPLY 201
|
||||
|
||||
typedef enum {
|
||||
sftp_read_idle = 0,
|
||||
sftp_read_packet_allocated,
|
||||
sftp_read_packet_created,
|
||||
sftp_read_packet_sent
|
||||
} libssh2_sftp_read_state;
|
||||
|
||||
typedef enum {
|
||||
sftp_readdir_idle = 0,
|
||||
sftp_readdir_packet_created,
|
||||
sftp_readdir_packet_sent
|
||||
} libssh2_sftp_readdir_state;
|
||||
|
||||
typedef enum {
|
||||
sftp_write_idle = 0,
|
||||
sftp_write_packet_created,
|
||||
sftp_write_packet_sent
|
||||
} libssh2_sftp_write_state;
|
||||
|
||||
typedef enum {
|
||||
sftp_mkdir_idle = 0,
|
||||
sftp_mkdir_packet_created,
|
||||
sftp_mkdir_packet_sent
|
||||
} libssh2_sftp_mkdir_state;
|
||||
|
||||
struct _LIBSSH2_SFTP {
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
|
||||
unsigned long request_id, version;
|
||||
|
||||
LIBSSH2_PACKET_BRIGADE packets;
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *handles;
|
||||
|
||||
unsigned long last_errno;
|
||||
|
||||
/* Holder for partial packet, use in libssh2_sftp_packet_read() */
|
||||
unsigned char *partial_packet; /* The data */
|
||||
unsigned long partial_len; /* Desired number of bytes */
|
||||
unsigned long partial_received; /* Bytes received so far */
|
||||
|
||||
/* Time that libssh2_sftp_packet_requirev() started reading */
|
||||
time_t requirev_start;
|
||||
|
||||
/* State variables used in _libssh2_sftp_read() */
|
||||
libssh2_sftp_read_state read_state;
|
||||
unsigned char *read_packet;
|
||||
unsigned long read_request_id;
|
||||
size_t read_total_read;
|
||||
|
||||
/* State variables used in _libssh2_sftp_readdir() */
|
||||
libssh2_sftp_readdir_state readdir_state;
|
||||
unsigned char *readdir_packet;
|
||||
unsigned long readdir_request_id;
|
||||
|
||||
/* State variables used in _libssh2_sftp_write() */
|
||||
libssh2_sftp_write_state write_state;
|
||||
unsigned char *write_packet;
|
||||
unsigned long write_request_id;
|
||||
|
||||
/* State variables used in _libssh2_sftp_mkdir() */
|
||||
libssh2_sftp_mkdir_state mkdir_state;
|
||||
unsigned char *mkdir_packet;
|
||||
unsigned long mkdir_request_id;
|
||||
|
||||
};
|
||||
|
||||
#define LIBSSH2_SFTP_HANDLE_FILE 0
|
||||
#define LIBSSH2_SFTP_HANDLE_DIR 1
|
||||
|
||||
@ -149,31 +82,9 @@ struct _LIBSSH2_SFTP {
|
||||
/* S_IFDIR */
|
||||
#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000
|
||||
|
||||
struct _LIBSSH2_SFTP_HANDLE {
|
||||
LIBSSH2_SFTP *sftp;
|
||||
LIBSSH2_SFTP_HANDLE *prev, *next;
|
||||
|
||||
char *handle;
|
||||
int handle_len;
|
||||
|
||||
char handle_type;
|
||||
|
||||
union _libssh2_sftp_handle_data {
|
||||
struct _libssh2_sftp_handle_file_data {
|
||||
libssh2_uint64_t offset;
|
||||
} file;
|
||||
struct _libssh2_sftp_handle_dir_data {
|
||||
unsigned long names_left;
|
||||
void *names_packet;
|
||||
char *next_name;
|
||||
} dir;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* {{{ libssh2_sftp_packet_add
|
||||
* Add a packet to the SFTP packet brigade
|
||||
*/
|
||||
/* libssh2_sftp_packet_add - NB-SAFE */
|
||||
static int libssh2_sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, unsigned long data_len)
|
||||
{
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
@ -232,7 +143,7 @@ static int libssh2_sftp_packet_read(LIBSSH2_SFTP *sftp, int should_block, int fl
|
||||
packet_received = sftp->partial_received;
|
||||
sftp->partial_packet = NULL;
|
||||
} else {
|
||||
rc = _libssh2_channel_read(channel, (char *)buffer, 4);
|
||||
rc = libssh2_channel_read_ex(channel, 0, (char *)buffer, 4);
|
||||
if (flush && (rc < 0)) {
|
||||
/* When flushing, exit quickly */
|
||||
return -1;
|
||||
@ -265,7 +176,7 @@ static int libssh2_sftp_packet_read(LIBSSH2_SFTP *sftp, int should_block, int fl
|
||||
|
||||
/* Read as much of the packet as we can */
|
||||
while (packet_len > packet_received) {
|
||||
long bytes_received = _libssh2_channel_read(channel, (char *)packet + packet_received, packet_len - packet_received);
|
||||
long bytes_received = libssh2_channel_read_ex(channel, 0, (char *)packet + packet_received, packet_len - packet_received);
|
||||
|
||||
if (flush && (rc < 0)) {
|
||||
/* When flushing, exit quickly */
|
||||
@ -374,7 +285,7 @@ static int libssh2_sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_
|
||||
return 0;
|
||||
}
|
||||
|
||||
bl = libssh2_channel_get_blocking(sftp->channel);
|
||||
bl = libssh2_session_get_blocking(session);
|
||||
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
int ret = libssh2_sftp_packet_read(sftp, bl, 0);
|
||||
if (!bl && (ret == PACKET_EAGAIN)) {
|
||||
@ -415,12 +326,12 @@ static int libssh2_sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_respon
|
||||
sftp->requirev_start = time(NULL);
|
||||
|
||||
/* Flush */
|
||||
bl = libssh2_channel_get_blocking(sftp->channel);
|
||||
bl = libssh2_session_get_blocking(sftp->channel->session);
|
||||
while (libssh2_sftp_packet_read(sftp, 0, 1) > 0);
|
||||
libssh2_channel_set_blocking(sftp->channel, bl);
|
||||
}
|
||||
|
||||
bl = libssh2_channel_get_blocking(sftp->channel);
|
||||
bl = libssh2_session_get_blocking(sftp->channel->session) ;
|
||||
while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
int ret;
|
||||
|
||||
@ -436,6 +347,7 @@ static int libssh2_sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_respon
|
||||
}
|
||||
}
|
||||
|
||||
#warning "XXX - The timeout is ignored if PACKET_EAGAIN is returned"
|
||||
ret = libssh2_sftp_packet_read(sftp, bl, 0);
|
||||
if (!bl && (ret == PACKET_EAGAIN)) {
|
||||
return PACKET_EAGAIN;
|
||||
@ -597,108 +509,161 @@ LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor)
|
||||
/* {{{ libssh2_sftp_init
|
||||
* Startup an SFTP session
|
||||
*/
|
||||
/* libssh2_sftp_init - NB-UNSAFE */
|
||||
LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
|
||||
{
|
||||
LIBSSH2_SFTP *sftp;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
unsigned char *data, *s, buffer[9]; /* sftp_header(5){excludes request_id} + version_id(4) */
|
||||
unsigned char *data, *s;
|
||||
unsigned long data_len;
|
||||
int bl;
|
||||
int rc;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Initializing SFTP subsystem");
|
||||
channel = libssh2_channel_open_session(session);
|
||||
if (!channel) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
|
||||
return NULL;
|
||||
if (session->sftpInit_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Initializing SFTP subsystem");
|
||||
|
||||
session->sftpInit_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (libssh2_channel_subsystem(channel, "sftp")) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request SFTP subsystem", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
if (session->sftpInit_state == libssh2_NB_state_created) {
|
||||
session->sftpInit_channel = libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
|
||||
LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT,
|
||||
NULL, 0);
|
||||
if (!session->sftpInit_channel) {
|
||||
if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block starting up channel", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
|
||||
session->sftpInit_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
session->sftpInit_state = libssh2_NB_state_sent;
|
||||
}
|
||||
|
||||
bl = libssh2_channel_get_blocking(channel);
|
||||
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
|
||||
libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
|
||||
|
||||
sftp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP));
|
||||
if (!sftp) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new SFTP structure", 0);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
if (session->sftpInit_state == libssh2_NB_state_sent) {
|
||||
rc = libssh2_channel_process_startup(session->sftpInit_channel, "subsystem", sizeof("subsystem") - 1,
|
||||
"sftp", strlen("sftp"));
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block to request SFTP subsystem", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request SFTP subsystem", 0);
|
||||
libssh2_channel_free(session->sftpInit_channel);
|
||||
session->sftpInit_channel = NULL;
|
||||
session->sftpInit_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session->sftpInit_state = libssh2_NB_state_sent1;
|
||||
}
|
||||
memset(sftp, 0, sizeof(LIBSSH2_SFTP));
|
||||
sftp->channel = channel;
|
||||
sftp->request_id = 0;
|
||||
|
||||
libssh2_htonu32(buffer, 5);
|
||||
buffer[4] = SSH_FXP_INIT;
|
||||
libssh2_htonu32(buffer + 5, LIBSSH2_SFTP_VERSION);
|
||||
if (session->sftpInit_state == libssh2_NB_state_sent1) {
|
||||
rc = libssh2_channel_handle_extended_data2(session->sftpInit_channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block requesting handle extended data", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session->sftpInit_sftp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP));
|
||||
if (!session->sftpInit_sftp) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new SFTP structure", 0);
|
||||
libssh2_channel_free(session->sftpInit_channel);
|
||||
session->sftpInit_channel = NULL;
|
||||
session->sftpInit_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
memset(session->sftpInit_sftp, 0, sizeof(LIBSSH2_SFTP));
|
||||
session->sftpInit_sftp->channel = session->sftpInit_channel;
|
||||
session->sftpInit_sftp->request_id = 0;
|
||||
|
||||
libssh2_htonu32(session->sftpInit_buffer, 5);
|
||||
session->sftpInit_buffer[4] = SSH_FXP_INIT;
|
||||
libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending FXP_INIT packet advertising version %d support",
|
||||
(int)LIBSSH2_SFTP_VERSION);
|
||||
|
||||
session->sftpInit_state = libssh2_NB_state_sent2;
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending FXP_INIT packet advertising version %d support", (int)LIBSSH2_SFTP_VERSION);
|
||||
if (9 != libssh2_channel_write(channel, (char *)buffer, 9)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send SSH_FXP_INIT", 0);
|
||||
libssh2_channel_free(channel);
|
||||
LIBSSH2_FREE(session, sftp);
|
||||
return NULL;
|
||||
if (session->sftpInit_state == libssh2_NB_state_sent2) {
|
||||
rc = libssh2_channel_write_ex(session->sftpInit_channel, 0, (char *)session->sftpInit_buffer, 9);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending SSH_FXP_INIT", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (9 != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send SSH_FXP_INIT", 0);
|
||||
libssh2_channel_free(session->sftpInit_channel);
|
||||
session->sftpInit_channel = NULL;
|
||||
LIBSSH2_FREE(session, session->sftpInit_sftp);
|
||||
session->sftpInit_sftp = NULL;
|
||||
session->sftpInit_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session->sftpInit_state = libssh2_NB_state_sent3;
|
||||
}
|
||||
|
||||
/* For initiallization we are requiring blocking, probably reasonable */
|
||||
if (libssh2_sftp_packet_require(sftp, SSH_FXP_VERSION, 0, &data, &data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
|
||||
"Timeout waiting for response from SFTP subsystem", 0);
|
||||
libssh2_channel_free(channel);
|
||||
LIBSSH2_FREE(session, sftp);
|
||||
rc = libssh2_sftp_packet_require(session->sftpInit_sftp, SSH_FXP_VERSION, 0, &data, &data_len);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response from SFTP subsystem", 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from SFTP subsystem", 0);
|
||||
libssh2_channel_free(session->sftpInit_channel);
|
||||
session->sftpInit_channel = NULL;
|
||||
LIBSSH2_FREE(session, session->sftpInit_sftp);
|
||||
session->sftpInit_sftp = NULL;
|
||||
session->sftpInit_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
if (data_len < 5) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Invalid SSH_FXP_VERSION response", 0);
|
||||
libssh2_channel_free(channel);
|
||||
LIBSSH2_FREE(session, sftp);
|
||||
libssh2_channel_free(session->sftpInit_channel);
|
||||
session->sftpInit_channel = NULL;
|
||||
LIBSSH2_FREE(session, session->sftpInit_sftp);
|
||||
session->sftpInit_sftp = NULL;
|
||||
session->sftpInit_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = data + 1;
|
||||
sftp->version = libssh2_ntohu32(s); s += 4;
|
||||
if (sftp->version > LIBSSH2_SFTP_VERSION) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Truncating remote SFTP version from %lu", sftp->version);
|
||||
sftp->version = LIBSSH2_SFTP_VERSION;
|
||||
session->sftpInit_sftp->version = libssh2_ntohu32(s); s += 4;
|
||||
if (session->sftpInit_sftp->version > LIBSSH2_SFTP_VERSION) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Truncating remote SFTP version from %lu", session->sftpInit_sftp->version);
|
||||
session->sftpInit_sftp->version = LIBSSH2_SFTP_VERSION;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Enabling SFTP version %lu compatability", sftp->version);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Enabling SFTP version %lu compatability", session->sftpInit_sftp->version);
|
||||
while (s < (data + data_len)) {
|
||||
unsigned char *extension_name, *extension_data;
|
||||
unsigned long extname_len, extdata_len;
|
||||
|
||||
extname_len = libssh2_ntohu32(s); s += 4;
|
||||
extension_name = s; s += extname_len;
|
||||
extension_name = s; s += extname_len;
|
||||
|
||||
extdata_len = libssh2_ntohu32(s); s += 4;
|
||||
extension_data = s; s += extdata_len;
|
||||
extension_data = s; s += extdata_len;
|
||||
|
||||
/* TODO: Actually process extensions */
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
/* Make sure that when the channel gets closed, the SFTP service is shut down too */
|
||||
sftp->channel->abstract = sftp;
|
||||
sftp->channel->close_cb = libssh2_sftp_dtor;
|
||||
session->sftpInit_sftp->channel->abstract = session->sftpInit_sftp;
|
||||
session->sftpInit_sftp->channel->close_cb = libssh2_sftp_dtor;
|
||||
|
||||
/* Restore the blocking state of the channel */
|
||||
libssh2_channel_set_blocking(channel, bl);
|
||||
|
||||
return sftp;
|
||||
session->sftpInit_state = libssh2_NB_state_idle;
|
||||
return session->sftpInit_sftp;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_sftp_shutdown
|
||||
* Shutsdown the SFTP subsystem
|
||||
*/
|
||||
/* libssh2_sftp_shutdown - NB-SAFE */
|
||||
LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp)
|
||||
{
|
||||
return libssh2_channel_free(sftp->channel);
|
||||
@ -749,18 +714,15 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request", (open_type == LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
|
||||
if (packet_len != _libssh2_channel_write(channel, (char *)packet,
|
||||
packet_len)) {
|
||||
while ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return NULL;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
/* #warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up farther" */
|
||||
while ((rc = libssh2_sftp_packet_requirev(sftp, 2, fopen_responses, request_id, &data, &data_len)) == PACKET_EAGAIN) {
|
||||
;
|
||||
}
|
||||
while ((rc = libssh2_sftp_packet_requirev(sftp, 2, fopen_responses, request_id, &data, &data_len)) == PACKET_EAGAIN);
|
||||
if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
|
||||
return NULL;
|
||||
@ -885,8 +847,9 @@ static ssize_t _libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
}
|
||||
|
||||
if (sftp->read_state != sftp_read_packet_sent) {
|
||||
if (libssh2_channel_get_blocking(channel)) {
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
|
||||
if (libssh2_session_get_blocking(channel->session)) {
|
||||
while ((retcode = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != retcode) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
sftp->read_packet = NULL;
|
||||
@ -894,7 +857,7 @@ static ssize_t _libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if ((retcode = libssh2_channel_writenb(channel, (char *)packet, packet_len)) == PACKET_EAGAIN) {
|
||||
if ((retcode = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN) {
|
||||
sftp->read_packet = packet;
|
||||
sftp->read_request_id = request_id;
|
||||
sftp->read_total_read = total_read;
|
||||
@ -979,7 +942,7 @@ LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle,
|
||||
{
|
||||
ssize_t rc;
|
||||
LIBSSH2_CHANNEL *ch = handle->sftp->channel;
|
||||
int bl = libssh2_channel_get_blocking(ch);
|
||||
int bl = libssh2_session_get_blocking(ch->session);
|
||||
|
||||
/* set blocking */
|
||||
libssh2_channel_set_blocking(ch, 1);
|
||||
@ -989,7 +952,7 @@ LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle,
|
||||
/* restore state */
|
||||
libssh2_channel_set_blocking(ch, bl);
|
||||
|
||||
if(rc < 0) {
|
||||
if (rc < 0) {
|
||||
/* precent accidental returning of other return codes since
|
||||
this API does not support/provide those */
|
||||
return -1;
|
||||
@ -1008,7 +971,7 @@ LIBSSH2_API ssize_t libssh2_sftp_readnb(LIBSSH2_SFTP_HANDLE *handle,
|
||||
{
|
||||
ssize_t rc;
|
||||
LIBSSH2_CHANNEL *ch = handle->sftp->channel;
|
||||
int bl = libssh2_channel_get_blocking(ch);
|
||||
int bl = libssh2_session_get_blocking(ch->session);
|
||||
|
||||
/* set non-blocking */
|
||||
libssh2_channel_set_blocking(ch, 0);
|
||||
@ -1110,15 +1073,16 @@ static int _libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size
|
||||
|
||||
if (sftp->readdir_state != sftp_readdir_packet_sent) {
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading entries from directory handle");
|
||||
if (libssh2_channel_get_blocking(channel)) {
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
|
||||
if (libssh2_session_get_blocking(channel->session)) {
|
||||
while ((retcode = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != retcode) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
sftp->readdir_state = sftp_readdir_idle;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if ((retcode = libssh2_channel_writenb(channel, (char *)packet, packet_len)) == PACKET_EAGAIN) {
|
||||
if ((retcode = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN) {
|
||||
sftp->readdir_packet = packet;
|
||||
sftp->readdir_request_id = request_id;
|
||||
return PACKET_EAGAIN;
|
||||
@ -1213,7 +1177,7 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
{
|
||||
int rc;
|
||||
LIBSSH2_CHANNEL *ch = handle->sftp->channel;
|
||||
int bl = libssh2_channel_get_blocking(ch);
|
||||
int bl = libssh2_session_get_blocking(ch->session);
|
||||
|
||||
/* set blocking */
|
||||
libssh2_channel_set_blocking(ch, 1);
|
||||
@ -1223,7 +1187,7 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
/* restore state */
|
||||
libssh2_channel_set_blocking(ch, bl);
|
||||
|
||||
if(rc < 0) {
|
||||
if (rc < 0) {
|
||||
/* precent accidental returning of other return codes since
|
||||
this API does not support/provide those */
|
||||
return -1;
|
||||
@ -1242,7 +1206,7 @@ LIBSSH2_API int libssh2_sftp_readdirnb(LIBSSH2_SFTP_HANDLE *handle, char *buffer
|
||||
{
|
||||
int rc;
|
||||
LIBSSH2_CHANNEL *ch = handle->sftp->channel;
|
||||
int bl = libssh2_channel_get_blocking(ch);
|
||||
int bl = libssh2_session_get_blocking(ch->session);
|
||||
|
||||
/* set non-blocking */
|
||||
libssh2_channel_set_blocking(ch, 0);
|
||||
@ -1296,15 +1260,16 @@ static ssize_t _libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buff
|
||||
}
|
||||
|
||||
if (sftp->write_state != sftp_write_packet_sent) {
|
||||
if (libssh2_channel_get_blocking(channel)) {
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
|
||||
if (libssh2_session_get_blocking(channel->session)) {
|
||||
while ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
sftp->write_state = sftp_write_idle;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if ((rc = libssh2_channel_writenb(channel, (char *)packet, packet_len)) == PACKET_EAGAIN) {
|
||||
if ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN) {
|
||||
sftp->write_packet = packet;
|
||||
sftp->write_request_id = request_id;
|
||||
return PACKET_EAGAIN;
|
||||
@ -1356,7 +1321,7 @@ LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
|
||||
{
|
||||
ssize_t rc;
|
||||
LIBSSH2_CHANNEL *ch = handle->sftp->channel;
|
||||
int bl = libssh2_channel_get_blocking(ch);
|
||||
int bl = libssh2_session_get_blocking(ch->session);
|
||||
|
||||
/* set blocking */
|
||||
libssh2_channel_set_blocking(ch, 1);
|
||||
@ -1366,7 +1331,7 @@ LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
|
||||
/* restore state */
|
||||
libssh2_channel_set_blocking(ch, bl);
|
||||
|
||||
if(rc < 0) {
|
||||
if (rc < 0) {
|
||||
/* precent accidental returning of other return codes since
|
||||
this API does not support/provide those */
|
||||
return -1;
|
||||
@ -1385,7 +1350,7 @@ LIBSSH2_API ssize_t libssh2_sftp_writenb(LIBSSH2_SFTP_HANDLE *handle,
|
||||
{
|
||||
ssize_t rc;
|
||||
LIBSSH2_CHANNEL *ch = handle->sftp->channel;
|
||||
int bl = libssh2_channel_get_blocking(ch);
|
||||
int bl = libssh2_session_get_blocking(ch->session);
|
||||
|
||||
/* set non-blocking */
|
||||
libssh2_channel_set_blocking(ch, 0);
|
||||
@ -1432,17 +1397,15 @@ LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_
|
||||
s += libssh2_sftp_attr2bin(s, attrs);
|
||||
}
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
|
||||
while ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, setstat ? (char *)"Unable to send FXP_FSETSTAT" : (char *)"Unable to send FXP_FSTAT command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
/* #warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up farther" */
|
||||
while ((rc = libssh2_sftp_packet_requirev(sftp, 2, fstat_responses, request_id, &data, &data_len)) == PACKET_EAGAIN) {
|
||||
;
|
||||
}
|
||||
while ((rc = libssh2_sftp_packet_requirev(sftp, 2, fstat_responses, request_id, &data, &data_len)) == PACKET_EAGAIN);
|
||||
if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
|
||||
return -1;
|
||||
@ -1518,17 +1481,15 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
libssh2_htonu32(s, handle->handle_len); s += 4;
|
||||
memcpy(s, handle->handle, handle->handle_len); s += handle->handle_len;
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
|
||||
while ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_CLOSE command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
/* #warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up farther" */
|
||||
while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) == PACKET_EAGAIN) {
|
||||
;
|
||||
}
|
||||
while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) == PACKET_EAGAIN);
|
||||
if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
|
||||
return -1;
|
||||
@ -1593,18 +1554,15 @@ LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
libssh2_htonu32(s, filename_len); s += 4;
|
||||
memcpy(s, filename, filename_len); s += filename_len;
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet,
|
||||
packet_len)) {
|
||||
while ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
/* #warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up farther" */
|
||||
while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) == PACKET_EAGAIN) {
|
||||
;
|
||||
}
|
||||
while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) == PACKET_EAGAIN);
|
||||
if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
|
||||
return -1;
|
||||
@ -1665,18 +1623,15 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_f
|
||||
libssh2_htonu32(s, flags); s += 4;
|
||||
}
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet,
|
||||
s - packet)) {
|
||||
while ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, s - packet)) == PACKET_EAGAIN);
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_RENAME command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
/* #warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up farther" */
|
||||
while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) == PACKET_EAGAIN) {
|
||||
;
|
||||
}
|
||||
while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) == PACKET_EAGAIN);
|
||||
if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
|
||||
return -1;
|
||||
@ -1751,15 +1706,16 @@ static int _libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned
|
||||
}
|
||||
|
||||
if (sftp->mkdir_state != sftp_mkdir_packet_sent) {
|
||||
if (libssh2_channel_get_blocking(channel)) {
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
|
||||
if (libssh2_session_get_blocking(channel->session)) {
|
||||
while ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
sftp->mkdir_state = sftp_mkdir_idle;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if ((rc = libssh2_channel_writenb(channel, (char *)packet, packet_len)) == PACKET_EAGAIN) {
|
||||
if ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN) {
|
||||
sftp->mkdir_packet = packet;
|
||||
sftp->mkdir_request_id = request_id;
|
||||
return PACKET_EAGAIN;
|
||||
@ -1809,7 +1765,7 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsi
|
||||
{
|
||||
ssize_t rc;
|
||||
LIBSSH2_CHANNEL *ch = sftp->channel;
|
||||
int bl = libssh2_channel_get_blocking(ch);
|
||||
int bl = libssh2_session_get_blocking(ch->session);
|
||||
|
||||
/* set blocking */
|
||||
libssh2_channel_set_blocking(ch, 1);
|
||||
@ -1819,7 +1775,7 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsi
|
||||
/* restore state */
|
||||
libssh2_channel_set_blocking(ch, bl);
|
||||
|
||||
if(rc < 0) {
|
||||
if (rc < 0) {
|
||||
/* precent accidental returning of other return codes since
|
||||
this API does not support/provide those */
|
||||
return -1;
|
||||
@ -1837,7 +1793,7 @@ LIBSSH2_API int libssh2_sftp_mkdirnb_ex(LIBSSH2_SFTP *sftp, const char *path, un
|
||||
{
|
||||
ssize_t rc;
|
||||
LIBSSH2_CHANNEL *ch = sftp->channel;
|
||||
int bl = libssh2_channel_get_blocking(ch);
|
||||
int bl = libssh2_session_get_blocking(ch->session);
|
||||
|
||||
/* set non-blocking */
|
||||
libssh2_channel_set_blocking(ch, 0);
|
||||
@ -1878,17 +1834,15 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsi
|
||||
libssh2_htonu32(s, path_len); s += 4;
|
||||
memcpy(s, path, path_len); s += path_len;
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
|
||||
while ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
/* #warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up farther" */
|
||||
while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) == PACKET_EAGAIN) {
|
||||
;
|
||||
}
|
||||
while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) == PACKET_EAGAIN);
|
||||
if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
|
||||
return -1;
|
||||
@ -1949,18 +1903,15 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path, unsig
|
||||
s += libssh2_sftp_attr2bin(s, attrs);
|
||||
}
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet,
|
||||
packet_len)) {
|
||||
while ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send STAT/LSTAT/SETSTAT command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
/* #warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up farther" */
|
||||
while ((rc = libssh2_sftp_packet_requirev(sftp, 2, stat_responses, request_id, &data, &data_len)) == PACKET_EAGAIN) {
|
||||
;
|
||||
}
|
||||
while ((rc = libssh2_sftp_packet_requirev(sftp, 2, stat_responses, request_id, &data, &data_len)) == PACKET_EAGAIN);
|
||||
if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
|
||||
return -1;
|
||||
@ -2038,18 +1989,15 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, un
|
||||
memcpy(s, target, target_len); s += target_len;
|
||||
}
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, (char *)packet,
|
||||
packet_len)) {
|
||||
while ((rc = libssh2_channel_write_ex(channel, 0, (char *)packet, packet_len)) == PACKET_EAGAIN);
|
||||
if (packet_len != rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send SYMLINK/READLINK command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
/* #warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up farther" */
|
||||
while ((rc = libssh2_sftp_packet_requirev(sftp, 2, link_responses, request_id, &data, &data_len)) == PACKET_EAGAIN) {
|
||||
;
|
||||
}
|
||||
while ((rc = libssh2_sftp_packet_requirev(sftp, 2, link_responses, request_id, &data, &data_len)) == PACKET_EAGAIN);
|
||||
if (rc) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
|
||||
return -1;
|
||||
@ -2096,24 +2044,3 @@ LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp)
|
||||
return sftp->last_errno;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_sftp_set_blocking
|
||||
* Set a channel's blocking mode on or off, this is an accessor
|
||||
* to the channel through the SFTP session handle
|
||||
*/
|
||||
/* libssh2_sftp_set_blocking - NB-SAFE */
|
||||
LIBSSH2_API void libssh2_sftp_set_blocking(LIBSSH2_SFTP *session, int blocking) {
|
||||
libssh2_channel_set_blocking(session->channel, blocking);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_sftp_get_blocking
|
||||
* Returns a channel's blocking mode on or off, this is an accessor
|
||||
* to the channel through the SFTP session handle
|
||||
*/
|
||||
/* libssh2_sftp_get_blocking - NB-SAFE */
|
||||
LIBSSH2_API int libssh2_sftp_get_blocking(LIBSSH2_SFTP *session) {
|
||||
return libssh2_channel_get_blocking(session->channel);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
406
src/transport.c
406
src/transport.c
@ -57,7 +57,7 @@ static void debugdump(LIBSSH2_SESSION *session,
|
||||
FILE *stream = stdout;
|
||||
unsigned int width=0x10;
|
||||
|
||||
if(!(session->showmask & (1<< LIBSSH2_DBG_TRANS))) {
|
||||
if (!(session->showmask & (1<< LIBSSH2_DBG_TRANS))) {
|
||||
/* not asked for, bail out */
|
||||
return;
|
||||
}
|
||||
@ -66,11 +66,11 @@ static void debugdump(LIBSSH2_SESSION *session,
|
||||
|
||||
for(i=0; i<size; i+= width) {
|
||||
|
||||
fprintf(stream, "%04x: ", i);
|
||||
fprintf(stream, "%04lx: ", i);
|
||||
|
||||
/* hex not disabled, show it */
|
||||
for(c = 0; c < width; c++) {
|
||||
if(i+c < size)
|
||||
if (i+c < size)
|
||||
fprintf(stream, "%02x ", ptr[i+c]);
|
||||
else
|
||||
fputs(" ", stream);
|
||||
@ -115,8 +115,8 @@ static libssh2pack_t decrypt(LIBSSH2_SESSION *session, unsigned char *source,
|
||||
}
|
||||
|
||||
/* if the crypt() function would write to a given address it
|
||||
wouldn't have to memcpy() and we could avoid this memcpy()
|
||||
too */
|
||||
wouldn't have to memcpy() and we could avoid this memcpy()
|
||||
too */
|
||||
memcpy(dest, source, blocksize);
|
||||
|
||||
len -= blocksize; /* less bytes left */
|
||||
@ -130,100 +130,115 @@ static libssh2pack_t decrypt(LIBSSH2_SESSION *session, unsigned char *source,
|
||||
* fullpacket() gets called when a full packet has been received and properly
|
||||
* collected.
|
||||
*/
|
||||
static libssh2pack_t fullpacket(LIBSSH2_SESSION *session,
|
||||
int encrypted /* 1 or 0 */)
|
||||
static libssh2pack_t
|
||||
fullpacket(LIBSSH2_SESSION *session, int encrypted /* 1 or 0 */)
|
||||
{
|
||||
unsigned char macbuf[MAX_MACSIZE];
|
||||
struct transportpacket *p = &session->packet;
|
||||
int payload_len = p->packet_length-1;
|
||||
libssh2pack_t packet_type;
|
||||
int macstate = LIBSSH2_MAC_CONFIRMED;
|
||||
int rc;
|
||||
|
||||
if(encrypted) {
|
||||
if (session->fullpacket_state == libssh2_NB_state_idle) {
|
||||
session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED;
|
||||
session->fullpacket_payload_len = p->packet_length-1;
|
||||
|
||||
/* Calculate MAC hash */
|
||||
session->remote.mac->hash(session,
|
||||
macbuf, /* store hash here */
|
||||
session->remote.seqno,
|
||||
p->init, 5,
|
||||
p->payload, payload_len,
|
||||
&session->remote.mac_abstract);
|
||||
|
||||
/* Compare the calculated hash with the MAC we just read from
|
||||
* the network. The read one is at the very end of the payload
|
||||
* buffer. Note that 'payload_len' here is the packet_length
|
||||
* field which includes the padding but not the MAC.
|
||||
*/
|
||||
if(memcmp(macbuf, p->payload + payload_len,
|
||||
session->remote.mac->mac_len)) {
|
||||
macstate = LIBSSH2_MAC_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
session->remote.seqno++;
|
||||
|
||||
/* ignore the padding */
|
||||
payload_len -= p->padding_length;
|
||||
|
||||
/* Check for and deal with decompression */
|
||||
if (session->remote.comp &&
|
||||
strcmp(session->remote.comp->name, "none")) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
int free_payload = 1;
|
||||
|
||||
if (session->remote.comp->comp(session, 0,
|
||||
&data, &data_len,
|
||||
LIBSSH2_PACKET_MAXDECOMP,
|
||||
&free_payload,
|
||||
p->payload, payload_len,
|
||||
&session->remote.comp_abstract)) {
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
return PACKET_FAIL;
|
||||
if (encrypted) {
|
||||
|
||||
/* Calculate MAC hash */
|
||||
session->remote.mac->hash(session,
|
||||
macbuf, /* store hash here */
|
||||
session->remote.seqno,
|
||||
p->init, 5,
|
||||
p->payload, session->fullpacket_payload_len,
|
||||
&session->remote.mac_abstract);
|
||||
|
||||
/* Compare the calculated hash with the MAC we just read from
|
||||
* the network. The read one is at the very end of the payload
|
||||
* buffer. Note that 'payload_len' here is the packet_length
|
||||
* field which includes the padding but not the MAC.
|
||||
*/
|
||||
if (memcmp(macbuf, p->payload + session->fullpacket_payload_len,
|
||||
session->remote.mac->mac_len)) {
|
||||
session->fullpacket_macstate = LIBSSH2_MAC_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
if (free_payload) {
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
p->payload = data;
|
||||
payload_len = data_len;
|
||||
}
|
||||
else {
|
||||
if (data == p->payload) {
|
||||
/* It's not to be freed, because the
|
||||
* compression layer reused payload, So let's
|
||||
* do the same!
|
||||
*/
|
||||
payload_len = data_len;
|
||||
session->remote.seqno++;
|
||||
|
||||
/* ignore the padding */
|
||||
session->fullpacket_payload_len -= p->padding_length;
|
||||
|
||||
/* Check for and deal with decompression */
|
||||
if (session->remote.comp &&
|
||||
strcmp(session->remote.comp->name, "none")) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
int free_payload = 1;
|
||||
|
||||
if (session->remote.comp->comp(session, 0,
|
||||
&data, &data_len,
|
||||
LIBSSH2_PACKET_MAXDECOMP,
|
||||
&free_payload,
|
||||
p->payload, session->fullpacket_payload_len,
|
||||
&session->remote.comp_abstract)) {
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
return PACKET_FAIL;
|
||||
}
|
||||
|
||||
if (free_payload) {
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
p->payload = data;
|
||||
session->fullpacket_payload_len = data_len;
|
||||
}
|
||||
else {
|
||||
/* No comp_method actually lets this happen,
|
||||
* but let's prepare for the future */
|
||||
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
|
||||
/* We need a freeable struct otherwise the
|
||||
* brigade won't know what to do with it */
|
||||
p->payload = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!p->payload) {
|
||||
libssh2_error(session,
|
||||
LIBSSH2_ERROR_ALLOC,
|
||||
(char *)"Unable to allocate memory for copy of uncompressed data", 0);
|
||||
return PACKET_ENOMEM;
|
||||
if (data == p->payload) {
|
||||
/* It's not to be freed, because the
|
||||
* compression layer reused payload, So let's
|
||||
* do the same!
|
||||
*/
|
||||
session->fullpacket_payload_len = data_len;
|
||||
}
|
||||
else {
|
||||
/* No comp_method actually lets this happen,
|
||||
* but let's prepare for the future */
|
||||
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
|
||||
/* We need a freeable struct otherwise the
|
||||
* brigade won't know what to do with it */
|
||||
p->payload = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!p->payload) {
|
||||
libssh2_error(session,
|
||||
LIBSSH2_ERROR_ALLOC,
|
||||
(char *)"Unable to allocate memory for copy of uncompressed data", 0);
|
||||
return PACKET_ENOMEM;
|
||||
}
|
||||
memcpy(p->payload, data, data_len);
|
||||
session->fullpacket_payload_len = data_len;
|
||||
}
|
||||
memcpy(p->payload, data, data_len);
|
||||
payload_len = data_len;
|
||||
}
|
||||
}
|
||||
|
||||
session->fullpacket_packet_type = p->payload[0];
|
||||
|
||||
debugdump(session, "libssh2_packet_read() plain",
|
||||
p->payload, session->fullpacket_payload_len);
|
||||
|
||||
session->fullpacket_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (session->fullpacket_state == libssh2_NB_state_created) {
|
||||
rc = libssh2_packet_add(session, p->payload, session->fullpacket_payload_len, session->fullpacket_macstate);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
else if (rc < 0) {
|
||||
return PACKET_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
packet_type = p->payload[0];
|
||||
session->fullpacket_state = libssh2_NB_state_idle;
|
||||
|
||||
debugdump(session, "libssh2_packet_read() plain",
|
||||
p->payload, payload_len);
|
||||
if (libssh2_packet_add(session, p->payload, payload_len, macstate) < 0)
|
||||
return PACKET_FAIL;
|
||||
|
||||
return packet_type;
|
||||
return session->fullpacket_packet_type;
|
||||
}
|
||||
|
||||
|
||||
@ -231,7 +246,7 @@ static libssh2pack_t fullpacket(LIBSSH2_SESSION *session,
|
||||
* Collect a packet into the input brigade
|
||||
* block only controls whether or not to wait for a packet to start,
|
||||
* Once a packet starts, libssh2 will block until it is complete
|
||||
|
||||
*
|
||||
* Returns packet type added to input brigade (PACKET_NONE if nothing added),
|
||||
* or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full
|
||||
* packet.
|
||||
@ -241,7 +256,6 @@ static libssh2pack_t fullpacket(LIBSSH2_SESSION *session,
|
||||
* This function reads the binary stream as specified in chapter 6 of RFC4253
|
||||
* "The Secure Shell (SSH) Transport Layer Protocol"
|
||||
*/
|
||||
|
||||
libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
{
|
||||
libssh2pack_t rc;
|
||||
@ -255,20 +269,28 @@ libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
int minimum;
|
||||
int encrypted = 1;
|
||||
|
||||
do {
|
||||
/*
|
||||
* =============================== NOTE ===============================
|
||||
* I know this is very ugly and not a really good use of "goto", but
|
||||
* this case statement would be even uglier to do it any other way
|
||||
*/
|
||||
if (session->readPack_state == libssh2_NB_state_jump1) {
|
||||
session->readPack_state = libssh2_NB_state_idle;
|
||||
encrypted = session->readPack_encrypted;
|
||||
goto libssh2_packet_read_point1;
|
||||
}
|
||||
|
||||
do {
|
||||
if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
return PACKET_NONE;
|
||||
}
|
||||
|
||||
if (session->state & LIBSSH2_STATE_NEWKEYS) {
|
||||
blocksize = session->remote.crypt->blocksize;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
encrypted = 0; /* not encrypted */
|
||||
blocksize = 5; /* not strictly true, but we can use 5
|
||||
here to make the checks below work
|
||||
fine still */
|
||||
blocksize = 5; /* not strictly true, but we can use 5 here to
|
||||
make the checks below work fine still */
|
||||
}
|
||||
minimum = p->total_num ? p->total_num - p->data_num : blocksize;
|
||||
|
||||
@ -285,28 +307,24 @@ libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
/* if remainbuf turns negative we have a bad internal error */
|
||||
assert(remainbuf >= 0);
|
||||
|
||||
while(remainbuf < minimum) {
|
||||
/* While there is too little data to deal with, read
|
||||
more */
|
||||
if (remainbuf < minimum) {
|
||||
/* If we have less than a minimum left, it is too
|
||||
little data to deal with, read more */
|
||||
ssize_t nread;
|
||||
|
||||
/* move any remainder to the start of the buffer so
|
||||
that we can do a full refill */
|
||||
if(remainbuf) {
|
||||
memmove(p->buf, &p->buf[p->readidx],
|
||||
remainbuf);
|
||||
if (remainbuf) {
|
||||
memmove(p->buf, &p->buf[p->readidx], remainbuf);
|
||||
p->readidx = 0;
|
||||
p->writeidx = remainbuf;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* nothing to move, just zero the indexes */
|
||||
p->readidx = p->writeidx = 0;
|
||||
}
|
||||
|
||||
/* now read a big chunk from the network into the temp
|
||||
buffer */
|
||||
nread = recv(session->socket_fd, &p->buf[remainbuf],
|
||||
PACKETBUFSIZE-remainbuf,
|
||||
/* now read a big chunk from the network into the temp buffer */
|
||||
nread = recv(session->socket_fd, &p->buf[remainbuf], PACKETBUFSIZE-remainbuf,
|
||||
LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (nread <= 0) {
|
||||
/* check if this is due to EAGAIN and return
|
||||
@ -329,23 +347,25 @@ libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
/* how much data to deal with from the buffer */
|
||||
numbytes = remainbuf;
|
||||
|
||||
if(!p->total_num) {
|
||||
if (numbytes < blocksize) {
|
||||
/* we can't act on anything less than blocksize */
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
|
||||
if (!p->total_num) {
|
||||
/* No payload package area allocated yet. To know the
|
||||
size of this payload, we need to decrypt the first
|
||||
blocksize data. */
|
||||
|
||||
if(encrypted) {
|
||||
rc = decrypt(session, &p->buf[p->readidx],
|
||||
block, blocksize);
|
||||
if(rc != PACKET_NONE) {
|
||||
if (encrypted) {
|
||||
rc = decrypt(session, &p->buf[p->readidx], block, blocksize);
|
||||
if (rc != PACKET_NONE) {
|
||||
return rc;
|
||||
}
|
||||
/* save the first 5 bytes of the decrypted
|
||||
package, to be used in the hash calculation
|
||||
later down. */
|
||||
/* save the first 5 bytes of the decrypted package, to be
|
||||
used in the hash calculation later down. */
|
||||
memcpy(p->init, &p->buf[p->readidx], 5);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* the data is plain, just copy it verbatim to
|
||||
the working block buffer */
|
||||
memcpy(block, &p->buf[p->readidx], blocksize);
|
||||
@ -355,16 +375,14 @@ libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
p->readidx += blocksize;
|
||||
|
||||
/* we now have the initial blocksize bytes decrypted,
|
||||
and we can extract packet and padding length from it
|
||||
*/
|
||||
* and we can extract packet and padding length from it
|
||||
*/
|
||||
p->packet_length = libssh2_ntohu32(block);
|
||||
p->padding_length = block[4];
|
||||
|
||||
/* total_num is the number of bytes following the
|
||||
initial (5 bytes) packet length and padding length
|
||||
fields */
|
||||
p->total_num = p->packet_length -1 +
|
||||
(encrypted?session->remote.mac->mac_len:0);
|
||||
/* total_num is the number of bytes following the initial
|
||||
(5 bytes) packet length and padding length fields */
|
||||
p->total_num = p->packet_length -1 + (encrypted ? session->remote.mac->mac_len : 0);
|
||||
|
||||
/* RFC4253 section 6.1 Maximum Packet Length says:
|
||||
*
|
||||
@ -374,26 +392,25 @@ libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
* or less (including length, padding length, payload,
|
||||
* padding, and MAC.)."
|
||||
*/
|
||||
if(p->total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
|
||||
if (p->total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
|
||||
return PACKET_TOOBIG;
|
||||
}
|
||||
|
||||
/* Get a packet handle put data into. We get one to
|
||||
hold all data, including padding and MAC. */
|
||||
p->payload = LIBSSH2_ALLOC(session, p->total_num);
|
||||
if(!p->payload) {
|
||||
if (!p->payload) {
|
||||
return PACKET_ENOMEM;
|
||||
}
|
||||
/* init write pointer to start of payload buffer */
|
||||
p->wptr = p->payload;
|
||||
|
||||
if(blocksize > 5) {
|
||||
if (blocksize > 5) {
|
||||
/* copy the data from index 5 to the end of
|
||||
the blocksize from the temporary buffer to
|
||||
the start of the decrypted buffer */
|
||||
memcpy(p->wptr, &block[5], blocksize-5);
|
||||
p->wptr += blocksize-5; /* advance write
|
||||
pointer */
|
||||
p->wptr += blocksize-5; /* advance write pointer */
|
||||
}
|
||||
|
||||
/* init the data_num field to the number of bytes of
|
||||
@ -405,17 +422,16 @@ libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
}
|
||||
|
||||
/* how much there is left to add to the current payload
|
||||
package */
|
||||
package */
|
||||
remainpack = p->total_num - p->data_num;
|
||||
|
||||
if(numbytes > remainpack) {
|
||||
/* if we have more data in the buffer than what is
|
||||
going into this particular packet, we limit this
|
||||
round to this packet only */
|
||||
if (numbytes > remainpack) {
|
||||
/* if we have more data in the buffer than what is going into this
|
||||
particular packet, we limit this round to this packet only */
|
||||
numbytes = remainpack;
|
||||
}
|
||||
|
||||
if(encrypted) {
|
||||
if (encrypted) {
|
||||
/* At the end of the incoming stream, there is a MAC,
|
||||
and we don't want to decrypt that since we need it
|
||||
"raw". We MUST however decrypt the padding data
|
||||
@ -425,35 +441,31 @@ libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
/* if what we have plus numbytes is bigger than the
|
||||
total minus the skip margin, we should lower the
|
||||
amount to decrypt even more */
|
||||
if((p->data_num + numbytes) > (p->total_num - skip)) {
|
||||
numdecrypt = (p->total_num - skip) -
|
||||
p->data_num;
|
||||
}
|
||||
else {
|
||||
if ((p->data_num + numbytes) > (p->total_num - skip)) {
|
||||
numdecrypt = (p->total_num - skip) - p->data_num;
|
||||
} else {
|
||||
int frac;
|
||||
numdecrypt = numbytes;
|
||||
frac = numdecrypt % blocksize;
|
||||
if(frac) {
|
||||
if (frac) {
|
||||
/* not an aligned amount of blocks,
|
||||
align it */
|
||||
align it */
|
||||
numdecrypt -= frac;
|
||||
/* and make it no unencrypted data
|
||||
after it */
|
||||
after it */
|
||||
numbytes = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* unencrypted data should not be decrypted at all */
|
||||
numdecrypt = 0;
|
||||
}
|
||||
|
||||
/* if there are bytes to decrypt, do that */
|
||||
if(numdecrypt > 0) {
|
||||
if (numdecrypt > 0) {
|
||||
/* now decrypt the lot */
|
||||
rc = decrypt(session, &p->buf[p->readidx],
|
||||
p->wptr, numdecrypt);
|
||||
if(rc != PACKET_NONE) {
|
||||
rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt);
|
||||
if (rc != PACKET_NONE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -469,8 +481,8 @@ libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
}
|
||||
|
||||
/* if there are bytes to copy that aren't decrypted, simply
|
||||
copy them as-is to the target buffer */
|
||||
if(numbytes > 0) {
|
||||
copy them as-is to the target buffer */
|
||||
if (numbytes > 0) {
|
||||
memcpy(p->wptr, &p->buf[p->readidx], numbytes);
|
||||
|
||||
/* advance the read pointer */
|
||||
@ -482,12 +494,18 @@ libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
}
|
||||
|
||||
/* now check how much data there's left to read to finish the
|
||||
current packet */
|
||||
current packet */
|
||||
remainpack = p->total_num - p->data_num;
|
||||
|
||||
if(!remainpack) {
|
||||
if (!remainpack) {
|
||||
/* we have a full packet */
|
||||
libssh2_packet_read_point1:
|
||||
rc = fullpacket(session, encrypted);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
session->readPack_encrypted = encrypted;
|
||||
session->readPack_state = libssh2_NB_state_jump1;
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
|
||||
p->total_num = 0; /* no packet buffer available */
|
||||
|
||||
@ -501,27 +519,24 @@ libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION *session)
|
||||
|
||||
#ifndef OLDSEND
|
||||
|
||||
static libssh2pack_t send_existing(LIBSSH2_SESSION *session,
|
||||
unsigned char *data,
|
||||
unsigned long data_len,
|
||||
ssize_t *ret)
|
||||
static libssh2pack_t send_existing(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len, ssize_t *ret)
|
||||
{
|
||||
ssize_t rc;
|
||||
ssize_t length;
|
||||
struct transportpacket *p = &session->packet;
|
||||
|
||||
if(!p->outbuf) {
|
||||
if (!p->outbuf) {
|
||||
*ret = 0;
|
||||
return PACKET_NONE;
|
||||
}
|
||||
|
||||
/* send as much as possible of the existing packet */
|
||||
if((data != p->odata) || (data_len != p->olen)) {
|
||||
/* When we are about to complete the sending of a packet, it
|
||||
is vital that the caller doesn't try to send a
|
||||
new/different packet since we don't add this one up until
|
||||
the previous one has been sent. To make the caller really
|
||||
notice his/hers flaw, we return error for this case */
|
||||
if ((data != p->odata) || (data_len != p->olen)) {
|
||||
/* When we are about to complete the sending of a packet, it is vital
|
||||
that the caller doesn't try to send a new/different packet since
|
||||
we don't add this one up until the previous one has been sent. To
|
||||
make the caller really notice his/hers flaw, we return error for
|
||||
this case */
|
||||
return PACKET_BADUSE;
|
||||
}
|
||||
|
||||
@ -530,27 +545,24 @@ static libssh2pack_t send_existing(LIBSSH2_SESSION *session,
|
||||
/* number of bytes left to send */
|
||||
length = p->ototal_num - p->osent;
|
||||
|
||||
rc = send(session->socket_fd,
|
||||
&p->outbuf[p->osent],
|
||||
length, LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
rc = send(session->socket_fd, &p->outbuf[p->osent], length, LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
|
||||
if(rc == length) {
|
||||
if (rc == length) {
|
||||
/* the remainder of the package was sent */
|
||||
LIBSSH2_FREE(session, p->outbuf);
|
||||
p->outbuf = NULL;
|
||||
p->ototal_num = 0;
|
||||
}
|
||||
else if(rc < 0) {
|
||||
else if (rc < 0) {
|
||||
/* nothing was sent */
|
||||
if(errno != EAGAIN) {
|
||||
if (errno != EAGAIN) {
|
||||
/* send failure! */
|
||||
return PACKET_FAIL;
|
||||
}
|
||||
return PACKET_EAGAIN;
|
||||
}
|
||||
|
||||
debugdump(session, "libssh2_packet_write send()",
|
||||
&p->outbuf[p->osent], length);
|
||||
debugdump(session, "libssh2_packet_write send()", &p->outbuf[p->osent], length);
|
||||
p->osent += length; /* we sent away this much data */
|
||||
|
||||
return PACKET_NONE;
|
||||
@ -565,12 +577,9 @@ static libssh2pack_t send_existing(LIBSSH2_SESSION *session,
|
||||
* sent, and this function should then be called with the same argument set
|
||||
* (same data pointer and same data_len) until zero or failure is returned.
|
||||
*/
|
||||
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data,
|
||||
unsigned long data_len)
|
||||
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len)
|
||||
{
|
||||
int blocksize =
|
||||
(session->state & LIBSSH2_STATE_NEWKEYS) ?
|
||||
session->local.crypt->blocksize : 8;
|
||||
int blocksize = (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->blocksize : 8;
|
||||
int padding_length;
|
||||
int packet_length;
|
||||
int total_length;
|
||||
@ -591,17 +600,16 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data,
|
||||
|
||||
/* FIRST, check if we have a pending write to complete */
|
||||
rc = send_existing(session, data, data_len, &ret);
|
||||
if(rc || ret)
|
||||
if (rc || ret) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
encrypted = (session->state & LIBSSH2_STATE_NEWKEYS)?1:0;
|
||||
|
||||
/* check if we should compress */
|
||||
if (encrypted && strcmp(session->local.comp->name, "none")) {
|
||||
if (session->local.comp->comp(session, 1, &data, &data_len,
|
||||
LIBSSH2_PACKET_MAXCOMP,
|
||||
&free_data, data, data_len,
|
||||
&session->local.comp_abstract)) {
|
||||
if (session->local.comp->comp(session, 1, &data, &data_len, LIBSSH2_PACKET_MAXCOMP,
|
||||
&free_data, data, data_len, &session->local.comp_abstract)) {
|
||||
return PACKET_COMPRESS; /* compression failure */
|
||||
}
|
||||
}
|
||||
@ -611,11 +619,10 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data,
|
||||
MUST be a multiple of the cipher block size or 8, whichever is
|
||||
larger. */
|
||||
|
||||
/* Plain math: (4 + 1 + packet_length + padding_length) % blocksize ==
|
||||
0 */
|
||||
/* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */
|
||||
|
||||
packet_length = data_len + 1 + 4; /* 1 is for padding_length field
|
||||
4 for the packet_length field */
|
||||
4 for the packet_length field */
|
||||
|
||||
/* at this point we have it all except the padding */
|
||||
|
||||
@ -643,14 +650,13 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data,
|
||||
packet_length += padding_length;
|
||||
|
||||
/* append the MAC length to the total_length size */
|
||||
total_length = packet_length +
|
||||
(encrypted?session->local.mac->mac_len:0);
|
||||
total_length = packet_length + (encrypted?session->local.mac->mac_len:0);
|
||||
|
||||
/* allocate memory to store the outgoing packet in, in case we can't
|
||||
send the whole one and thus need to keep it after this function
|
||||
returns. */
|
||||
p->outbuf = LIBSSH2_ALLOC(session, total_length);
|
||||
if(!p->outbuf) {
|
||||
if (!p->outbuf) {
|
||||
return PACKET_ENOMEM;
|
||||
}
|
||||
|
||||
@ -667,41 +673,33 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data,
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
|
||||
if(encrypted) {
|
||||
if (encrypted) {
|
||||
/* Calculate MAC hash. Put the output at index packet_length,
|
||||
since that size includes the whole packet. The MAC is
|
||||
calculated on the entire unencrypted packet, including all
|
||||
fields except the MAC field itself. */
|
||||
session->local.mac->hash(session,
|
||||
p->outbuf + packet_length,
|
||||
session->local.seqno,
|
||||
p->outbuf, packet_length,
|
||||
NULL, 0,
|
||||
&session->local.mac_abstract);
|
||||
session->local.mac->hash(session, p->outbuf + packet_length, session->local.seqno, p->outbuf, packet_length,
|
||||
NULL, 0, &session->local.mac_abstract);
|
||||
|
||||
/* Encrypt the whole packet data, one block size at a time.
|
||||
The MAC field is not encrypted. */
|
||||
for(i=0; i < packet_length;
|
||||
i += session->local.crypt->blocksize) {
|
||||
for(i=0; i < packet_length; i += session->local.crypt->blocksize) {
|
||||
unsigned char *ptr = &p->outbuf[i];
|
||||
if(session->local.crypt->crypt(session, ptr,
|
||||
&session->local.crypt_abstract))
|
||||
if (session->local.crypt->crypt(session, ptr, &session->local.crypt_abstract))
|
||||
return PACKET_FAIL; /* encryption failure */
|
||||
}
|
||||
}
|
||||
|
||||
session->local.seqno++;
|
||||
|
||||
ret = send(session->socket_fd, p->outbuf,
|
||||
total_length, LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
ret = send(session->socket_fd, p->outbuf, total_length,
|
||||
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
|
||||
if(ret != -1) {
|
||||
debugdump(session, "libssh2_packet_write send()",
|
||||
p->outbuf, ret);
|
||||
if (ret != -1) {
|
||||
debugdump(session, "libssh2_packet_write send()", p->outbuf, ret);
|
||||
}
|
||||
if(ret != total_length) {
|
||||
if((ret > 0 ) ||
|
||||
((ret == -1) && (errno == EAGAIN))) {
|
||||
if (ret != total_length) {
|
||||
if ((ret > 0 ) || ((ret == -1) && (errno == EAGAIN))) {
|
||||
/* the whole packet could not be sent, save the rest */
|
||||
p->odata = orgdata;
|
||||
p->olen = orgdata_len;
|
||||
|
1367
src/userauth.c
1367
src/userauth.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
x
Ссылка в новой задаче
Block a user