Compare commits
24 Commits
RELEASE.0.
...
RELEASE.0.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3f24fb005e | ||
![]() |
f11c657a10 | ||
![]() |
d4efdee802 | ||
![]() |
aa8b8afe4f | ||
![]() |
525a181037 | ||
![]() |
9977cee99b | ||
![]() |
3a744117d6 | ||
![]() |
d974137db9 | ||
![]() |
66f913e53a | ||
![]() |
912e9ca713 | ||
![]() |
6fdf9c9c06 | ||
![]() |
26e7e66ecf | ||
![]() |
a0cd3ed3dc | ||
![]() |
3614bdac21 | ||
![]() |
14af2e3952 | ||
![]() |
620a685af2 | ||
![]() |
4ab2f2ab73 | ||
![]() |
d2ca405d0f | ||
![]() |
566bea77ea | ||
![]() |
165837c085 | ||
![]() |
7035d475eb | ||
![]() |
794f01acc1 | ||
![]() |
2b670d36ca | ||
![]() |
7a153310f7 |
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
|
@@ -10,7 +10,7 @@ CC = @CC@
|
|||||||
CFLAGS = -c @CFLAGS@ -Iinclude/ -Wall -g
|
CFLAGS = -c @CFLAGS@ -Iinclude/ -Wall -g
|
||||||
LIBS = -lssh2 -Lsrc/
|
LIBS = -lssh2 -Lsrc/
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
VERSION=0.1
|
VERSION=0.3
|
||||||
DISTLIB=libssh2-$(VERSION)
|
DISTLIB=libssh2-$(VERSION)
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@@ -28,6 +28,7 @@ install:
|
|||||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||||
done && test -z "$$fail"
|
done && test -z "$$fail"
|
||||||
$(INSTALL) -m 644 include/libssh2.h $(incldir)/
|
$(INSTALL) -m 644 include/libssh2.h $(incldir)/
|
||||||
|
$(INSTALL) -m 644 include/libssh2_sftp.h $(incldir)/
|
||||||
clean:
|
clean:
|
||||||
@for dir in ${subdirs}; do \
|
@for dir in ${subdirs}; do \
|
||||||
(cd $$dir && $(MAKE) clean) \
|
(cd $$dir && $(MAKE) clean) \
|
||||||
@@ -44,5 +45,6 @@ dist:
|
|||||||
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \
|
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \
|
||||||
$(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh \
|
$(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh \
|
||||||
$(DISTLIB)/src/*.c $(DISTLIB)/src/Makefile.in \
|
$(DISTLIB)/src/*.c $(DISTLIB)/src/Makefile.in \
|
||||||
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_config.h.in
|
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \
|
||||||
|
$(DISTLIB)/include/libssh2_config.h.in
|
||||||
rm -f $(DISTLIB)
|
rm -f $(DISTLIB)
|
||||||
|
50
README
50
README
@@ -1,8 +1,54 @@
|
|||||||
libssh2 - SSH2 library
|
libssh2 - SSH2 library
|
||||||
======================
|
======================
|
||||||
|
|
||||||
Version 0.1-dev
|
Version 0.3
|
||||||
---------------
|
-----------
|
||||||
|
|
||||||
|
Fixed libssh2_channel_read_ex(). Packet loop initialized BEFORE transport polled for new packets (should have been after).
|
||||||
|
|
||||||
|
Fixed blocking issues in scp_send()/scp_recv().
|
||||||
|
|
||||||
|
Fixed degree of indirection in macerror callback.
|
||||||
|
|
||||||
|
Changed packet read mechanism to use a fixed buffer and avoid unnecessary alloc/free calls. (especially while non-block looping)
|
||||||
|
|
||||||
|
Added channel close callback.
|
||||||
|
|
||||||
|
Added SFTP support (Using its own header file: libssh2_sftp.h)
|
||||||
|
|
||||||
|
Version 0.2
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Changed extended data ignorance mechanism:
|
||||||
|
libssh2_channel_ignore_extended_data() changed to libssh2_channel_handle_extended_data()
|
||||||
|
Macro introduced for backward compatability during beta phase.
|
||||||
|
*** THE LIBSSH2_CHANNEL_IGNORE_EXTENDED_DATA() MACRO WILL BE REMOVED PRIOR TO 1.0 RELEASE ***
|
||||||
|
libssh2_channel_handle_extended_data() may be passed one of three "ignore_mode" constants
|
||||||
|
LIBSSH2_CHANNEL_EXTENDED_DATA_NONE Default behavior, queue ED packets and return them with read_ex
|
||||||
|
LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE Equivalent to libssh2_channel_ignore_extended_data()
|
||||||
|
IGNORE will implicitly flush the extended data stream(s)
|
||||||
|
LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE Calls to channel_read() will check both the standard data stream
|
||||||
|
and the extended data stream(s) for the first available packet
|
||||||
|
|
||||||
|
Changed libssh2_session_disconnect_ex() to return an error code when alloc fails
|
||||||
|
|
||||||
|
Added libssh2_channel_flush_ex() and basic macros: ..._flush() ..._flush_stderr()
|
||||||
|
flush_ex accepts either the streamid (0 for standard data, 1 for stderr) or one of the two following constants:
|
||||||
|
LIBSSH2_CHANNEL_FLUSH_ALL Flush all streams
|
||||||
|
LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA Flush all streams EXCEPT the standard data stream
|
||||||
|
|
||||||
|
Added libssh2_session_callback_set() for setting ignore/debug/disconnect/macerror callbacks
|
||||||
|
|
||||||
|
Added libssh2_session_method_pref() to selectively set methods and method preferences.
|
||||||
|
|
||||||
|
Added libssh2_session_methods() to determine what methods were negotiated.
|
||||||
|
|
||||||
|
Added libssh2_session_abstract() for retreiving &session->abstract
|
||||||
|
|
||||||
|
Added libssh2_session_last_error() for retreiving error codes/messages
|
||||||
|
|
||||||
|
Version 0.1
|
||||||
|
-----------
|
||||||
|
|
||||||
Initial Release:
|
Initial Release:
|
||||||
KEX methods: diffie-hellman-group14-sha1, diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1
|
KEX methods: diffie-hellman-group14-sha1, diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1
|
||||||
|
1
TODO
1
TODO
@@ -1,4 +1,3 @@
|
|||||||
* More Crypt Methods
|
* More Crypt Methods
|
||||||
* hmac-md5, hmac-md5-96
|
* hmac-md5, hmac-md5-96
|
||||||
* SFTP support
|
|
||||||
* Review callbacks
|
* Review callbacks
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
# AC_PREREQ(2.57)
|
# AC_PREREQ(2.57)
|
||||||
AC_INIT(libssh2, 0.1 , pollita@php.net)
|
AC_INIT(libssh2, 0.3 , sarag@libssh2.org)
|
||||||
AC_CONFIG_SRCDIR([src])
|
AC_CONFIG_SRCDIR([src])
|
||||||
AC_CONFIG_HEADER([include/libssh2_config.h])
|
AC_CONFIG_HEADER([include/libssh2_config.h])
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@@ -42,7 +42,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#define LIBSSH2_VERSION "0.1"
|
#define LIBSSH2_VERSION "0.3"
|
||||||
|
#define LIBSSH2_APINO 200412211608
|
||||||
|
|
||||||
/* Part of every banner, user specified or not */
|
/* Part of every banner, user specified or not */
|
||||||
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
|
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
|
||||||
@@ -51,6 +52,51 @@
|
|||||||
#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER
|
#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER
|
||||||
#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n"
|
#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n"
|
||||||
|
|
||||||
|
/* Capabilities */
|
||||||
|
#define LIBSSH2_KEX_DH_GROUP1
|
||||||
|
#define LIBSSH2_KEX_DH_GROUP14
|
||||||
|
#define LIBSSH2_KEX_DH_GROUP_EXCHANGE
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_RSA
|
||||||
|
#define LIBSSH2_HOSTKEY_RSA
|
||||||
|
#endif
|
||||||
|
#ifndef OPENSSL_NO_DSA
|
||||||
|
#define LIBSSH2_HOSTKEY_DSA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_AES
|
||||||
|
#define LIBSSH2_CRYPT_AES256_CBC
|
||||||
|
#define LIBSSH2_CRYPT_RIJNDAEL_CBC_LYSATOR_LIU_SE
|
||||||
|
#define LIBSSH2_CRYPT_AES192_CBC
|
||||||
|
#define LIBSSH2_CRYPT_AES128_CBC
|
||||||
|
#endif
|
||||||
|
#ifndef OPENSSL_NO_BLOWFISH
|
||||||
|
#define LIBSSH2_CRYPT_BLOWFISH_CBC
|
||||||
|
#endif
|
||||||
|
#ifndef OPENSSL_NO_RC4
|
||||||
|
#define LIBSSH2_CRYPT_ARCFOUR
|
||||||
|
#endif
|
||||||
|
#ifndef OPENSSL_NO_CAST
|
||||||
|
#define LIBSSH2_CRYPT_CAST128_CBC
|
||||||
|
#endif
|
||||||
|
#ifndef OPENSSL_NO_DES
|
||||||
|
#define LIBSSH2_CRYPT_3DES_CBC
|
||||||
|
#endif
|
||||||
|
/* LIBSSH2_CRYPT_NONE already defined (or not) by ./configure */
|
||||||
|
|
||||||
|
#ifdef LIBSSH2_HAVE_ZLIB
|
||||||
|
#define LIBSSH2_COMP_ZLIB
|
||||||
|
#endif
|
||||||
|
#define LIBSSH2_COMP_NONE
|
||||||
|
|
||||||
|
#define LIBSSH2_MAC_SHA1
|
||||||
|
#define LIBSSH2_MAC_SHA1_96
|
||||||
|
#ifndef OPENSSL_NO_RIPEMD
|
||||||
|
#define LIBSSH2_MAC_RIPEMD160
|
||||||
|
#define LIBSSH2_MAC_RIPEMD160_OPENSSH_COM
|
||||||
|
#endif
|
||||||
|
/* LIBSSH2_MAC_NONE already defined (or not) by ./configure */
|
||||||
|
|
||||||
/* Enable the "new" version of diffie-hellman-group-exchange-sha1 */
|
/* Enable the "new" version of diffie-hellman-group-exchange-sha1 */
|
||||||
#define LIBSSH2_DH_GEX_NEW
|
#define LIBSSH2_DH_GEX_NEW
|
||||||
|
|
||||||
@@ -71,10 +117,13 @@
|
|||||||
#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120
|
#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120
|
||||||
|
|
||||||
/* Maximum size to allow a payload to compress to, plays it safe by falling short of spec limits */
|
/* Maximum size to allow a payload to compress to, plays it safe by falling short of spec limits */
|
||||||
#define LIBSSH2_PACKET_MAXCOMP 32000
|
#define LIBSSH2_PACKET_MAXCOMP 32000
|
||||||
|
|
||||||
/* Maximum size to allow a payload to deccompress to, plays it safe by allowing more than spec requires */
|
/* Maximum size to allow a payload to deccompress to, plays it safe by allowing more than spec requires */
|
||||||
#define LIBSSH2_PACKET_MAXDECOMP 40000
|
#define LIBSSH2_PACKET_MAXDECOMP 40000
|
||||||
|
|
||||||
|
/* Maximum size for an inbound compressed payload, plays it safe by overshooting spec limits */
|
||||||
|
#define LIBSSH2_PACKET_MAXPAYLOAD 40000
|
||||||
|
|
||||||
/* Malloc callbacks */
|
/* Malloc callbacks */
|
||||||
#define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract)
|
#define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract)
|
||||||
@@ -88,6 +137,26 @@
|
|||||||
#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, void **abstract)
|
#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, void **abstract)
|
||||||
#define LIBSSH2_MACERROR_FUNC(name) int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, void **abstract)
|
#define LIBSSH2_MACERROR_FUNC(name) int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, void **abstract)
|
||||||
|
|
||||||
|
#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) void name(LIBSSH2_SESSION *session, void **session_abstract, LIBSSH2_CHANNEL *channel, void **channel_abstract)
|
||||||
|
|
||||||
|
/* libssh2_session_callback_set() constants */
|
||||||
|
#define LIBSSH2_CALLBACK_IGNORE 0
|
||||||
|
#define LIBSSH2_CALLBACK_DEBUG 1
|
||||||
|
#define LIBSSH2_CALLBACK_DISCONNECT 2
|
||||||
|
#define LIBSSH2_CALLBACK_MACERROR 3
|
||||||
|
|
||||||
|
/* libssh2_session_method_pref() constants */
|
||||||
|
#define LIBSSH2_METHOD_KEX 0
|
||||||
|
#define LIBSSH2_METHOD_HOSTKEY 1
|
||||||
|
#define LIBSSH2_METHOD_CRYPT_CS 2
|
||||||
|
#define LIBSSH2_METHOD_CRYPT_SC 3
|
||||||
|
#define LIBSSH2_METHOD_MAC_CS 4
|
||||||
|
#define LIBSSH2_METHOD_MAC_SC 5
|
||||||
|
#define LIBSSH2_METHOD_COMP_CS 6
|
||||||
|
#define LIBSSH2_METHOD_COMP_SC 7
|
||||||
|
#define LIBSSH2_METHOD_LANG_CS 8
|
||||||
|
#define LIBSSH2_METHOD_LANG_SC 9
|
||||||
|
|
||||||
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
|
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
|
||||||
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
||||||
|
|
||||||
@@ -148,18 +217,31 @@ typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
|||||||
#define LIBSSH2_ERROR_SCP_PROTOCOL -28
|
#define LIBSSH2_ERROR_SCP_PROTOCOL -28
|
||||||
#define LIBSSH2_ERROR_ZLIB -29
|
#define LIBSSH2_ERROR_ZLIB -29
|
||||||
#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30
|
#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30
|
||||||
|
#define LIBSSH2_ERROR_SFTP_PROTOCOL -31
|
||||||
|
|
||||||
/* Session API */
|
/* 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);
|
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);
|
||||||
#define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL)
|
#define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL)
|
||||||
|
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session);
|
||||||
|
|
||||||
|
LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback);
|
||||||
|
|
||||||
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
|
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
|
||||||
LIBSSH2_API void libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang);
|
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang);
|
||||||
#define libssh2_session_disconnect(session, description) libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, (description), "")
|
#define libssh2_session_disconnect(session, description) libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, (description), "")
|
||||||
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session);
|
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session);
|
||||||
|
|
||||||
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
|
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, char *prefs);
|
||||||
|
LIBSSH2_API void libssh2_session_methods(LIBSSH2_SESSION *session, char **kex, char **hostkey,
|
||||||
|
char **crypt_cs, char **crypt_sc,
|
||||||
|
char **mac_cs, char **mac_sc,
|
||||||
|
char **comp_cs, char **comp_sc,
|
||||||
|
char **lang_cs, char **lang_sc);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
|
||||||
|
|
||||||
/* Userauth API */
|
/* Userauth API */
|
||||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len);
|
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len);
|
||||||
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
|
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
|
||||||
@@ -176,6 +258,13 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
|||||||
#define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536
|
#define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536
|
||||||
#define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384
|
#define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384
|
||||||
|
|
||||||
|
/* Extended Data Handling */
|
||||||
|
#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0
|
||||||
|
#define LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE 1
|
||||||
|
#define LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE 2
|
||||||
|
|
||||||
|
#define SSH_EXTENDED_DATA_STDERR 1
|
||||||
|
|
||||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size, char *message, int message_len);
|
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size, char *message, int message_len);
|
||||||
#define libssh2_channel_open_session(session) libssh2_channel_open_ex((session), "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0)
|
#define libssh2_channel_open_session(session) libssh2_channel_open_ex((session), "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0)
|
||||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport);
|
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport);
|
||||||
@@ -192,7 +281,6 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, char *
|
|||||||
#define libssh2_channel_exec(channel, command) libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))
|
#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))
|
#define libssh2_channel_subsystem(channel, subsystem) libssh2_channel_process_startup((channel), "subsystem", sizeof("subsystem") - 1, (subsystem), strlen(subsystem))
|
||||||
|
|
||||||
#define SSH_EXTENDED_DATA_STDERR 1
|
|
||||||
LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen);
|
LIBSSH2_API int 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(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_read_stderr(channel, buf, buflen) libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
||||||
@@ -202,7 +290,19 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
|
|||||||
#define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
#define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
||||||
|
|
||||||
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
|
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
|
||||||
LIBSSH2_API void libssh2_channel_ignore_extended_data(LIBSSH2_CHANNEL *channel, int ignore);
|
LIBSSH2_API void libssh2_channel_handle_extended_data(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
|
||||||
|
*/
|
||||||
|
/* DEPRECATED */
|
||||||
|
#define libssh2_channel_ignore_extended_data(channel, ignore) libssh2_channel_handle_extended_data((channel), (ignore) ? LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL )
|
||||||
|
|
||||||
|
#define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA -1
|
||||||
|
#define LIBSSH2_CHANNEL_FLUSH_ALL -2
|
||||||
|
LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid);
|
||||||
|
#define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0)
|
||||||
|
#define libssh2_channel_flush_stderr(channel) libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR)
|
||||||
|
|
||||||
LIBSSH2_API int libssh2_channel_send_eof(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_eof(LIBSSH2_CHANNEL *channel);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@@ -55,7 +55,9 @@
|
|||||||
#define LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len) \
|
#define LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len) \
|
||||||
session->ssh_msg_disconnect((session), (reason), (message), (message_len), (language), (language_len), &(session)->abstract)
|
session->ssh_msg_disconnect((session), (reason), (message), (message_len), (language), (language_len), &(session)->abstract)
|
||||||
|
|
||||||
#define LIBSSH2_MACERROR(session, data, datalen) session->macerror((session), (data), (datalen), (session)->abstract)
|
#define LIBSSH2_MACERROR(session, data, datalen) session->macerror((session), (data), (datalen), &(session)->abstract)
|
||||||
|
|
||||||
|
#define LIBSSH2_CHANNEL_CLOSE(session, channel) channel->close_cb((session), &(session)->abstract, (channel), &(channel)->abstract)
|
||||||
|
|
||||||
typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD;
|
typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD;
|
||||||
typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD;
|
typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD;
|
||||||
@@ -98,7 +100,7 @@ typedef struct _libssh2_channel_data {
|
|||||||
unsigned long window_size_initial, window_size, packet_size;
|
unsigned long window_size_initial, window_size, packet_size;
|
||||||
|
|
||||||
/* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */
|
/* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */
|
||||||
char close, eof, ignore_extended_data;
|
char close, eof, extended_data_ignore_mode;
|
||||||
} libssh2_channel_data;
|
} libssh2_channel_data;
|
||||||
|
|
||||||
struct _LIBSSH2_CHANNEL {
|
struct _LIBSSH2_CHANNEL {
|
||||||
@@ -112,6 +114,9 @@ struct _LIBSSH2_CHANNEL {
|
|||||||
LIBSSH2_SESSION *session;
|
LIBSSH2_SESSION *session;
|
||||||
|
|
||||||
LIBSSH2_CHANNEL *next, *prev;
|
LIBSSH2_CHANNEL *next, *prev;
|
||||||
|
|
||||||
|
void *abstract;
|
||||||
|
LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _LIBSSH2_CHANNEL_BRIGADE {
|
struct _LIBSSH2_CHANNEL_BRIGADE {
|
||||||
@@ -135,9 +140,10 @@ typedef struct _libssh2_endpoint_data {
|
|||||||
void *comp_abstract;
|
void *comp_abstract;
|
||||||
|
|
||||||
/* Method Preferences -- NULL yields "load order" */
|
/* Method Preferences -- NULL yields "load order" */
|
||||||
LIBSSH2_CRYPT_METHOD **crypt_prefs;
|
char *crypt_prefs;
|
||||||
LIBSSH2_MAC_METHOD **mac_prefs;
|
char *mac_prefs;
|
||||||
LIBSSH2_COMP_METHOD **comp_prefs;
|
char *comp_prefs;
|
||||||
|
char *lang_prefs;
|
||||||
} libssh2_endpoint_data;
|
} libssh2_endpoint_data;
|
||||||
|
|
||||||
struct _LIBSSH2_SESSION {
|
struct _LIBSSH2_SESSION {
|
||||||
@@ -154,8 +160,8 @@ struct _LIBSSH2_SESSION {
|
|||||||
LIBSSH2_MACERROR_FUNC((*macerror));
|
LIBSSH2_MACERROR_FUNC((*macerror));
|
||||||
|
|
||||||
/* Method preferences -- NULL yields "load order" */
|
/* Method preferences -- NULL yields "load order" */
|
||||||
LIBSSH2_KEX_METHOD **kex_prefs;
|
char *kex_prefs;
|
||||||
LIBSSH2_HOSTKEY_METHOD **hostkey_prefs;
|
char *hostkey_prefs;
|
||||||
|
|
||||||
int exchanging_keys;
|
int exchanging_keys;
|
||||||
int newkeys;
|
int newkeys;
|
||||||
@@ -354,7 +360,9 @@ struct _LIBSSH2_MAC_METHOD {
|
|||||||
void libssh2_session_shutdown(LIBSSH2_SESSION *session);
|
void libssh2_session_shutdown(LIBSSH2_SESSION *session);
|
||||||
|
|
||||||
unsigned long libssh2_ntohu32(const unsigned char *buf);
|
unsigned long libssh2_ntohu32(const unsigned char *buf);
|
||||||
|
unsigned long long libssh2_ntohu64(const unsigned char *buf);
|
||||||
void libssh2_htonu32(unsigned char *buf, unsigned long val);
|
void libssh2_htonu32(unsigned char *buf, unsigned long val);
|
||||||
|
void libssh2_htonu64(unsigned char *buf, unsigned long long val);
|
||||||
|
|
||||||
int libssh2_packet_read(LIBSSH2_SESSION *session, int block);
|
int libssh2_packet_read(LIBSSH2_SESSION *session, int block);
|
||||||
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_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);
|
||||||
|
190
include/libssh2_sftp.h
Normal file
190
include/libssh2_sftp.h
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBSSH2_SFTP_H
|
||||||
|
#define LIBSSH2_SFTP_H 1
|
||||||
|
|
||||||
|
/* Note: Version 6 was documented at the time of writing
|
||||||
|
* However it was marked as "DO NOT IMPLEMENT" due to pending changes
|
||||||
|
*
|
||||||
|
* Let's start with Version 3 (The version found in OpenSSH) and go from there
|
||||||
|
*/
|
||||||
|
#define LIBSSH2_SFTP_VERSION 3
|
||||||
|
#define LIBSSH2_SFTP_PACKET_MAXLEN 40000
|
||||||
|
|
||||||
|
typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP;
|
||||||
|
typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE;
|
||||||
|
typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES;
|
||||||
|
|
||||||
|
/* Flags for open_ex() */
|
||||||
|
#define LIBSSH2_SFTP_OPENFILE 0
|
||||||
|
#define LIBSSH2_SFTP_OPENDIR 1
|
||||||
|
|
||||||
|
/* Flags for rename_ex() */
|
||||||
|
#define LIBSSH2_SFTP_RENAME_OVERWRITE 0x00000001
|
||||||
|
#define LIBSSH2_SFTP_RENAME_ATOMIC 0x00000002
|
||||||
|
#define LIBSSH2_SFTP_RENAME_NATIVE 0x00000004
|
||||||
|
|
||||||
|
/* Flags for stat_ex() */
|
||||||
|
#define LIBSSH2_SFTP_STAT 0
|
||||||
|
#define LIBSSH2_SFTP_LSTAT 1
|
||||||
|
#define LIBSSH2_SFTP_SETSTAT 2
|
||||||
|
|
||||||
|
/* Flags for symlink_ex() */
|
||||||
|
#define LIBSSH2_SFTP_SYMLINK 0
|
||||||
|
#define LIBSSH2_SFTP_READLINK 1
|
||||||
|
#define LIBSSH2_SFTP_REALPATH 2
|
||||||
|
|
||||||
|
/* SFTP attribute flag bits */
|
||||||
|
#define LIBSSH2_SFTP_ATTR_SIZE 0x00000001
|
||||||
|
#define LIBSSH2_SFTP_ATTR_UIDGID 0x00000002
|
||||||
|
#define LIBSSH2_SFTP_ATTR_PERMISSIONS 0x00000004
|
||||||
|
#define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008
|
||||||
|
#define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000
|
||||||
|
|
||||||
|
struct _LIBSSH2_SFTP_ATTRIBUTES {
|
||||||
|
/* If flags & ATTR_* bit is set, then the value in this struct will be meaningful
|
||||||
|
* Otherwise it should be ignored
|
||||||
|
*/
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
unsigned long long filesize;
|
||||||
|
unsigned long uid, gid;
|
||||||
|
unsigned long permissions;
|
||||||
|
unsigned long atime, mtime;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SFTP filetypes */
|
||||||
|
#define LIBSSH2_SFTP_TYPE_REGULAR 1
|
||||||
|
#define LIBSSH2_SFTP_TYPE_DIRECTORY 2
|
||||||
|
#define LIBSSH2_SFTP_TYPE_SYMLINK 3
|
||||||
|
#define LIBSSH2_SFTP_TYPE_SPECIAL 4
|
||||||
|
#define LIBSSH2_SFTP_TYPE_UNKNOWN 5
|
||||||
|
#define LIBSSH2_SFTP_TYPE_SOCKET 6
|
||||||
|
#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE 7
|
||||||
|
#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8
|
||||||
|
#define LIBSSH2_SFTP_TYPE_FIFO 9
|
||||||
|
|
||||||
|
/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open())
|
||||||
|
* Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */
|
||||||
|
#define LIBSSH2_FXF_READ 0x00000001
|
||||||
|
#define LIBSSH2_FXF_WRITE 0x00000002
|
||||||
|
#define LIBSSH2_FXF_APPEND 0x00000004
|
||||||
|
#define LIBSSH2_FXF_CREAT 0x00000008
|
||||||
|
#define LIBSSH2_FXF_TRUNC 0x00000010
|
||||||
|
#define LIBSSH2_FXF_EXCL 0x00000020
|
||||||
|
|
||||||
|
/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */
|
||||||
|
#define LIBSSH2_FX_OK 0
|
||||||
|
#define LIBSSH2_FX_EOF 1
|
||||||
|
#define LIBSSH2_FX_NO_SUCH_FILE 2
|
||||||
|
#define LIBSSH2_FX_PERMISSION_DENIED 3
|
||||||
|
#define LIBSSH2_FX_FAILURE 4
|
||||||
|
#define LIBSSH2_FX_BAD_MESSAGE 5
|
||||||
|
#define LIBSSH2_FX_NO_CONNECTION 6
|
||||||
|
#define LIBSSH2_FX_CONNECTION_LOST 7
|
||||||
|
#define LIBSSH2_FX_OP_UNSUPPORTED 8
|
||||||
|
#define LIBSSH2_FX_INVALID_HANDLE 9
|
||||||
|
#define LIBSSH2_FX_NO_SUCH_PATH 10
|
||||||
|
#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11
|
||||||
|
#define LIBSSH2_FX_WRITE_PROTECT 12
|
||||||
|
#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_DIR_NOT_EMPTY 18
|
||||||
|
#define LIBSSH2_FX_NOT_A_DIRECTORY 19
|
||||||
|
#define LIBSSH2_FX_INVALID_FILENAME 20
|
||||||
|
#define LIBSSH2_FX_LINK_LOOP 21
|
||||||
|
|
||||||
|
/* SFTP API */
|
||||||
|
LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session);
|
||||||
|
LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp);
|
||||||
|
LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp);
|
||||||
|
|
||||||
|
/* File / Directory Ops */
|
||||||
|
LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len, unsigned long flags, long mode, int open_type);
|
||||||
|
#define libssh2_sftp_open(sftp, filename, flags, mode) libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), (mode), LIBSSH2_SFTP_OPENFILE)
|
||||||
|
#define libssh2_sftp_opendir(sftp, path) libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, LIBSSH2_SFTP_OPENDIR)
|
||||||
|
|
||||||
|
LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen);
|
||||||
|
LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||||
|
LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
|
||||||
|
#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle)
|
||||||
|
#define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle)
|
||||||
|
|
||||||
|
LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
|
||||||
|
#define libssh2_sftp_rewind(handle) libssh2_sftp_seek((handle), 0)
|
||||||
|
|
||||||
|
LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat);
|
||||||
|
#define libssh2_sftp_fstat(handle, attrs) libssh2_sftp_fstat_ex((handle), (attrs), 0)
|
||||||
|
#define libssh2_sftp_fsetstat(handle, attrs) libssh2_sftp_fstat_ex((handle), (attrs), 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Miscellaneous Ops */
|
||||||
|
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filename, int srouce_filename_len,
|
||||||
|
char *dest_filename, int dest_filename_len,
|
||||||
|
long flags);
|
||||||
|
#define libssh2_sftp_rename(sftp, sourcefile, destfile) libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), (destfile), strlen(destfile), \
|
||||||
|
LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE)
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len);
|
||||||
|
#define libssh2_sftp_unlink(sftp, filename) libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename))
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, long mode);
|
||||||
|
#define libssh2_sftp_mkdir(sftp, path, mode) libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode))
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len);
|
||||||
|
#define libssh2_sftp_rmdir(sftp, path) libssh2_sftp_rmdir_ex((sftp), (path), strlen(path))
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||||
|
#define libssh2_sftp_stat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, (attrs))
|
||||||
|
#define libssh2_sftp_lstat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, (attrs))
|
||||||
|
#define libssh2_sftp_setstat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, (attrs))
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, int path_len, char *target, int target_len, int link_type);
|
||||||
|
#define libssh2_sftp_symlink(sftp, orig, linkpath) libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), strlen(linkpath), LIBSSH2_SFTP_SYMLINK)
|
||||||
|
#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)
|
||||||
|
|
||||||
|
#endif /* LIBSSH2_SFTP_H */
|
@@ -1,4 +1,4 @@
|
|||||||
OBJECTS = channel.o comp.o crypt.o hostkey.o kex.o mac.o misc.o packet.o scp.o session.o userauth.o
|
OBJECTS = channel.o comp.o crypt.o hostkey.o kex.o mac.o misc.o packet.o scp.o session.o sftp.o userauth.o
|
||||||
|
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
prefix = @prefix@
|
prefix = @prefix@
|
||||||
@@ -42,6 +42,9 @@ scp.o: scp.c
|
|||||||
session.o: session.c
|
session.o: session.c
|
||||||
$(CC) -o session.o session.c $(CFLAGS) $(LIBS)
|
$(CC) -o session.o session.c $(CFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
sftp.o: sftp.c
|
||||||
|
$(CC) -o sftp.o sftp.c $(CFLAGS) $(LIBS)
|
||||||
|
|
||||||
userauth.o: userauth.c
|
userauth.o: userauth.c
|
||||||
$(CC) -o userauth.o userauth.c $(CFLAGS) $(LIBS)
|
$(CC) -o userauth.o userauth.c $(CFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
213
src/channel.c
213
src/channel.c
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@@ -72,7 +72,6 @@ static unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session)
|
|||||||
LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id)
|
LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id)
|
||||||
{
|
{
|
||||||
LIBSSH2_CHANNEL *channel = session->channels.head;
|
LIBSSH2_CHANNEL *channel = session->channels.head;
|
||||||
|
|
||||||
while (channel) {
|
while (channel) {
|
||||||
if (channel->local.id == channel_id) {
|
if (channel->local.id == channel_id) {
|
||||||
return channel;
|
return channel;
|
||||||
@@ -104,15 +103,39 @@ LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long
|
|||||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size,
|
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size,
|
||||||
char *message, int message_len)
|
char *message, int message_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_CHANNEL *channel;
|
LIBSSH2_CHANNEL *channel = NULL;
|
||||||
unsigned long local_channel = libssh2_channel_nextid(session);
|
unsigned long local_channel = libssh2_channel_nextid(session);
|
||||||
unsigned char *s, *packet;
|
unsigned char *s, *packet = NULL;
|
||||||
unsigned long packet_len = channel_type_len + message_len + 17; /* packet_type(1) + channel_type_len(4) + sender_channel(4) +
|
unsigned long packet_len = channel_type_len + message_len + 17; /* packet_type(1) + channel_type_len(4) + sender_channel(4) +
|
||||||
window_size(4) + packet_size(4) */
|
window_size(4) + packet_size(4) */
|
||||||
unsigned char *data;
|
unsigned char *data = NULL;
|
||||||
unsigned long data_len;
|
unsigned long data_len;
|
||||||
int polls = 0;
|
int polls = 0;
|
||||||
|
|
||||||
|
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
|
||||||
|
if (!channel) {
|
||||||
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for channel data", 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
|
||||||
|
|
||||||
|
channel->channel_type_len = channel_type_len;
|
||||||
|
channel->channel_type = LIBSSH2_ALLOC(session, channel_type_len);
|
||||||
|
if (!channel->channel_type) {
|
||||||
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating memory for channel type name", 0);
|
||||||
|
LIBSSH2_FREE(session, channel);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(channel->channel_type, channel_type, channel_type_len);
|
||||||
|
|
||||||
|
/* REMEMBER: local as in locally sourced */
|
||||||
|
channel->local.id = local_channel;
|
||||||
|
channel->remote.window_size = window_size;
|
||||||
|
channel->remote.window_size_initial = window_size;
|
||||||
|
channel->remote.packet_size = packet_size;
|
||||||
|
|
||||||
|
libssh2_channel_add(session, channel);
|
||||||
|
|
||||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||||
if (!packet) {
|
if (!packet) {
|
||||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate temporary space for packet", 0);
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate temporary space for packet", 0);
|
||||||
@@ -132,8 +155,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
|
|||||||
|
|
||||||
if (libssh2_packet_write(session, packet, packet_len)) {
|
if (libssh2_packet_write(session, packet, packet_len)) {
|
||||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel-open request", 0);
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel-open request", 0);
|
||||||
LIBSSH2_FREE(session, packet);
|
goto channel_error;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
|
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
|
||||||
@@ -146,62 +168,62 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
|
|||||||
|
|
||||||
/* TODO: provide reason code and description */
|
/* TODO: provide reason code and description */
|
||||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0);
|
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0);
|
||||||
LIBSSH2_FREE(session, data);
|
goto channel_error;
|
||||||
LIBSSH2_FREE(session, packet);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
usleep(LIBSSH2_SOCKET_POLL_UDELAY);
|
usleep(LIBSSH2_SOCKET_POLL_UDELAY);
|
||||||
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
|
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
|
||||||
/* Give up waiting */
|
/* Give up waiting */
|
||||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timed out waiting for response", 0);
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timed out waiting for response", 0);
|
||||||
LIBSSH2_FREE(session, packet);
|
goto channel_error;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LIBSSH2_FREE(session, packet);
|
|
||||||
|
|
||||||
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
|
channel->remote.id = libssh2_ntohu32(data + 5);
|
||||||
if (!channel) {
|
|
||||||
/* Play nice and close that channel that we're not going to use after all */
|
|
||||||
data[3] = SSH_MSG_CHANNEL_CLOSE;
|
|
||||||
libssh2_packet_write(session, data + 3, 5);
|
|
||||||
|
|
||||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for channel data", 0);
|
|
||||||
LIBSSH2_FREE(session, data);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
|
|
||||||
|
|
||||||
channel->channel_type_len = channel_type_len;
|
|
||||||
channel->channel_type = LIBSSH2_ALLOC(session, channel_type_len);
|
|
||||||
if (!channel->channel_type) {
|
|
||||||
/* Play nice and close that channel that we're not going to use after all */
|
|
||||||
data[4] = SSH_MSG_CHANNEL_CLOSE;
|
|
||||||
libssh2_packet_write(session, data + 4, 5);
|
|
||||||
|
|
||||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating memory for channel type name", 0);
|
|
||||||
LIBSSH2_FREE(session, channel);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memcpy(channel->channel_type, channel_type, channel_type_len);
|
|
||||||
|
|
||||||
/* REMEMBER: local as in locally sourced */
|
|
||||||
channel->local.id = local_channel;
|
|
||||||
channel->local.window_size = libssh2_ntohu32(data + 9);
|
channel->local.window_size = libssh2_ntohu32(data + 9);
|
||||||
channel->local.window_size_initial = libssh2_ntohu32(data + 9);
|
channel->local.window_size_initial = libssh2_ntohu32(data + 9);
|
||||||
channel->local.packet_size = libssh2_ntohu32(data + 13);
|
channel->local.packet_size = libssh2_ntohu32(data + 13);
|
||||||
|
|
||||||
channel->remote.id = libssh2_ntohu32(data + 5);
|
LIBSSH2_FREE(session, packet);
|
||||||
channel->remote.window_size = window_size;
|
|
||||||
channel->remote.window_size_initial = window_size;
|
|
||||||
channel->remote.packet_size = packet_size;
|
|
||||||
|
|
||||||
LIBSSH2_FREE(session, data);
|
LIBSSH2_FREE(session, data);
|
||||||
|
|
||||||
libssh2_channel_add(session, channel);
|
|
||||||
|
|
||||||
return channel;
|
return channel;
|
||||||
|
|
||||||
|
channel_error:
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
LIBSSH2_FREE(session, data);
|
||||||
|
}
|
||||||
|
if (packet) {
|
||||||
|
LIBSSH2_FREE(session, packet);
|
||||||
|
}
|
||||||
|
if (channel) {
|
||||||
|
unsigned char channel_id[4];
|
||||||
|
LIBSSH2_FREE(session, channel->channel_type);
|
||||||
|
|
||||||
|
if (channel->next) {
|
||||||
|
channel->next->prev = channel->prev;
|
||||||
|
}
|
||||||
|
if (channel->prev) {
|
||||||
|
channel->prev->next = channel->next;
|
||||||
|
}
|
||||||
|
if (session->channels.head == channel) {
|
||||||
|
session->channels.head = channel->next;
|
||||||
|
}
|
||||||
|
if (session->channels.tail == channel) {
|
||||||
|
session->channels.tail = channel->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear out packets meant for this channel */
|
||||||
|
libssh2_htonu32(channel_id, channel->local.id);
|
||||||
|
while ((libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_DATA, &data, &data_len, 1, channel_id, 4, 1) >= 0) ||
|
||||||
|
(libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, &data_len, 1, channel_id, 4, 1) >= 0)) {
|
||||||
|
LIBSSH2_FREE(session, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBSSH2_FREE(session, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
@@ -210,6 +232,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
|
|||||||
*/
|
*/
|
||||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport)
|
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport)
|
||||||
{
|
{
|
||||||
|
LIBSSH2_CHANNEL *channel;
|
||||||
unsigned char *message, *s;
|
unsigned char *message, *s;
|
||||||
unsigned long host_len = strlen(host), shost_len = strlen(shost);
|
unsigned long host_len = strlen(host), shost_len = strlen(shost);
|
||||||
unsigned long message_len = host_len + shost_len + 16; /* host_len(4) + port(4) + shost_len(4) + sport(4) */
|
unsigned long message_len = host_len + shost_len + 16; /* host_len(4) + port(4) + shost_len(4) + sport(4) */
|
||||||
@@ -227,7 +250,10 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *se
|
|||||||
memcpy(s, shost, shost_len); s += shost_len;
|
memcpy(s, shost, shost_len); s += shost_len;
|
||||||
libssh2_htonu32(s, sport); s += 4;
|
libssh2_htonu32(s, sport); s += 4;
|
||||||
|
|
||||||
return libssh2_channel_open_ex(session, "direct-tcpip", sizeof("direct-tcpip") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, message, message_len);
|
channel = libssh2_channel_open_ex(session, "direct-tcpip", sizeof("direct-tcpip") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, message, message_len);
|
||||||
|
LIBSSH2_FREE(session, message);
|
||||||
|
|
||||||
|
return channel;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
@@ -434,23 +460,30 @@ LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int bloc
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ libssh2_channel_ignore_extended_data
|
/* {{{ libssh2_channel_flush_ex
|
||||||
* Ignore (or stop ignoring) extended data
|
* Flush data from one (or all) stream
|
||||||
|
* Returns number of bytes flushed, or -1 on failure
|
||||||
*/
|
*/
|
||||||
LIBSSH2_API void libssh2_channel_ignore_extended_data(LIBSSH2_CHANNEL *channel, int ignore)
|
LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid)
|
||||||
{
|
{
|
||||||
channel->remote.ignore_extended_data = ignore;
|
LIBSSH2_PACKET *packet = channel->session->packets.head;
|
||||||
|
unsigned long refund_bytes = 0, flush_bytes = 0;
|
||||||
|
|
||||||
if (ignore) {
|
while (packet) {
|
||||||
/* Flush queued extended data */
|
LIBSSH2_PACKET *next = packet->next;
|
||||||
LIBSSH2_PACKET *packet = channel->session->packets.head;
|
unsigned char packet_type = packet->data[0];
|
||||||
unsigned long refund_bytes = 0;
|
|
||||||
|
|
||||||
while (packet) {
|
if (((packet_type == SSH_MSG_CHANNEL_DATA) || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)) &&
|
||||||
LIBSSH2_PACKET *next = packet->next;
|
(libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
|
||||||
|
/* It's our channel at least */
|
||||||
|
if ((streamid == LIBSSH2_CHANNEL_FLUSH_ALL) ||
|
||||||
|
((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA) && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) || (streamid = libssh2_ntohu32(packet->data + 5)))) ||
|
||||||
|
((packet_type == SSH_MSG_CHANNEL_DATA) && (streamid == 0))) {
|
||||||
|
|
||||||
if ((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
|
/* It's one of the streams we wanted to flush */
|
||||||
refund_bytes += packet->data_len - 13;
|
refund_bytes += packet->data_len - 13;
|
||||||
|
flush_bytes += packet->data_len - packet->data_head;
|
||||||
|
|
||||||
LIBSSH2_FREE(channel->session, packet->data);
|
LIBSSH2_FREE(channel->session, packet->data);
|
||||||
if (packet->prev) {
|
if (packet->prev) {
|
||||||
packet->prev->next = packet->next;
|
packet->prev->next = packet->next;
|
||||||
@@ -464,23 +497,43 @@ LIBSSH2_API void libssh2_channel_ignore_extended_data(LIBSSH2_CHANNEL *channel,
|
|||||||
}
|
}
|
||||||
LIBSSH2_FREE(channel->session, packet);
|
LIBSSH2_FREE(channel->session, packet);
|
||||||
}
|
}
|
||||||
packet = next;
|
|
||||||
}
|
}
|
||||||
if (refund_bytes && channel->remote.window_size_initial) {
|
packet = next;
|
||||||
unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */
|
}
|
||||||
|
|
||||||
/* Adjust the window based on the block we just freed */
|
if (refund_bytes && channel->remote.window_size_initial) {
|
||||||
adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
|
unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */
|
||||||
libssh2_htonu32(adjust + 1, channel->remote.id);
|
|
||||||
libssh2_htonu32(adjust + 5, refund_bytes);
|
|
||||||
|
|
||||||
if (libssh2_packet_write(channel->session, adjust, 9)) {
|
/* Adjust the window based on the block we just freed */
|
||||||
libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0);
|
adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
|
||||||
} else {
|
libssh2_htonu32(adjust + 1, channel->remote.id);
|
||||||
channel->remote.window_size += refund_bytes;
|
libssh2_htonu32(adjust + 5, refund_bytes);
|
||||||
}
|
|
||||||
|
if (libssh2_packet_write(channel->session, adjust, 9)) {
|
||||||
|
libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
channel->remote.window_size += refund_bytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return flush_bytes;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_channel_handle_extended_data
|
||||||
|
* How should extended data look to the calling app?
|
||||||
|
* Keep it in separate channels[_read() _read_stdder()]? (NORMAL)
|
||||||
|
* Merge the extended data to the standard data? [everything via _read()]? (MERGE)
|
||||||
|
* Ignore it entirely [toss out packets as they come in]? (IGNORE)
|
||||||
|
*/
|
||||||
|
LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode)
|
||||||
|
{
|
||||||
|
channel->remote.extended_data_ignore_mode = ignore_mode;
|
||||||
|
|
||||||
|
if (ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) {
|
||||||
|
libssh2_channel_flush_ex(channel, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
@@ -493,17 +546,23 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
|||||||
int bytes_read = 0, blocking_read = 0;
|
int bytes_read = 0, blocking_read = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
LIBSSH2_PACKET *packet = session->packets.head;
|
LIBSSH2_PACKET *packet;
|
||||||
|
|
||||||
/* Process any waiting packets */
|
/* Process any waiting packets */
|
||||||
while (libssh2_packet_read(session, blocking_read) > 0) blocking_read = 0;
|
while (libssh2_packet_read(session, blocking_read) > 0) blocking_read = 0;
|
||||||
|
packet = session->packets.head;
|
||||||
|
|
||||||
while (packet && (bytes_read < buflen)) {
|
while (packet && (bytes_read < buflen)) {
|
||||||
/* In case packet gets destroyed during this iteration */
|
/* In case packet gets destroyed during this iteration */
|
||||||
LIBSSH2_PACKET *next = packet->next;
|
LIBSSH2_PACKET *next = packet->next;
|
||||||
|
|
||||||
|
/* Either we asked for a specific extended data stream (and data was available),
|
||||||
|
* or the standard stream (and data was available),
|
||||||
|
* or the standard stream with extended_data_merge enabled and data was available
|
||||||
|
*/
|
||||||
if ((stream_id && (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
|
if ((stream_id && (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
|
||||||
(!stream_id && (packet->data[0] == SSH_MSG_CHANNEL_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
|
(!stream_id && (packet->data[0] == SSH_MSG_CHANNEL_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
|
||||||
|
(!stream_id && (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1)) && (channel->remote.extended_data_ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
|
||||||
int want = buflen - bytes_read;
|
int want = buflen - bytes_read;
|
||||||
int unlink_packet = 0;
|
int unlink_packet = 0;
|
||||||
|
|
||||||
@@ -580,7 +639,7 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
|
|||||||
/* twiddle our thumbs until there's window space available */
|
/* twiddle our thumbs until there's window space available */
|
||||||
if (libssh2_packet_read(session, 1) < 0) {
|
if (libssh2_packet_read(session, 1) < 0) {
|
||||||
/* Error occured, disconnect? */
|
/* Error occured, disconnect? */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -675,6 +734,10 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (channel->close_cb) {
|
||||||
|
LIBSSH2_CHANNEL_CLOSE(session, channel);
|
||||||
|
}
|
||||||
|
|
||||||
packet[0] = SSH_MSG_CHANNEL_CLOSE;
|
packet[0] = SSH_MSG_CHANNEL_CLOSE;
|
||||||
libssh2_htonu32(packet + 1, channel->remote.id);
|
libssh2_htonu32(packet + 1, channel->remote.id);
|
||||||
if (libssh2_packet_write(session, packet, 5)) {
|
if (libssh2_packet_write(session, packet, 5)) {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@@ -485,7 +485,10 @@ LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* {{{ libssh2_hostkey_hash
|
/* {{{ libssh2_hostkey_hash
|
||||||
* Returns NULL terminated hash signature
|
* Returns hash signature
|
||||||
|
* Returned buffer should NOT be freed
|
||||||
|
* Length of buffer is determined by hash type
|
||||||
|
* i.e. MD5 == 16, SHA1 == 20
|
||||||
*/
|
*/
|
||||||
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type)
|
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type)
|
||||||
{
|
{
|
||||||
|
314
src/kex.c
314
src/kex.c
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@@ -671,16 +671,16 @@ static size_t libssh2_kex_method_list(unsigned char *buf, size_t list_strlen, LI
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
#define LIBSSH2_METHOD_PREFS \
|
#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) ((prefvar) ? strlen(prefvar) : libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar)))
|
||||||
LIBSSH2_KEX_METHOD **kex_prefs = session->kex_prefs ? session->kex_prefs : libssh2_kex_methods; \
|
#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \
|
||||||
LIBSSH2_HOSTKEY_METHOD **hostkey_prefs = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods(); \
|
if (prefvar) { \
|
||||||
LIBSSH2_CRYPT_METHOD **crypt_cs_prefs = session->local.crypt_prefs ? session->local.crypt_prefs : libssh2_crypt_methods(); \
|
libssh2_htonu32((buf), (prefvarlen)); \
|
||||||
LIBSSH2_CRYPT_METHOD **crypt_sc_prefs = session->remote.crypt_prefs ? session->remote.crypt_prefs : libssh2_crypt_methods(); \
|
buf += 4; \
|
||||||
LIBSSH2_COMP_METHOD **comp_cs_prefs = session->local.comp_prefs ? session->local.comp_prefs : libssh2_comp_methods(); \
|
memcpy((buf), (prefvar), (prefvarlen)); \
|
||||||
LIBSSH2_COMP_METHOD **comp_sc_prefs = session->remote.comp_prefs ? session->remote.comp_prefs : libssh2_comp_methods(); \
|
buf += (prefvarlen); \
|
||||||
LIBSSH2_MAC_METHOD **mac_cs_prefs = session->local.mac_prefs ? session->local.mac_prefs : libssh2_mac_methods(); \
|
} else { \
|
||||||
LIBSSH2_MAC_METHOD **mac_sc_prefs = session->remote.mac_prefs ? session->remote.mac_prefs : libssh2_mac_methods();
|
buf += libssh2_kex_method_list((buf), (prefvarlen), (LIBSSH2_COMMON_METHOD**)(defaultvar)); \
|
||||||
|
}
|
||||||
|
|
||||||
/* {{{ libssh2_kexinit
|
/* {{{ libssh2_kexinit
|
||||||
* Send SSH_MSG_KEXINIT packet
|
* Send SSH_MSG_KEXINIT packet
|
||||||
@@ -694,18 +694,17 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
|||||||
size_t mac_cs_len, mac_sc_len;
|
size_t mac_cs_len, mac_sc_len;
|
||||||
size_t lang_cs_len, lang_sc_len;
|
size_t lang_cs_len, lang_sc_len;
|
||||||
unsigned char *data, *s;
|
unsigned char *data, *s;
|
||||||
LIBSSH2_METHOD_PREFS
|
|
||||||
|
|
||||||
kex_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)kex_prefs);
|
kex_len = LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods);
|
||||||
hostkey_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)hostkey_prefs);
|
hostkey_len = LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs, libssh2_hostkey_methods());
|
||||||
crypt_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)crypt_cs_prefs);
|
crypt_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs, libssh2_crypt_methods());
|
||||||
crypt_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)crypt_sc_prefs);
|
crypt_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs, libssh2_crypt_methods());
|
||||||
mac_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)mac_cs_prefs);
|
mac_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs, libssh2_mac_methods());
|
||||||
mac_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)mac_sc_prefs);
|
mac_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs, libssh2_mac_methods());
|
||||||
comp_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)comp_cs_prefs);
|
comp_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs, libssh2_comp_methods());
|
||||||
comp_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)comp_sc_prefs);
|
comp_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs, libssh2_comp_methods());
|
||||||
lang_cs_len = 0; /* No langs in this version */
|
lang_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
|
||||||
lang_sc_len = 0; /* No langs in this version */
|
lang_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL);
|
||||||
|
|
||||||
data_len += kex_len + hostkey_len + \
|
data_len += kex_len + hostkey_len + \
|
||||||
crypt_cs_len + crypt_sc_len + \
|
crypt_cs_len + crypt_sc_len + \
|
||||||
@@ -726,16 +725,16 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
|||||||
s += 16;
|
s += 16;
|
||||||
|
|
||||||
/* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */
|
/* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */
|
||||||
s += libssh2_kex_method_list(s, kex_len, (LIBSSH2_COMMON_METHOD**)kex_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs, libssh2_kex_methods);
|
||||||
s += libssh2_kex_method_list(s, hostkey_len, (LIBSSH2_COMMON_METHOD**)hostkey_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs, libssh2_hostkey_methods());
|
||||||
s += libssh2_kex_method_list(s, crypt_cs_len, (LIBSSH2_COMMON_METHOD**)crypt_cs_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs, libssh2_crypt_methods());
|
||||||
s += libssh2_kex_method_list(s, crypt_sc_len, (LIBSSH2_COMMON_METHOD**)crypt_sc_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs, libssh2_crypt_methods());
|
||||||
s += libssh2_kex_method_list(s, mac_cs_len, (LIBSSH2_COMMON_METHOD**)mac_cs_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs, libssh2_mac_methods());
|
||||||
s += libssh2_kex_method_list(s, mac_sc_len, (LIBSSH2_COMMON_METHOD**)mac_sc_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs, libssh2_mac_methods());
|
||||||
s += libssh2_kex_method_list(s, comp_cs_len, (LIBSSH2_COMMON_METHOD**)comp_cs_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs, libssh2_comp_methods());
|
||||||
s += libssh2_kex_method_list(s, comp_sc_len, (LIBSSH2_COMMON_METHOD**)comp_sc_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs, libssh2_comp_methods());
|
||||||
s += libssh2_kex_method_list(s, lang_cs_len, NULL);
|
LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs, NULL);
|
||||||
s += libssh2_kex_method_list(s, lang_sc_len, NULL);
|
LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs, NULL);
|
||||||
|
|
||||||
/* No optimistic KEX packet follows */
|
/* No optimistic KEX packet follows */
|
||||||
/* Deal with optimistic packets
|
/* Deal with optimistic packets
|
||||||
@@ -803,14 +802,61 @@ static unsigned char *libssh2_kex_agree_instr(unsigned char *haystack, unsigned
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_get_method_by_name
|
||||||
|
*/
|
||||||
|
static LIBSSH2_COMMON_METHOD *libssh2_get_method_by_name(char *name, int name_len, LIBSSH2_COMMON_METHOD **methodlist)
|
||||||
|
{
|
||||||
|
while (*methodlist) {
|
||||||
|
if ((strlen((*methodlist)->name) == name_len) &&
|
||||||
|
(strncmp((*methodlist)->name, name, name_len) == 0)) {
|
||||||
|
return *methodlist;
|
||||||
|
}
|
||||||
|
methodlist++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ libssh2_kex_agree_hostkey
|
/* {{{ libssh2_kex_agree_hostkey
|
||||||
* Agree on a Hostkey which works with this kex
|
* Agree on a Hostkey which works with this kex
|
||||||
*/
|
*/
|
||||||
static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex_flags, unsigned char *hostkey, unsigned long hostkey_len)
|
static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex_flags, unsigned char *hostkey, unsigned long hostkey_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_HOSTKEY_METHOD **hostkeyp = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods();
|
LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
|
if (session->hostkey_prefs) {
|
||||||
|
s = session->hostkey_prefs;
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
unsigned char *p = strchr(s, ',');
|
||||||
|
int method_len = (p ? (p - s) : strlen(s));
|
||||||
|
if (libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
|
||||||
|
LIBSSH2_HOSTKEY_METHOD *method = (LIBSSH2_HOSTKEY_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)hostkeyp);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
/* Invalid method -- Should never be reached */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
|
||||||
|
if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) ||
|
||||||
|
(method->encrypt)) {
|
||||||
|
/* Either this hostkey can do encryption or this kex just doesn't require it */
|
||||||
|
if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) == 0) ||
|
||||||
|
(method->sig_verify)) {
|
||||||
|
/* Either this hostkey can do signing or this kex just doesn't require it */
|
||||||
|
session->hostkey = method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? p + 1 : NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while ((*hostkeyp)->name) {
|
while ((*hostkeyp)->name) {
|
||||||
s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*hostkeyp)->name));
|
s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*hostkeyp)->name));
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -839,9 +885,37 @@ static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex
|
|||||||
static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char *kex, unsigned long kex_len,
|
static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char *kex, unsigned long kex_len,
|
||||||
unsigned char *hostkey, unsigned long hostkey_len)
|
unsigned char *hostkey, unsigned long hostkey_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_KEX_METHOD **kexp = session->kex_prefs ? session->kex_prefs : libssh2_kex_methods;
|
LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
|
if (session->kex_prefs) {
|
||||||
|
s = session->kex_prefs;
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
unsigned char *p = strchr(s, ',');
|
||||||
|
int method_len = (p ? (p - s) : strlen(s));
|
||||||
|
if (libssh2_kex_agree_instr(kex, kex_len, s, method_len)) {
|
||||||
|
LIBSSH2_KEX_METHOD *method = (LIBSSH2_KEX_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)kexp);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
/* Invalid method -- Should never be reached */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We've agreed on a key exchange method,
|
||||||
|
* Can we agree on a hostkey that works with this kex?
|
||||||
|
*/
|
||||||
|
if (libssh2_kex_agree_hostkey(session, method->flags, hostkey, hostkey_len) == 0) {
|
||||||
|
session->kex = method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? p + 1 : NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while (*kexp && (*kexp)->name) {
|
while (*kexp && (*kexp)->name) {
|
||||||
s = libssh2_kex_agree_instr(kex, kex_len, (*kexp)->name, strlen((*kexp)->name));
|
s = libssh2_kex_agree_instr(kex, kex_len, (*kexp)->name, strlen((*kexp)->name));
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -864,9 +938,33 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
|
|||||||
*/
|
*/
|
||||||
static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *crypt, unsigned long crypt_len)
|
static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *crypt, unsigned long crypt_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_CRYPT_METHOD **cryptp = endpoint->crypt_prefs ? endpoint->crypt_prefs : libssh2_crypt_methods();
|
LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
|
if (endpoint->crypt_prefs) {
|
||||||
|
s = endpoint->crypt_prefs;
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
unsigned char *p = strchr(s, ',');
|
||||||
|
int method_len = (p ? (p - s) : strlen(s));
|
||||||
|
|
||||||
|
if (libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
|
||||||
|
LIBSSH2_CRYPT_METHOD *method = (LIBSSH2_CRYPT_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)cryptp);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
/* Invalid method -- Should never be reached */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint->crypt = method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? p + 1 : NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while ((*cryptp)->name) {
|
while ((*cryptp)->name) {
|
||||||
s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name));
|
s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name));
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -885,9 +983,33 @@ static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_da
|
|||||||
*/
|
*/
|
||||||
static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *mac, unsigned long mac_len)
|
static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *mac, unsigned long mac_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_MAC_METHOD **macp = endpoint->mac_prefs ? endpoint->mac_prefs : libssh2_mac_methods();
|
LIBSSH2_MAC_METHOD **macp = libssh2_mac_methods();
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
|
if (endpoint->mac_prefs) {
|
||||||
|
s = endpoint->mac_prefs;
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
unsigned char *p = strchr(s, ',');
|
||||||
|
int method_len = (p ? (p - s) : strlen(s));
|
||||||
|
|
||||||
|
if (libssh2_kex_agree_instr(mac, mac_len, s, method_len)) {
|
||||||
|
LIBSSH2_MAC_METHOD *method = (LIBSSH2_MAC_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)macp);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
/* Invalid method -- Should never be reached */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint->mac = method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? p + 1 : NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while ((*macp)->name) {
|
while ((*macp)->name) {
|
||||||
s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name));
|
s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name));
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -906,9 +1028,33 @@ static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data
|
|||||||
*/
|
*/
|
||||||
static int libssh2_kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *comp, unsigned long comp_len)
|
static int libssh2_kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *comp, unsigned long comp_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_COMP_METHOD **compp = endpoint->comp_prefs ? endpoint->comp_prefs : libssh2_comp_methods();
|
LIBSSH2_COMP_METHOD **compp = libssh2_comp_methods();
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
|
if (endpoint->comp_prefs) {
|
||||||
|
s = endpoint->comp_prefs;
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
unsigned char *p = strchr(s, ',');
|
||||||
|
int method_len = (p ? (p - s) : strlen(s));
|
||||||
|
|
||||||
|
if (libssh2_kex_agree_instr(comp, comp_len, s, method_len)) {
|
||||||
|
LIBSSH2_COMP_METHOD *method = (LIBSSH2_COMP_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)compp);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
/* Invalid method -- Should never be reached */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint->comp = method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? p + 1 : NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while ((*compp)->name) {
|
while ((*compp)->name) {
|
||||||
s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name));
|
s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name));
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -1054,3 +1200,97 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_session_method_pref
|
||||||
|
* Set preferred method
|
||||||
|
*/
|
||||||
|
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, char *prefs)
|
||||||
|
{
|
||||||
|
char **prefvar, *s, *newprefs;
|
||||||
|
int prefs_len = strlen(prefs);
|
||||||
|
LIBSSH2_COMMON_METHOD **mlist;
|
||||||
|
|
||||||
|
switch (method_type) {
|
||||||
|
case LIBSSH2_METHOD_KEX:
|
||||||
|
prefvar = &session->kex_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_kex_methods;
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_HOSTKEY:
|
||||||
|
prefvar = &session->hostkey_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_hostkey_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_CRYPT_CS:
|
||||||
|
prefvar = &session->local.crypt_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_crypt_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_CRYPT_SC:
|
||||||
|
prefvar = &session->remote.crypt_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_crypt_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_MAC_CS:
|
||||||
|
prefvar = &session->local.mac_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_mac_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_MAC_SC:
|
||||||
|
prefvar = &session->remote.mac_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_mac_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_COMP_CS:
|
||||||
|
prefvar = &session->local.comp_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_comp_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_COMP_SC:
|
||||||
|
prefvar = &session->remote.comp_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_comp_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_LANG_CS:
|
||||||
|
prefvar = &session->local.lang_prefs;
|
||||||
|
mlist = NULL;
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_LANG_SC:
|
||||||
|
prefvar = &session->remote.lang_prefs;
|
||||||
|
mlist = NULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1);
|
||||||
|
if (!newprefs) {
|
||||||
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Error allocated space for method preferences", 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(s, prefs, prefs_len + 1);
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
char *p = strchr(s, ',');
|
||||||
|
int method_len = p ? (p - s) : strlen(s);
|
||||||
|
|
||||||
|
if (!libssh2_get_method_by_name(s, method_len, mlist)) {
|
||||||
|
/* Strip out unsupported method */
|
||||||
|
if (p) {
|
||||||
|
memcpy(s, p + 1, strlen(s) - method_len);
|
||||||
|
} else {
|
||||||
|
if (s > newprefs) {
|
||||||
|
*(--s) = '\0';
|
||||||
|
} else {
|
||||||
|
*s = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? (p + 1) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(newprefs) == 0) {
|
||||||
|
LIBSSH2_FREE(session, newprefs);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*prefvar) {
|
||||||
|
LIBSSH2_FREE(session, *prefvar);
|
||||||
|
}
|
||||||
|
*prefvar = newprefs;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
|
35
src/misc.c
35
src/misc.c
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@@ -45,6 +45,21 @@ unsigned long libssh2_ntohu32(const unsigned char *buf)
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_ntohu64
|
||||||
|
* Note: Some 32-bit platforms have issues with bitops on long longs
|
||||||
|
* Work around this by doing expensive (but safer) arithmetic ops with optimization defying parentheses
|
||||||
|
*/
|
||||||
|
unsigned long long libssh2_ntohu64(const unsigned char *buf)
|
||||||
|
{
|
||||||
|
unsigned long msl, lsl;
|
||||||
|
|
||||||
|
msl = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||||
|
lsl = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
|
||||||
|
|
||||||
|
return ((msl * 65536) * 65536) + lsl;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ libssh2_htonu32
|
/* {{{ libssh2_htonu32
|
||||||
*/
|
*/
|
||||||
void libssh2_htonu32(unsigned char *buf, unsigned long value)
|
void libssh2_htonu32(unsigned char *buf, unsigned long value)
|
||||||
@@ -56,6 +71,24 @@ void libssh2_htonu32(unsigned char *buf, unsigned long value)
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_htonu64
|
||||||
|
*/
|
||||||
|
void libssh2_htonu64(unsigned char *buf, unsigned long long value)
|
||||||
|
{
|
||||||
|
unsigned long msl = (value / 65536) / 65536;
|
||||||
|
|
||||||
|
buf[0] = (msl >> 24) & 0xFF;
|
||||||
|
buf[1] = (msl >> 16) & 0xFF;
|
||||||
|
buf[2] = (msl >> 8) & 0xFF;
|
||||||
|
buf[3] = msl & 0xFF;
|
||||||
|
|
||||||
|
buf[4] = (value >> 24) & 0xFF;
|
||||||
|
buf[5] = (value >> 16) & 0xFF;
|
||||||
|
buf[6] = (value >> 8) & 0xFF;
|
||||||
|
buf[7] = value & 0xFF;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
/* Base64 Conversion */
|
/* Base64 Conversion */
|
||||||
|
|
||||||
/* {{{ */
|
/* {{{ */
|
||||||
|
32
src/packet.c
32
src/packet.c
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@@ -153,7 +153,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
|||||||
LIBSSH2_FREE(session, data);
|
LIBSSH2_FREE(session, data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (channel->remote.ignore_extended_data && (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
|
if ((channel->remote.extended_data_ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) && (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
|
||||||
/* Pretend we didn't receive this */
|
/* Pretend we didn't receive this */
|
||||||
LIBSSH2_FREE(session, data);
|
LIBSSH2_FREE(session, data);
|
||||||
|
|
||||||
@@ -317,7 +317,10 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
|||||||
|
|
||||||
fcntl(session->socket_fd, F_SETFL, O_NONBLOCK);
|
fcntl(session->socket_fd, F_SETFL, O_NONBLOCK);
|
||||||
if (session->newkeys) {
|
if (session->newkeys) {
|
||||||
unsigned char *block, *payload, *s, tmp[6];
|
/* Temporary Buffer
|
||||||
|
* The largest blocksize (currently) is 32, the largest MAC (currently) is 20
|
||||||
|
*/
|
||||||
|
unsigned char block[2 * 32], *payload, *s, tmp[6];
|
||||||
long read_len;
|
long read_len;
|
||||||
unsigned long blocksize = session->remote.crypt->blocksize;
|
unsigned long blocksize = session->remote.crypt->blocksize;
|
||||||
unsigned long packet_len, payload_len;
|
unsigned long packet_len, payload_len;
|
||||||
@@ -327,9 +330,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
|||||||
/* Safely ignored in CUSTOM cipher mode */
|
/* Safely ignored in CUSTOM cipher mode */
|
||||||
EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->remote.crypt_abstract;
|
EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->remote.crypt_abstract;
|
||||||
|
|
||||||
/* Temporary Buffer */
|
|
||||||
block = LIBSSH2_ALLOC(session, 2 * (blocksize > session->remote.mac->mac_len ? blocksize : session->remote.mac->mac_len));
|
|
||||||
|
|
||||||
/* Note: If we add any cipher with a blocksize less than 6 we'll need to get more creative with this
|
/* Note: If we add any cipher with a blocksize less than 6 we'll need to get more creative with this
|
||||||
* For now, all blocksize sizes are 8+
|
* For now, all blocksize sizes are 8+
|
||||||
*/
|
*/
|
||||||
@@ -338,13 +338,11 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
|||||||
} else {
|
} else {
|
||||||
read_len = read(session->socket_fd, block, 1);
|
read_len = read(session->socket_fd, block, 1);
|
||||||
if (read_len <= 0) {
|
if (read_len <= 0) {
|
||||||
LIBSSH2_FREE(session, block);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
read_len += libssh2_blocking_read(session, block + read_len, blocksize - read_len);
|
read_len += libssh2_blocking_read(session, block + read_len, blocksize - read_len);
|
||||||
}
|
}
|
||||||
if (read_len < blocksize) {
|
if (read_len < blocksize) {
|
||||||
LIBSSH2_FREE(session, block);
|
|
||||||
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
|
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +352,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
|||||||
} else {
|
} else {
|
||||||
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
|
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
|
||||||
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
|
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
|
||||||
LIBSSH2_FREE(session, block);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,6 +361,15 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
|||||||
memcpy(tmp, block, 5); /* Use this for MAC later */
|
memcpy(tmp, block, 5); /* Use this for MAC later */
|
||||||
|
|
||||||
payload_len = packet_len - 1; /* padding_len(1) */
|
payload_len = packet_len - 1; /* padding_len(1) */
|
||||||
|
/* Sanity Check */
|
||||||
|
if ((payload_len > LIBSSH2_PACKET_MAXPAYLOAD) ||
|
||||||
|
((packet_len + 4) % blocksize)) {
|
||||||
|
/* If something goes horribly wrong during the decryption phase, just bailout and die gracefully */
|
||||||
|
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
|
||||||
|
libssh2_error(session, LIBSSH2_ERROR_PROTO, "Fatal protocol error, invalid payload size", 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
s = payload = LIBSSH2_ALLOC(session, payload_len);
|
s = payload = LIBSSH2_ALLOC(session, payload_len);
|
||||||
memcpy(s, block + 5, blocksize - 5);
|
memcpy(s, block + 5, blocksize - 5);
|
||||||
s += blocksize - 5;
|
s += blocksize - 5;
|
||||||
@@ -371,7 +377,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
|||||||
while ((s - payload) < payload_len) {
|
while ((s - payload) < payload_len) {
|
||||||
read_len = libssh2_blocking_read(session, block, blocksize);
|
read_len = libssh2_blocking_read(session, block, blocksize);
|
||||||
if (read_len < blocksize) {
|
if (read_len < blocksize) {
|
||||||
LIBSSH2_FREE(session, block);
|
|
||||||
LIBSSH2_FREE(session, payload);
|
LIBSSH2_FREE(session, payload);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -381,7 +386,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
|||||||
} else {
|
} else {
|
||||||
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
|
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
|
||||||
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
|
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
|
||||||
LIBSSH2_FREE(session, block);
|
|
||||||
LIBSSH2_FREE(session, payload);
|
LIBSSH2_FREE(session, payload);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -393,7 +397,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
|||||||
|
|
||||||
read_len = libssh2_blocking_read(session, block, session->remote.mac->mac_len);
|
read_len = libssh2_blocking_read(session, block, session->remote.mac->mac_len);
|
||||||
if (read_len < session->remote.mac->mac_len) {
|
if (read_len < session->remote.mac->mac_len) {
|
||||||
LIBSSH2_FREE(session, block);
|
|
||||||
LIBSSH2_FREE(session, payload);
|
LIBSSH2_FREE(session, payload);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -402,13 +405,9 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
|||||||
session->remote.mac->hash(session, block + session->remote.mac->mac_len, session->remote.seqno, tmp, 5, payload, payload_len, &session->remote.mac_abstract);
|
session->remote.mac->hash(session, block + session->remote.mac->mac_len, session->remote.seqno, tmp, 5, payload, payload_len, &session->remote.mac_abstract);
|
||||||
|
|
||||||
macstate = (strncmp(block, block + session->remote.mac->mac_len, session->remote.mac->mac_len) == 0) ? LIBSSH2_MAC_CONFIRMED : LIBSSH2_MAC_INVALID;
|
macstate = (strncmp(block, block + session->remote.mac->mac_len, session->remote.mac->mac_len) == 0) ? LIBSSH2_MAC_CONFIRMED : LIBSSH2_MAC_INVALID;
|
||||||
/* SMG */
|
|
||||||
if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error!", 0);
|
|
||||||
|
|
||||||
session->remote.seqno++;
|
session->remote.seqno++;
|
||||||
|
|
||||||
LIBSSH2_FREE(session, block);
|
|
||||||
|
|
||||||
/* Ignore padding */
|
/* Ignore padding */
|
||||||
payload_len -= padding_len;
|
payload_len -= padding_len;
|
||||||
|
|
||||||
@@ -441,7 +440,6 @@ if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error
|
|||||||
payload = LIBSSH2_ALLOC(session, data_len);
|
payload = LIBSSH2_ALLOC(session, data_len);
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of uncompressed data", 0);
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of uncompressed data", 0);
|
||||||
LIBSSH2_FREE(session, block);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(payload, data, data_len);
|
memcpy(payload, data, data_len);
|
||||||
|
12
src/scp.c
12
src/scp.c
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@@ -76,6 +76,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
|||||||
LIBSSH2_FREE(session, command);
|
LIBSSH2_FREE(session, command);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/* Use blocking I/O for negotiation phase */
|
||||||
|
libssh2_channel_set_blocking(channel, 1);
|
||||||
|
|
||||||
/* Request SCP for the desired file */
|
/* Request SCP for the desired file */
|
||||||
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
||||||
@@ -307,7 +309,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
|||||||
sb->st_size = size;
|
sb->st_size = size;
|
||||||
sb->st_mode = mode;
|
sb->st_mode = mode;
|
||||||
}
|
}
|
||||||
/* Let the data BEGIN! */
|
/* Revert to non-blocking and let the data BEGIN! */
|
||||||
|
libssh2_channel_set_blocking(channel, 0);
|
||||||
|
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
@@ -347,6 +350,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
|||||||
LIBSSH2_FREE(session, command);
|
LIBSSH2_FREE(session, command);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/* Use blocking I/O for negotiation phase */
|
||||||
|
libssh2_channel_set_blocking(channel, 1);
|
||||||
|
|
||||||
/* Request SCP for the desired file */
|
/* Request SCP for the desired file */
|
||||||
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
||||||
@@ -400,7 +405,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ready to send file */
|
/* Ready to start, switch to non-blocking and let calling app send file */
|
||||||
|
libssh2_channel_set_blocking(channel, 0);
|
||||||
|
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
221
src/session.c
221
src/session.c
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@@ -160,6 +160,41 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_session_callback_set
|
||||||
|
* Set (or reset) a callback function
|
||||||
|
* Returns the prior address
|
||||||
|
*/
|
||||||
|
LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback)
|
||||||
|
{
|
||||||
|
void *oldcb;
|
||||||
|
|
||||||
|
switch (cbtype) {
|
||||||
|
case LIBSSH2_CALLBACK_IGNORE:
|
||||||
|
oldcb = session->ssh_msg_ignore;
|
||||||
|
session->ssh_msg_ignore = callback;
|
||||||
|
return oldcb;
|
||||||
|
break;
|
||||||
|
case LIBSSH2_CALLBACK_DEBUG:
|
||||||
|
oldcb = session->ssh_msg_debug;
|
||||||
|
session->ssh_msg_debug = callback;
|
||||||
|
return oldcb;
|
||||||
|
break;
|
||||||
|
case LIBSSH2_CALLBACK_DISCONNECT:
|
||||||
|
oldcb = session->ssh_msg_disconnect;
|
||||||
|
session->ssh_msg_disconnect = callback;
|
||||||
|
return oldcb;
|
||||||
|
break;
|
||||||
|
case LIBSSH2_CALLBACK_MACERROR:
|
||||||
|
oldcb = session->macerror;
|
||||||
|
session->macerror = callback;
|
||||||
|
return oldcb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ proto libssh2_session_startup
|
/* {{{ proto libssh2_session_startup
|
||||||
* session: LIBSSH2_SESSION struct allocated and owned by the calling program
|
* session: LIBSSH2_SESSION struct allocated and owned by the calling program
|
||||||
* Returns: 0 on success, or non-zero on failure
|
* Returns: 0 on success, or non-zero on failure
|
||||||
@@ -303,6 +338,7 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free banner(s) */
|
||||||
if (session->remote.banner) {
|
if (session->remote.banner) {
|
||||||
LIBSSH2_FREE(session, session->remote.banner);
|
LIBSSH2_FREE(session, session->remote.banner);
|
||||||
}
|
}
|
||||||
@@ -310,6 +346,40 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
|||||||
LIBSSH2_FREE(session, session->local.banner);
|
LIBSSH2_FREE(session, session->local.banner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free preference(s) */
|
||||||
|
if (session->kex_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->kex_prefs);
|
||||||
|
}
|
||||||
|
if (session->hostkey_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->hostkey_prefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->local.crypt_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->local.crypt_prefs);
|
||||||
|
}
|
||||||
|
if (session->local.mac_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->local.mac_prefs);
|
||||||
|
}
|
||||||
|
if (session->local.comp_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->local.comp_prefs);
|
||||||
|
}
|
||||||
|
if (session->local.lang_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->local.lang_prefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->remote.crypt_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->remote.crypt_prefs);
|
||||||
|
}
|
||||||
|
if (session->remote.mac_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->remote.mac_prefs);
|
||||||
|
}
|
||||||
|
if (session->remote.comp_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->remote.comp_prefs);
|
||||||
|
}
|
||||||
|
if (session->remote.lang_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->remote.lang_prefs);
|
||||||
|
}
|
||||||
|
|
||||||
/* Cleanup any remaining packets */
|
/* Cleanup any remaining packets */
|
||||||
while (session->packets.head) {
|
while (session->packets.head) {
|
||||||
LIBSSH2_PACKET *tmp = session->packets.head;
|
LIBSSH2_PACKET *tmp = session->packets.head;
|
||||||
@@ -332,9 +402,9 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
|||||||
|
|
||||||
/* {{{ libssh2_session_disconnect_ex
|
/* {{{ libssh2_session_disconnect_ex
|
||||||
*/
|
*/
|
||||||
LIBSSH2_API void libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang)
|
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang)
|
||||||
{
|
{
|
||||||
unsigned char *data;
|
unsigned char *s, *data;
|
||||||
unsigned long data_len, descr_len = 0, lang_len = 0;
|
unsigned long data_len, descr_len = 0, lang_len = 0;
|
||||||
|
|
||||||
if (description) {
|
if (description) {
|
||||||
@@ -345,28 +415,139 @@ LIBSSH2_API void libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int rea
|
|||||||
}
|
}
|
||||||
data_len = descr_len + lang_len + 13; /* packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
|
data_len = descr_len + lang_len + 13; /* packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
|
||||||
|
|
||||||
data = LIBSSH2_ALLOC(session, data_len);
|
s = data = LIBSSH2_ALLOC(session, data_len);
|
||||||
if (data) {
|
if (!data) {
|
||||||
unsigned char *s = data;
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for disconnect packet", 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
*(s++) = SSH_MSG_DISCONNECT;
|
*(s++) = SSH_MSG_DISCONNECT;
|
||||||
libssh2_htonu32(s, reason); s += 4;
|
libssh2_htonu32(s, reason); s += 4;
|
||||||
|
|
||||||
libssh2_htonu32(s, descr_len); s += 4;
|
libssh2_htonu32(s, descr_len); s += 4;
|
||||||
if (description) {
|
if (description) {
|
||||||
memcpy(s, description, descr_len);
|
memcpy(s, description, descr_len);
|
||||||
s += descr_len;
|
s += descr_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
libssh2_htonu32(s, lang_len); s += 4;
|
libssh2_htonu32(s, lang_len); s += 4;
|
||||||
if (lang) {
|
if (lang) {
|
||||||
memcpy(s, lang, lang_len);
|
memcpy(s, lang, lang_len);
|
||||||
s += lang_len;
|
s += lang_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
libssh2_packet_write(session, data, data_len);
|
libssh2_packet_write(session, data, data_len);
|
||||||
|
|
||||||
LIBSSH2_FREE(session, data);
|
LIBSSH2_FREE(session, data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_session_methods
|
||||||
|
* Return the currently active methods
|
||||||
|
* NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
|
||||||
|
* Strings should NOT be freed
|
||||||
|
*/
|
||||||
|
LIBSSH2_API void libssh2_session_methods(LIBSSH2_SESSION *session, char **kex, char **hostkey,
|
||||||
|
char **crypt_cs, char **crypt_sc,
|
||||||
|
char **mac_cs, char **mac_sc,
|
||||||
|
char **comp_cs, char **comp_sc,
|
||||||
|
char **lang_cs, char **lang_sc)
|
||||||
|
{
|
||||||
|
if (kex) {
|
||||||
|
*kex = session->kex->name;
|
||||||
|
}
|
||||||
|
if (hostkey) {
|
||||||
|
*hostkey = session->hostkey->name;
|
||||||
|
}
|
||||||
|
if (crypt_cs) {
|
||||||
|
*crypt_cs = session->local.crypt->name;
|
||||||
|
}
|
||||||
|
if (crypt_sc) {
|
||||||
|
*crypt_sc = session->remote.crypt->name;
|
||||||
|
}
|
||||||
|
if (mac_cs) {
|
||||||
|
*mac_cs = session->local.mac->name;
|
||||||
|
}
|
||||||
|
if (mac_sc) {
|
||||||
|
*mac_sc = session->remote.mac->name;
|
||||||
|
}
|
||||||
|
if (comp_cs) {
|
||||||
|
*comp_cs = session->local.comp->name;
|
||||||
|
}
|
||||||
|
if (comp_sc) {
|
||||||
|
*comp_sc = session->remote.comp->name;
|
||||||
|
}
|
||||||
|
if (lang_cs) {
|
||||||
|
*lang_cs = "";
|
||||||
|
}
|
||||||
|
if (lang_sc) {
|
||||||
|
*lang_sc = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_session_abstract
|
||||||
|
* Retreive a pointer to the abstract property
|
||||||
|
*/
|
||||||
|
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session)
|
||||||
|
{
|
||||||
|
return &session->abstract;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_session_last_error
|
||||||
|
* Returns error code and populates an error string into errmsg
|
||||||
|
* If want_buf is non-zero then the string placed into errmsg must be freed by the calling program
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
/* No error to report */
|
||||||
|
if (!session->err_code) {
|
||||||
|
if (errmsg) {
|
||||||
|
if (want_buf) {
|
||||||
|
*errmsg = LIBSSH2_ALLOC(session, 1);
|
||||||
|
if (*errmsg) {
|
||||||
|
**errmsg = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*errmsg = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errmsg_len) {
|
||||||
|
*errmsg_len = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errmsg) {
|
||||||
|
char *serrmsg = session->err_msg ? session->err_msg : "";
|
||||||
|
int ownbuf = session->err_msg ? session->err_should_free : 0;
|
||||||
|
|
||||||
|
if (want_buf) {
|
||||||
|
if (ownbuf) {
|
||||||
|
/* Just give the calling program the buffer */
|
||||||
|
*errmsg = serrmsg;
|
||||||
|
session->err_should_free = 0;
|
||||||
|
} else {
|
||||||
|
/* Make a copy so the calling program can own it */
|
||||||
|
*errmsg = LIBSSH2_ALLOC(session, session->err_msglen + 1);
|
||||||
|
if (*errmsg) {
|
||||||
|
memcpy(*errmsg, session->err_msg, session->err_msglen);
|
||||||
|
(*errmsg)[session->err_msglen] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*errmsg = serrmsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errmsg_len) {
|
||||||
|
*errmsg_len = session->err_msglen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session->err_code;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
1349
src/sftp.c
Normal file
1349
src/sftp.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms,
|
* Redistribution and use in source and binary forms,
|
||||||
@@ -300,7 +300,7 @@ static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKE
|
|||||||
char *method, int method_len,
|
char *method, int method_len,
|
||||||
char *privkeyfile, char *passphrase)
|
char *privkeyfile, char *passphrase)
|
||||||
{
|
{
|
||||||
LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods();
|
LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods();
|
||||||
|
|
||||||
*hostkey_method = NULL;
|
*hostkey_method = NULL;
|
||||||
*hostkey_abstract = NULL;
|
*hostkey_abstract = NULL;
|
||||||
|
Reference in New Issue
Block a user