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.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
|
@@ -10,7 +10,7 @@ CC = @CC@
|
||||
CFLAGS = -c @CFLAGS@ -Iinclude/ -Wall -g
|
||||
LIBS = -lssh2 -Lsrc/
|
||||
INSTALL = @INSTALL@
|
||||
VERSION=0.1
|
||||
VERSION=0.3
|
||||
DISTLIB=libssh2-$(VERSION)
|
||||
|
||||
all:
|
||||
@@ -28,6 +28,7 @@ install:
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
$(INSTALL) -m 644 include/libssh2.h $(incldir)/
|
||||
$(INSTALL) -m 644 include/libssh2_sftp.h $(incldir)/
|
||||
clean:
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) clean) \
|
||||
@@ -44,5 +45,6 @@ dist:
|
||||
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \
|
||||
$(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh \
|
||||
$(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)
|
||||
|
50
README
50
README
@@ -1,8 +1,54 @@
|
||||
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:
|
||||
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
|
||||
* hmac-md5, hmac-md5-96
|
||||
* SFTP support
|
||||
* Review callbacks
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# 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_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.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -42,7 +42,8 @@
|
||||
#include <string.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 */
|
||||
#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_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 */
|
||||
#define LIBSSH2_DH_GEX_NEW
|
||||
|
||||
@@ -71,10 +117,13 @@
|
||||
#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120
|
||||
|
||||
/* 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 */
|
||||
#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 */
|
||||
#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_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_CHANNEL LIBSSH2_CHANNEL;
|
||||
|
||||
@@ -148,18 +217,31 @@ typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
||||
#define LIBSSH2_ERROR_SCP_PROTOCOL -28
|
||||
#define LIBSSH2_ERROR_ZLIB -29
|
||||
#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30
|
||||
#define LIBSSH2_ERROR_SFTP_PROTOCOL -31
|
||||
|
||||
/* 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);
|
||||
#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 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), "")
|
||||
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session);
|
||||
|
||||
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 */
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len);
|
||||
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_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);
|
||||
#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);
|
||||
@@ -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_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);
|
||||
#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))
|
||||
@@ -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))
|
||||
|
||||
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_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.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -55,7 +55,9 @@
|
||||
#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)
|
||||
|
||||
#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_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD;
|
||||
@@ -98,7 +100,7 @@ typedef struct _libssh2_channel_data {
|
||||
unsigned long window_size_initial, window_size, packet_size;
|
||||
|
||||
/* 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;
|
||||
|
||||
struct _LIBSSH2_CHANNEL {
|
||||
@@ -112,6 +114,9 @@ struct _LIBSSH2_CHANNEL {
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
LIBSSH2_CHANNEL *next, *prev;
|
||||
|
||||
void *abstract;
|
||||
LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
|
||||
};
|
||||
|
||||
struct _LIBSSH2_CHANNEL_BRIGADE {
|
||||
@@ -135,9 +140,10 @@ typedef struct _libssh2_endpoint_data {
|
||||
void *comp_abstract;
|
||||
|
||||
/* Method Preferences -- NULL yields "load order" */
|
||||
LIBSSH2_CRYPT_METHOD **crypt_prefs;
|
||||
LIBSSH2_MAC_METHOD **mac_prefs;
|
||||
LIBSSH2_COMP_METHOD **comp_prefs;
|
||||
char *crypt_prefs;
|
||||
char *mac_prefs;
|
||||
char *comp_prefs;
|
||||
char *lang_prefs;
|
||||
} libssh2_endpoint_data;
|
||||
|
||||
struct _LIBSSH2_SESSION {
|
||||
@@ -154,8 +160,8 @@ struct _LIBSSH2_SESSION {
|
||||
LIBSSH2_MACERROR_FUNC((*macerror));
|
||||
|
||||
/* Method preferences -- NULL yields "load order" */
|
||||
LIBSSH2_KEX_METHOD **kex_prefs;
|
||||
LIBSSH2_HOSTKEY_METHOD **hostkey_prefs;
|
||||
char *kex_prefs;
|
||||
char *hostkey_prefs;
|
||||
|
||||
int exchanging_keys;
|
||||
int newkeys;
|
||||
@@ -354,7 +360,9 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
void libssh2_session_shutdown(LIBSSH2_SESSION *session);
|
||||
|
||||
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_htonu64(unsigned char *buf, unsigned long long val);
|
||||
|
||||
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);
|
||||
|
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@
|
||||
prefix = @prefix@
|
||||
@@ -42,6 +42,9 @@ scp.o: scp.c
|
||||
session.o: session.c
|
||||
$(CC) -o session.o session.c $(CFLAGS) $(LIBS)
|
||||
|
||||
sftp.o: sftp.c
|
||||
$(CC) -o sftp.o sftp.c $(CFLAGS) $(LIBS)
|
||||
|
||||
userauth.o: userauth.c
|
||||
$(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.
|
||||
*
|
||||
* 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 *channel = session->channels.head;
|
||||
|
||||
while (channel) {
|
||||
if (channel->local.id == channel_id) {
|
||||
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,
|
||||
char *message, int message_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
LIBSSH2_CHANNEL *channel = NULL;
|
||||
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) +
|
||||
window_size(4) + packet_size(4) */
|
||||
unsigned char *data;
|
||||
unsigned char *data = NULL;
|
||||
unsigned long data_len;
|
||||
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);
|
||||
if (!packet) {
|
||||
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)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel-open request", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return NULL;
|
||||
goto channel_error;
|
||||
}
|
||||
|
||||
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 */
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return NULL;
|
||||
goto channel_error;
|
||||
}
|
||||
usleep(LIBSSH2_SOCKET_POLL_UDELAY);
|
||||
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
|
||||
/* Give up waiting */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timed out waiting for response", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return NULL;
|
||||
goto channel_error;
|
||||
}
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
|
||||
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->remote.id = libssh2_ntohu32(data + 5);
|
||||
channel->local.window_size = libssh2_ntohu32(data + 9);
|
||||
channel->local.window_size_initial = libssh2_ntohu32(data + 9);
|
||||
channel->local.packet_size = libssh2_ntohu32(data + 13);
|
||||
|
||||
channel->remote.id = libssh2_ntohu32(data + 5);
|
||||
channel->remote.window_size = window_size;
|
||||
channel->remote.window_size_initial = window_size;
|
||||
channel->remote.packet_size = packet_size;
|
||||
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
libssh2_channel_add(session, 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_CHANNEL *channel;
|
||||
unsigned char *message, *s;
|
||||
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) */
|
||||
@@ -227,7 +250,10 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *se
|
||||
memcpy(s, shost, shost_len); s += shost_len;
|
||||
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
|
||||
* Ignore (or stop ignoring) extended data
|
||||
/* {{{ libssh2_channel_flush_ex
|
||||
* 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) {
|
||||
/* Flush queued extended data */
|
||||
LIBSSH2_PACKET *packet = channel->session->packets.head;
|
||||
unsigned long refund_bytes = 0;
|
||||
while (packet) {
|
||||
LIBSSH2_PACKET *next = packet->next;
|
||||
unsigned char packet_type = packet->data[0];
|
||||
|
||||
while (packet) {
|
||||
LIBSSH2_PACKET *next = packet->next;
|
||||
if (((packet_type == SSH_MSG_CHANNEL_DATA) || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)) &&
|
||||
(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;
|
||||
flush_bytes += packet->data_len - packet->data_head;
|
||||
|
||||
LIBSSH2_FREE(channel->session, packet->data);
|
||||
if (packet->prev) {
|
||||
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);
|
||||
}
|
||||
packet = next;
|
||||
}
|
||||
if (refund_bytes && channel->remote.window_size_initial) {
|
||||
unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */
|
||||
packet = next;
|
||||
}
|
||||
|
||||
/* Adjust the window based on the block we just freed */
|
||||
adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
|
||||
libssh2_htonu32(adjust + 1, channel->remote.id);
|
||||
libssh2_htonu32(adjust + 5, refund_bytes);
|
||||
if (refund_bytes && channel->remote.window_size_initial) {
|
||||
unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */
|
||||
|
||||
if (libssh2_packet_write(channel->session, adjust, 9)) {
|
||||
libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0);
|
||||
} else {
|
||||
channel->remote.window_size += refund_bytes;
|
||||
}
|
||||
/* Adjust the window based on the block we just freed */
|
||||
adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
|
||||
libssh2_htonu32(adjust + 1, channel->remote.id);
|
||||
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;
|
||||
|
||||
do {
|
||||
LIBSSH2_PACKET *packet = session->packets.head;
|
||||
LIBSSH2_PACKET *packet;
|
||||
|
||||
/* Process any waiting packets */
|
||||
while (libssh2_packet_read(session, blocking_read) > 0) blocking_read = 0;
|
||||
packet = session->packets.head;
|
||||
|
||||
while (packet && (bytes_read < buflen)) {
|
||||
/* In case packet gets destroyed during this iteration */
|
||||
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))) ||
|
||||
(!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 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 */
|
||||
if (libssh2_packet_read(session, 1) < 0) {
|
||||
/* Error occured, disconnect? */
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,6 +734,10 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (channel->close_cb) {
|
||||
LIBSSH2_CHANNEL_CLOSE(session, channel);
|
||||
}
|
||||
|
||||
packet[0] = SSH_MSG_CHANNEL_CLOSE;
|
||||
libssh2_htonu32(packet + 1, channel->remote.id);
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -485,7 +485,10 @@ LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void)
|
||||
}
|
||||
|
||||
/* {{{ 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)
|
||||
{
|
||||
|
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.
|
||||
*
|
||||
* 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 \
|
||||
LIBSSH2_KEX_METHOD **kex_prefs = session->kex_prefs ? session->kex_prefs : libssh2_kex_methods; \
|
||||
LIBSSH2_HOSTKEY_METHOD **hostkey_prefs = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods(); \
|
||||
LIBSSH2_CRYPT_METHOD **crypt_cs_prefs = session->local.crypt_prefs ? session->local.crypt_prefs : libssh2_crypt_methods(); \
|
||||
LIBSSH2_CRYPT_METHOD **crypt_sc_prefs = session->remote.crypt_prefs ? session->remote.crypt_prefs : libssh2_crypt_methods(); \
|
||||
LIBSSH2_COMP_METHOD **comp_cs_prefs = session->local.comp_prefs ? session->local.comp_prefs : libssh2_comp_methods(); \
|
||||
LIBSSH2_COMP_METHOD **comp_sc_prefs = session->remote.comp_prefs ? session->remote.comp_prefs : libssh2_comp_methods(); \
|
||||
LIBSSH2_MAC_METHOD **mac_cs_prefs = session->local.mac_prefs ? session->local.mac_prefs : libssh2_mac_methods(); \
|
||||
LIBSSH2_MAC_METHOD **mac_sc_prefs = session->remote.mac_prefs ? session->remote.mac_prefs : libssh2_mac_methods();
|
||||
|
||||
#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) ((prefvar) ? strlen(prefvar) : libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar)))
|
||||
#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \
|
||||
if (prefvar) { \
|
||||
libssh2_htonu32((buf), (prefvarlen)); \
|
||||
buf += 4; \
|
||||
memcpy((buf), (prefvar), (prefvarlen)); \
|
||||
buf += (prefvarlen); \
|
||||
} else { \
|
||||
buf += libssh2_kex_method_list((buf), (prefvarlen), (LIBSSH2_COMMON_METHOD**)(defaultvar)); \
|
||||
}
|
||||
|
||||
/* {{{ libssh2_kexinit
|
||||
* 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 lang_cs_len, lang_sc_len;
|
||||
unsigned char *data, *s;
|
||||
LIBSSH2_METHOD_PREFS
|
||||
|
||||
kex_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)kex_prefs);
|
||||
hostkey_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)hostkey_prefs);
|
||||
crypt_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)crypt_cs_prefs);
|
||||
crypt_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)crypt_sc_prefs);
|
||||
mac_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)mac_cs_prefs);
|
||||
mac_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)mac_sc_prefs);
|
||||
comp_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)comp_cs_prefs);
|
||||
comp_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)comp_sc_prefs);
|
||||
lang_cs_len = 0; /* No langs in this version */
|
||||
lang_sc_len = 0; /* No langs in this version */
|
||||
kex_len = LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods);
|
||||
hostkey_len = LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs, libssh2_hostkey_methods());
|
||||
crypt_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs, libssh2_crypt_methods());
|
||||
crypt_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs, libssh2_crypt_methods());
|
||||
mac_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs, libssh2_mac_methods());
|
||||
mac_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs, libssh2_mac_methods());
|
||||
comp_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs, libssh2_comp_methods());
|
||||
comp_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs, libssh2_comp_methods());
|
||||
lang_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
|
||||
lang_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL);
|
||||
|
||||
data_len += kex_len + hostkey_len + \
|
||||
crypt_cs_len + crypt_sc_len + \
|
||||
@@ -726,16 +725,16 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
||||
s += 16;
|
||||
|
||||
/* 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);
|
||||
s += libssh2_kex_method_list(s, hostkey_len, (LIBSSH2_COMMON_METHOD**)hostkey_prefs);
|
||||
s += libssh2_kex_method_list(s, crypt_cs_len, (LIBSSH2_COMMON_METHOD**)crypt_cs_prefs);
|
||||
s += libssh2_kex_method_list(s, crypt_sc_len, (LIBSSH2_COMMON_METHOD**)crypt_sc_prefs);
|
||||
s += libssh2_kex_method_list(s, mac_cs_len, (LIBSSH2_COMMON_METHOD**)mac_cs_prefs);
|
||||
s += libssh2_kex_method_list(s, mac_sc_len, (LIBSSH2_COMMON_METHOD**)mac_sc_prefs);
|
||||
s += libssh2_kex_method_list(s, comp_cs_len, (LIBSSH2_COMMON_METHOD**)comp_cs_prefs);
|
||||
s += libssh2_kex_method_list(s, comp_sc_len, (LIBSSH2_COMMON_METHOD**)comp_sc_prefs);
|
||||
s += libssh2_kex_method_list(s, lang_cs_len, NULL);
|
||||
s += libssh2_kex_method_list(s, lang_sc_len, NULL);
|
||||
LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs, libssh2_kex_methods);
|
||||
LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs, libssh2_hostkey_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs, libssh2_crypt_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs, libssh2_crypt_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs, libssh2_mac_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs, libssh2_mac_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs, libssh2_comp_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs, libssh2_comp_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs, NULL);
|
||||
LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs, NULL);
|
||||
|
||||
/* No optimistic KEX packet follows */
|
||||
/* 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
|
||||
* 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)
|
||||
{
|
||||
LIBSSH2_HOSTKEY_METHOD **hostkeyp = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods();
|
||||
LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
|
||||
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) {
|
||||
s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*hostkeyp)->name));
|
||||
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,
|
||||
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;
|
||||
|
||||
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) {
|
||||
s = libssh2_kex_agree_instr(kex, kex_len, (*kexp)->name, strlen((*kexp)->name));
|
||||
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)
|
||||
{
|
||||
LIBSSH2_CRYPT_METHOD **cryptp = endpoint->crypt_prefs ? endpoint->crypt_prefs : libssh2_crypt_methods();
|
||||
LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
|
||||
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) {
|
||||
s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name));
|
||||
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)
|
||||
{
|
||||
LIBSSH2_MAC_METHOD **macp = endpoint->mac_prefs ? endpoint->mac_prefs : libssh2_mac_methods();
|
||||
LIBSSH2_MAC_METHOD **macp = libssh2_mac_methods();
|
||||
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) {
|
||||
s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name));
|
||||
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)
|
||||
{
|
||||
LIBSSH2_COMP_METHOD **compp = endpoint->comp_prefs ? endpoint->comp_prefs : libssh2_comp_methods();
|
||||
LIBSSH2_COMP_METHOD **compp = libssh2_comp_methods();
|
||||
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) {
|
||||
s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name));
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
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 */
|
||||
|
||||
/* {{{ */
|
||||
|
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.
|
||||
*
|
||||
* 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);
|
||||
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 */
|
||||
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);
|
||||
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;
|
||||
unsigned long blocksize = session->remote.crypt->blocksize;
|
||||
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 */
|
||||
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
|
||||
* For now, all blocksize sizes are 8+
|
||||
*/
|
||||
@@ -338,13 +338,11 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
} else {
|
||||
read_len = read(session->socket_fd, block, 1);
|
||||
if (read_len <= 0) {
|
||||
LIBSSH2_FREE(session, block);
|
||||
return 0;
|
||||
}
|
||||
read_len += libssh2_blocking_read(session, block + read_len, blocksize - read_len);
|
||||
}
|
||||
if (read_len < blocksize) {
|
||||
LIBSSH2_FREE(session, block);
|
||||
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
|
||||
}
|
||||
|
||||
@@ -354,7 +352,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
} else {
|
||||
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
|
||||
LIBSSH2_FREE(session, block);
|
||||
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 */
|
||||
|
||||
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);
|
||||
memcpy(s, block + 5, blocksize - 5);
|
||||
s += blocksize - 5;
|
||||
@@ -371,7 +377,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
while ((s - payload) < payload_len) {
|
||||
read_len = libssh2_blocking_read(session, block, blocksize);
|
||||
if (read_len < blocksize) {
|
||||
LIBSSH2_FREE(session, block);
|
||||
LIBSSH2_FREE(session, payload);
|
||||
return -1;
|
||||
}
|
||||
@@ -381,7 +386,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
} else {
|
||||
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
|
||||
LIBSSH2_FREE(session, block);
|
||||
LIBSSH2_FREE(session, payload);
|
||||
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);
|
||||
if (read_len < session->remote.mac->mac_len) {
|
||||
LIBSSH2_FREE(session, block);
|
||||
LIBSSH2_FREE(session, payload);
|
||||
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);
|
||||
|
||||
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++;
|
||||
|
||||
LIBSSH2_FREE(session, block);
|
||||
|
||||
/* Ignore padding */
|
||||
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);
|
||||
if (!payload) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of uncompressed data", 0);
|
||||
LIBSSH2_FREE(session, block);
|
||||
return -1;
|
||||
}
|
||||
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.
|
||||
*
|
||||
* 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);
|
||||
return NULL;
|
||||
}
|
||||
/* Use blocking I/O for negotiation phase */
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
|
||||
/* Request SCP for the desired file */
|
||||
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
||||
@@ -307,7 +309,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
sb->st_size = size;
|
||||
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;
|
||||
}
|
||||
@@ -347,6 +350,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
LIBSSH2_FREE(session, command);
|
||||
return NULL;
|
||||
}
|
||||
/* Use blocking I/O for negotiation phase */
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
|
||||
/* Request SCP for the desired file */
|
||||
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
||||
@@ -400,7 +405,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
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;
|
||||
}
|
||||
|
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.
|
||||
*
|
||||
* 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
|
||||
* session: LIBSSH2_SESSION struct allocated and owned by the calling program
|
||||
* 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
while (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_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;
|
||||
|
||||
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 = LIBSSH2_ALLOC(session, data_len);
|
||||
if (data) {
|
||||
unsigned char *s = data;
|
||||
s = data = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!data) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for disconnect packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(s++) = SSH_MSG_DISCONNECT;
|
||||
libssh2_htonu32(s, reason); s += 4;
|
||||
*(s++) = SSH_MSG_DISCONNECT;
|
||||
libssh2_htonu32(s, reason); s += 4;
|
||||
|
||||
libssh2_htonu32(s, descr_len); s += 4;
|
||||
if (description) {
|
||||
memcpy(s, description, descr_len);
|
||||
s += descr_len;
|
||||
}
|
||||
libssh2_htonu32(s, descr_len); s += 4;
|
||||
if (description) {
|
||||
memcpy(s, description, descr_len);
|
||||
s += descr_len;
|
||||
}
|
||||
|
||||
libssh2_htonu32(s, lang_len); s += 4;
|
||||
if (lang) {
|
||||
memcpy(s, lang, lang_len);
|
||||
s += lang_len;
|
||||
}
|
||||
libssh2_htonu32(s, lang_len); s += 4;
|
||||
if (lang) {
|
||||
memcpy(s, lang, lang_len);
|
||||
s += lang_len;
|
||||
}
|
||||
|
||||
libssh2_packet_write(session, data, data_len);
|
||||
libssh2_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.
|
||||
*
|
||||
* 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 *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_abstract = NULL;
|
||||
|
Reference in New Issue
Block a user