1
1

* Renamed the functions in src/transport.c to be _libssh2_transport_ prefixed

and introduced a transport.h header.

* Fixed the blocking mode to only change behavior not the actual underlying
  socket mode so we now always work with non-blocking sockets. This also
  introduces a new rule of thumb in libssh2 code: we don't call the
  external function calls internally. We use the internal (non-blocking)
  ones!

* libssh2_channel_receive_window_adjust2 was added and
  libssh2_channel_receive_window_adjust is now deprecated

* Introduced "local" header files with prototypes etc for different parts
  instead of cramming everything into libssh2_priv.h. channel.h is the
  first.
Этот коммит содержится в:
Daniel Stenberg 2009-03-26 15:41:14 +00:00
родитель 239bdffb59
Коммит eabe072496
19 изменённых файлов: 1370 добавлений и 437 удалений

17
NEWS
Просмотреть файл

@ -1,3 +1,20 @@
* Renamed the functions in src/transport.c to be _libssh2_transport_ prefixed
and introduced a transport.h header.
* Fixed the blocking mode to only change behavior not the actual underlying
socket mode so we now always work with non-blocking sockets. This also
introduces a new rule of thumb in libssh2 code: we don't call the
external function calls internally. We use the internal (non-blocking)
ones!
* libssh2_channel_receive_window_adjust2 was added and
libssh2_channel_receive_window_adjust is now deprecated
* Introduced "local" header files with prototypes etc for different parts
instead of cramming everything into libssh2_priv.h. channel.h is the
first.
- (Mar 19 2009) Daniel Stenberg: based on a patch by "E L" we now use errno - (Mar 19 2009) Daniel Stenberg: based on a patch by "E L" we now use errno
properly after recv() and send() calls (that internally are now known as properly after recv() and send() calls (that internally are now known as
_libssh2_recv() and _libssh2_send()) so that the API and more works fine on _libssh2_recv() and _libssh2_send()) so that the API and more works fine on

4
TODO
Просмотреть файл

@ -30,7 +30,9 @@ At next SONAME bump
* stop using #defined macros as part of the official API. The macros should * stop using #defined macros as part of the official API. The macros should
either be turned into real functions or discarded from the API. either be turned into real functions or discarded from the API.
* remove the followign functions from the API/ABI * remove the following functions from the API/ABI
libssh2_base64_decode() libssh2_base64_decode()
libssh2_session_flag() libssh2_session_flag()
libssh2_channel_handle_extended_data()
libssh2_channel_receive_window_adjust()

Просмотреть файл

@ -1,4 +1,4 @@
# $Id: Makefile.am,v 1.36 2009/03/16 15:00:45 bagder Exp $ # $Id: Makefile.am,v 1.37 2009/03/26 15:41:15 bagder Exp $
EXTRA_DIST = template.3 EXTRA_DIST = template.3
@ -19,6 +19,7 @@ dist_man_MANS = \
libssh2_channel_process_startup.3 \ libssh2_channel_process_startup.3 \
libssh2_channel_read_ex.3 \ libssh2_channel_read_ex.3 \
libssh2_channel_receive_window_adjust.3 \ libssh2_channel_receive_window_adjust.3 \
libssh2_channel_receive_window_adjust2.3 \
libssh2_channel_request_pty_ex.3 \ libssh2_channel_request_pty_ex.3 \
libssh2_channel_send_eof.3 \ libssh2_channel_send_eof.3 \
libssh2_channel_set_blocking.3 \ libssh2_channel_set_blocking.3 \

Просмотреть файл

@ -1,4 +1,4 @@
.\" $Id: libssh2_channel_handle_extended_data.3,v 1.1 2007/06/13 20:09:15 jehousley Exp $ .\" $Id: libssh2_channel_handle_extended_data.3,v 1.2 2009/03/26 15:41:16 bagder Exp $
.\" .\"
.TH libssh2_channel_handle_extended_data 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual" .TH libssh2_channel_handle_extended_data 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
.SH NAME .SH NAME
@ -10,6 +10,9 @@ void
libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode); libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
.SH DESCRIPTION .SH DESCRIPTION
This function is deprecated. Use the
\fIlibssh2_channel_handle_extended_data2(3)\fP function instead!
\fIchannel\fP - Active channel stream to change extended data handling on. \fIchannel\fP - Active channel stream to change extended data handling on.
\fIignore_mode\fP - One of the three LIBSSH2_CHANNEL_EXTENDED_DATA_* Constants. \fIignore_mode\fP - One of the three LIBSSH2_CHANNEL_EXTENDED_DATA_* Constants.
@ -17,21 +20,18 @@ libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
\fBLIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL\fP: Queue extended data for eventual \fBLIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL\fP: Queue extended data for eventual
reading reading
.br .br
\fBLIBSSH2_CHANNEL_EXTENDED_DATA_MERGE\fP: Treat extended data and ordinary \fBLIBSSH2_CHANNEL_EXTENDED_DATA_MERGE\fP: Treat extended data and ordinary
data the same. Merge all substreams such that calls to data the same. Merge all substreams such that calls to
.BR libssh2_channel_read(3) \fIlibssh2_channel_read(3)\fP will pull from all substreams on a
will pull from all substreams on a first-in/first-out basis. first-in/first-out basis.
.br .br
\fBLIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE\fP: Discard all extended data as it \fBLIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE\fP: Discard all extended data as it
arrives. arrives.
Change how a channel deals with extended data packets. By default all Change how a channel deals with extended data packets. By default all extended
extended data is queued until read by data is queued until read by \fIlibssh2_channel_read_ex(3)\fP
.BR libssh2_channel_read_ex(3)
.SH RETURN VALUE .SH RETURN VALUE
None. None.
.SH SEE ALSO .SH SEE ALSO
.BR libssh2_channel_handle_extended_data2(3) .BR libssh2_channel_handle_extended_data2(3)
.BR libssh2_channel_read_ex(3) .BR libssh2_channel_read_ex(3)

Просмотреть файл

@ -1,4 +1,4 @@
.\" $Id: libssh2_channel_receive_window_adjust.3,v 1.2 2009/03/16 23:25:14 bagder Exp $ .\" $Id: libssh2_channel_receive_window_adjust.3,v 1.3 2009/03/26 15:41:16 bagder Exp $
.\" .\"
.TH libssh2_channel_receive_window_adjust 3 "15 Mar 2009" "libssh2 0.15" "libssh2 manual" .TH libssh2_channel_receive_window_adjust 3 "15 Mar 2009" "libssh2 0.15" "libssh2 manual"
.SH NAME .SH NAME
@ -12,6 +12,9 @@ libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
unsigned char force); unsigned char force);
.SH DESCRIPTION .SH DESCRIPTION
This function is deprecated in 1.1. Use
\fIlibssh2_channel_receive_window_adjust2(3)\fP!
Adjust the receive window for a channel by adjustment bytes. If the amount to Adjust the receive window for a channel by adjustment bytes. If the amount to
be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the
adjustment amount will be queued for a later packet. adjustment amount will be queued for a later packet.

Просмотреть файл

@ -0,0 +1,29 @@
.\" $Id: libssh2_channel_receive_window_adjust2.3,v 1.1 2009/03/26 15:41:16 bagder Exp $
.\"
.TH libssh2_channel_receive_window_adjust2 3 "26 Mar 2009" "libssh2 1.1" "libssh2 manual"
.SH NAME
libssh2_channel_receive_window_adjust2 - adjust the channel window
.SH SYNOPSIS
#include <libssh2.h>
int
libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL * channel,
unsigned long adjustment,
unsigned char force,
unsigned int *window);
.SH DESCRIPTION
Adjust the receive window for a channel by adjustment bytes. If the amount to
be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the
adjustment amount will be queued for a later packet.
This function stores the new size of the receive window (as understood by
remote end) in the variable 'window' points to.
.SH RETURN VALUE
Return 0 on success and a negative value on error. If used in non-blocking
mode it will return LIBSSH2_ERROR_EAGAIN when it would otherwise block.
.SH ERRORS
.SH AVAILABILITY
Added in libssh2 1.1 since the previous API has deficiencies.
.SH SEE ALSO
.BR libssh2_channel_window_read_ex(3)

Просмотреть файл

@ -1,4 +1,4 @@
.\" $Id: libssh2_channel_set_blocking.3,v 1.5 2007/06/14 17:23:13 jehousley Exp $ .\" $Id: libssh2_channel_set_blocking.3,v 1.6 2009/03/26 15:41:16 bagder Exp $
.\" .\"
.TH libssh2_channel_set_blocking 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual" .TH libssh2_channel_set_blocking 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
.SH NAME .SH NAME
@ -8,7 +8,6 @@ libssh2_channel_set_blocking - set or clear blocking mode on channel
void void
libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking); libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
.SH DESCRIPTION .SH DESCRIPTION
\fIchannel\fP - channel stream to set or clean blocking status on. \fIchannel\fP - channel stream to set or clean blocking status on.
@ -18,10 +17,8 @@ make it non-blocking.
Currently this is just a short cut call to Currently this is just a short cut call to
.BR libssh2_session_set_blocking(3) .BR libssh2_session_set_blocking(3)
and therefore will affect the session and all channels. and therefore will affect the session and all channels.
.SH RETURN VALUE .SH RETURN VALUE
None None
.SH SEE ALSO .SH SEE ALSO
.BR libssh2_session_set_blocking(3) .BR libssh2_session_set_blocking(3)
.BR libssh2_channel_read_ex(3) .BR libssh2_channel_read_ex(3)

Просмотреть файл

@ -576,11 +576,18 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel,
#define libssh2_channel_window_read(channel) \ #define libssh2_channel_window_read(channel) \
libssh2_channel_window_read_ex((channel), NULL, NULL) libssh2_channel_window_read_ex((channel), NULL, NULL)
/* libssh2_channel_receive_window_adjust is DEPRECATED, do not use! */
LIBSSH2_API unsigned long LIBSSH2_API unsigned long
libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel,
unsigned long adjustment, unsigned long adjustment,
unsigned char force); unsigned char force);
LIBSSH2_API int
libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel,
unsigned long adjustment,
unsigned char force,
unsigned int *storewindow);
LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel,
int stream_id, const char *buf, int stream_id, const char *buf,
size_t buflen); size_t buflen);
@ -603,6 +610,7 @@ LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION* session);
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel,
int blocking); int blocking);
/* libssh2_channel_handle_extended_data is DEPRECATED, do not use! */
LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel,
int ignore_mode); int ignore_mode);
LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel,

Просмотреть файл

@ -1,9 +1,10 @@
# $Id: Makefile.am,v 1.16 2009/03/17 10:19:54 jas4711 Exp $ # $Id: Makefile.am,v 1.17 2009/03/26 15:41:17 bagder Exp $
AUTOMAKE_OPTIONS = foreign nostdinc AUTOMAKE_OPTIONS = foreign nostdinc
libssh2_la_SOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c \ libssh2_la_SOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c \
misc.c packet.c publickey.c scp.c session.c sftp.c userauth.c \ misc.c packet.c publickey.c scp.c session.c sftp.c userauth.c \
libssh2_priv.h openssl.h libgcrypt.h transport.c version.c libssh2_priv.h openssl.h libgcrypt.h transport.c version.c transport.h \
channel.h
if LIBGCRYPT if LIBGCRYPT
libssh2_la_SOURCES += libgcrypt.c pem.c libssh2_la_SOURCES += libgcrypt.c pem.c

Разница между файлами не показана из-за своего большого размера Загрузить разницу

64
src/channel.h Обычный файл
Просмотреть файл

@ -0,0 +1,64 @@
#ifndef __LIBSSH2_CHANNEL_H
#define __LIBSSH2_CHANNEL_H
/* Copyright (c) 2008-2009 by Daniel Stenberg
*
* 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.
*/
/*
* _libssh2_channel_receive_window_adjust
*
* Adjust the receive window for a channel by adjustment bytes. If the amount
* to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the
* adjustment amount will be queued for a later packet.
*
* Always non-blocking.
*/
int _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
unsigned long adjustment,
unsigned char force,
unsigned int *store);
/*
* _libssh2_channel_flush
*
* Flush data from one (or all) stream
* Returns number of bytes flushed, or negative on failure
*/
int _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid);
#endif /* __LIBSSH2_CHANNEL_H */

Просмотреть файл

@ -37,6 +37,8 @@
#include "libssh2_priv.h" #include "libssh2_priv.h"
#include "transport.h"
/* TODO: Switch this to an inline and handle alloc() failures */ /* TODO: Switch this to an inline and handle alloc() failures */
/* Helper macro called from kex_method_diffie_hellman_group1_sha1_key_exchange */ /* Helper macro called from kex_method_diffie_hellman_group1_sha1_key_exchange */
#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \ #define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \
@ -139,8 +141,8 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
} }
if (exchange_state->state == libssh2_NB_state_created) { if (exchange_state->state == libssh2_NB_state_created) {
rc = _libssh2_packet_write(session, exchange_state->e_packet, rc = _libssh2_transport_write(session, exchange_state->e_packet,
exchange_state->e_packet_len); exchange_state->e_packet_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} else if (rc) { } else if (rc) {
@ -415,7 +417,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
} }
if (exchange_state->state == libssh2_NB_state_sent2) { if (exchange_state->state == libssh2_NB_state_sent2) {
rc = _libssh2_packet_write(session, &exchange_state->c, 1); rc = _libssh2_transport_write(session, &exchange_state->c, 1);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} else if (rc) { } else if (rc) {
@ -837,7 +839,7 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange
} }
if (key_state->state == libssh2_NB_state_created) { if (key_state->state == libssh2_NB_state_created) {
rc = _libssh2_packet_write(session, key_state->request, rc = _libssh2_transport_write(session, key_state->request,
key_state->request_len); key_state->request_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
@ -1136,7 +1138,7 @@ static int kexinit(LIBSSH2_SESSION * session)
data_len = session->kexinit_data_len; data_len = session->kexinit_data_len;
} }
rc = _libssh2_packet_write(session, data, data_len); rc = _libssh2_transport_write(session, data, data_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
session->kexinit_data = data; session->kexinit_data = data;
session->kexinit_data_len = data_len; session->kexinit_data_len = data_len;

Просмотреть файл

@ -684,6 +684,9 @@ struct _LIBSSH2_SESSION
unsigned char *session_id; unsigned char *session_id;
unsigned long session_id_len; unsigned long session_id_len;
/* this is set to TRUE if a blocking API behavior is requested */
int api_block_mode;
/* Server's public key */ /* Server's public key */
const LIBSSH2_HOSTKEY_METHOD *hostkey; const LIBSSH2_HOSTKEY_METHOD *hostkey;
void *server_hostkey_abstract; void *server_hostkey_abstract;
@ -716,9 +719,10 @@ struct _LIBSSH2_SESSION
/* Actual I/O socket */ /* Actual I/O socket */
int socket_fd; int socket_fd;
int socket_block;
int socket_state; int socket_state;
int socket_block_directions; int socket_block_directions;
int socket_prev_blockstate; /* stores the state of the socket blockiness
when libssh2_session_startup() is called */
/* Error tracking */ /* Error tracking */
char *err_msg; char *err_msg;
@ -1145,7 +1149,8 @@ ssize_t _libssh2_send(int socket, const void *buffer, size_t length, int flags);
#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when #define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when
waiting for more data to arrive */ waiting for more data to arrive */
int _libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds);
int _libssh2_wait_socket(LIBSSH2_SESSION *session);
/* CAUTION: some of these error codes are returned in the public API and is /* CAUTION: some of these error codes are returned in the public API and is
@ -1223,4 +1228,40 @@ int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen);
int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
unsigned char **i, unsigned int *ilen); unsigned char **i, unsigned int *ilen);
/* Conveniance-macros to allow code like this;
int rc = BLOCK_ADJUST(rc, session, session_startup(session, sock) );
int rc = BLOCK_ADJUST_ERRNO(ptr, session, session_startup(session, sock) );
The point of course being to make sure that while in non-blocking mode
these always return no matter what the return code is, but in blocking mode
it blocks if EAGAIN is the reason for the return from the underlying
function.
*/
#define BLOCK_ADJUST(rc,sess,x) \
do { \
rc = x; \
if(!sess->api_block_mode || (rc != LIBSSH2_ERROR_EAGAIN)) \
break; \
rc = _libssh2_wait_socket(sess); \
if(rc) \
break; \
} while(1)
#define BLOCK_ADJUST_ERRNO(ptr,sess,x) \
do { \
int rc; \
ptr = x; \
if(!sess->api_block_mode || \
(libssh2_session_last_errno(sess) != LIBSSH2_ERROR_EAGAIN)) \
break; \
rc = _libssh2_wait_socket(sess); \
if(rc) \
break; \
} while(1)
#endif /* LIBSSH2_H */ #endif /* LIBSSH2_H */

Просмотреть файл

@ -59,6 +59,8 @@
#include <sys/types.h> #include <sys/types.h>
#include "transport.h"
/* /*
* libssh2_packet_queue_listener * libssh2_packet_queue_listener
* *
@ -202,8 +204,8 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
} }
if (listen_state->state == libssh2_NB_state_created) { if (listen_state->state == libssh2_NB_state_created) {
rc = _libssh2_packet_write(session, listen_state->packet, rc = _libssh2_transport_write(session, listen_state->packet,
17); 17);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} else if (rc) { } else if (rc) {
@ -256,7 +258,8 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
p += sizeof(FwdNotReq) - 1; p += sizeof(FwdNotReq) - 1;
_libssh2_htonu32(p, 0); _libssh2_htonu32(p, 0);
rc = _libssh2_packet_write(session, listen_state->packet, packet_len); rc = _libssh2_transport_write(session, listen_state->packet,
packet_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} else if (rc) { } else if (rc) {
@ -374,7 +377,7 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
} }
if (x11open_state->state == libssh2_NB_state_created) { if (x11open_state->state == libssh2_NB_state_created) {
rc = _libssh2_packet_write(session, x11open_state->packet, 17); rc = _libssh2_transport_write(session, x11open_state->packet, 17);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} else if (rc) { } else if (rc) {
@ -422,7 +425,7 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
p += sizeof(X11FwdUnAvil) - 1; p += sizeof(X11FwdUnAvil) - 1;
_libssh2_htonu32(p, 0); _libssh2_htonu32(p, 0);
rc = _libssh2_packet_write(session, x11open_state->packet, packet_len); rc = _libssh2_transport_write(session, x11open_state->packet, packet_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} else if (rc) { } else if (rc) {
@ -922,11 +925,10 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
} }
/* /*
* The KEXINIT message has been added to the queue. * The KEXINIT message has been added to the queue. The packAdd and
* The packAdd and readPack states need to be reset * readPack states need to be reset because libssh2_kex_exchange
* because libssh2_kex_exchange (eventually) calls upon * (eventually) calls upon _libssh2_transport_read to read the rest of
* libssh2_packet_read to read the rest of the key exchange * the key exchange conversation.
* conversation.
*/ */
session->readPack_state = libssh2_NB_state_idle; session->readPack_state = libssh2_NB_state_idle;
session->packet.total_num = 0; session->packet.total_num = 0;
@ -1029,39 +1031,10 @@ _libssh2_packet_askv(LIBSSH2_SESSION * session,
return -1; return -1;
} }
/*
* _libssh2_waitsocket
*
* Returns
* negative on error
* >0 on incoming data
* 0 on timeout
*
* FIXME: convert to use poll on systems that have it.
*/
int
_libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds)
{
struct timeval timeout;
int rc;
fd_set fd;
timeout.tv_sec = seconds;
timeout.tv_usec = 0;
FD_ZERO(&fd);
FD_SET(session->socket_fd, &fd);
rc = select(session->socket_fd + 1, &fd, NULL, NULL, &timeout);
return rc;
}
/* /*
* _libssh2_packet_require * _libssh2_packet_require
* *
* Loops _libssh2_packet_read() until the packet requested is available * Loops _libssh2_transport_read() until the packet requested is available
* SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
* *
* Returns negative on error * Returns negative on error
@ -1091,11 +1064,11 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type,
} }
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) { while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
libssh2pack_t ret = _libssh2_packet_read(session); libssh2pack_t ret = _libssh2_transport_read(session);
if (ret == PACKET_EAGAIN) { if (ret == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} else if ((ret == 0) && (!session->socket_block)) { } else if (ret == 0) {
/* If we are in non-blocking and there is no data, return that */ /* There is no data, return that. TODO: is this really correct? */
return PACKET_EAGAIN; return PACKET_EAGAIN;
} else if (ret < 0) { } else if (ret < 0) {
state->start = 0; state->start = 0;
@ -1111,7 +1084,7 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type,
/* nothing available, wait until data arrives or we time out */ /* nothing available, wait until data arrives or we time out */
long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start); long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
if ((left <= 0) || (_libssh2_waitsocket(session, left) <= 0)) { if (left <= 0) {
state->start = 0; state->start = 0;
return PACKET_TIMEOUT; return PACKET_TIMEOUT;
} }
@ -1125,7 +1098,7 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type,
/* /*
* _libssh2_packet_burn * _libssh2_packet_burn
* *
* Loops _libssh2_packet_read() until any packet is available and promptly * Loops _libssh2_transport_read() until any packet is available and promptly
* discards it. * discards it.
* Used during KEX exchange to discard badly guessed KEX_INIT packets * Used during KEX exchange to discard badly guessed KEX_INIT packets
*/ */
@ -1158,7 +1131,7 @@ _libssh2_packet_burn(LIBSSH2_SESSION * session,
} }
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) { while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
if ((ret = _libssh2_packet_read(session)) == PACKET_EAGAIN) { if ((ret = _libssh2_transport_read(session)) == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} else if (ret < 0) { } else if (ret < 0) {
*state = libssh2_NB_state_idle; *state = libssh2_NB_state_idle;
@ -1185,7 +1158,7 @@ _libssh2_packet_burn(LIBSSH2_SESSION * session,
/* /*
* _libssh2_packet_requirev * _libssh2_packet_requirev
* *
* Loops _libssh2_packet_read() until one of a list of packet types requested is * Loops _libssh2_transport_read() until one of a list of packet types requested is
* available * available
* SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
* packet_types is a null terminated list of packet_type numbers * packet_types is a null terminated list of packet_type numbers
@ -1212,7 +1185,7 @@ _libssh2_packet_requirev(LIBSSH2_SESSION * session,
} }
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) { while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
int ret = _libssh2_packet_read(session); int ret = _libssh2_transport_read(session);
if ((ret < 0) && (ret != PACKET_EAGAIN)) { if ((ret < 0) && (ret != PACKET_EAGAIN)) {
state->start = 0; state->start = 0;
return ret; return ret;
@ -1220,10 +1193,11 @@ _libssh2_packet_requirev(LIBSSH2_SESSION * session,
if (ret <= 0) { if (ret <= 0) {
long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start); long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
if ((left <= 0) || (_libssh2_waitsocket(session, left) <= 0)) { if (left <= 0) {
state->start = 0; state->start = 0;
return PACKET_TIMEOUT; return PACKET_TIMEOUT;
} else if (ret == PACKET_EAGAIN) { }
else if (ret == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} }
} }

Просмотреть файл

@ -1,4 +1,5 @@
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
* Copyright (c) 2009 by Daniel Stenberg
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@ -396,12 +397,13 @@ libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner)
} }
/* /*
* proto libssh2_session_init * libssh2_session_init_ex
* *
* Allocate and initialize a libssh2 session structure * Allocate and initialize a libssh2 session structure. Allows for malloc
* Allows for malloc callbacks in case the calling program has its own memory manager * callbacks in case the calling program has its own memory manager It's
* It's allowable (but unadvisable) to define some but not all of the malloc callbacks * allowable (but unadvisable) to define some but not all of the malloc
* An additional pointer value may be optionally passed to be sent to the callbacks (so they know who's asking) * callbacks An additional pointer value may be optionally passed to be sent
* to the callbacks (so they know who's asking)
*/ */
LIBSSH2_API LIBSSH2_SESSION * LIBSSH2_API LIBSSH2_SESSION *
libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
@ -430,6 +432,7 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
session->free = local_free; session->free = local_free;
session->realloc = local_realloc; session->realloc = local_realloc;
session->abstract = abstract; session->abstract = abstract;
session->api_block_mode = 1; /* blocking API by default */
_libssh2_debug(session, LIBSSH2_DBG_TRANS, _libssh2_debug(session, LIBSSH2_DBG_TRANS,
"New session resource allocated"); "New session resource allocated");
libssh2_crypto_init(); libssh2_crypto_init();
@ -485,16 +488,46 @@ libssh2_session_callback_set(LIBSSH2_SESSION * session,
} }
/* /*
* proto libssh2_session_startup * _libssh2_wait_socket()
* *
* session: LIBSSH2_SESSION struct allocated and owned by the calling program * Utility function that waits for action on the socket. Returns 0 when ready
* Returns: 0 on success, or non-zero on failure * to run again or error on timeout.
* Any memory allocated by libssh2 will use alloc/realloc/free
* callbacks in session
* socket *must* be populated with an opened and connected socket.
*/ */
LIBSSH2_API int int _libssh2_wait_socket(LIBSSH2_SESSION *session)
libssh2_session_startup(LIBSSH2_SESSION * session, int sock) {
fd_set fd;
fd_set *writefd = NULL;
fd_set *readfd = NULL;
int dir;
int rc;
FD_ZERO(&fd);
FD_SET(session->socket_fd, &fd);
/* now make sure we wait in the correct direction */
dir = libssh2_session_block_directions(session);
if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
readfd = &fd;
if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
writefd = &fd;
/* Note that this COULD be made to use a timeout that perhaps could be
customizable by the app or something... */
rc = select(session->socket_fd + 1, readfd, writefd, NULL, NULL);
if(rc <= 0) {
/* timeout (or error), bail out with a timeout error */
session->err_code = LIBSSH2_ERROR_TIMEOUT;
return LIBSSH2_ERROR_TIMEOUT;
}
return 0; /* ready to try again */
}
static int
session_startup(LIBSSH2_SESSION *session, int sock)
{ {
int rc; int rc;
@ -510,15 +543,12 @@ libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
} }
session->socket_fd = sock; session->socket_fd = sock;
session->socket_block = session->socket_prev_blockstate =
!get_socket_nonblocking(session->socket_fd); !get_socket_nonblocking(session->socket_fd);
if (session->socket_block) {
/* if (session->socket_prev_blockstate) {
* Since we can't be sure that we are in blocking or there /* If in blocking state chang to non-blocking */
* was an error detecting the state, so set to blocking to session_nonblock(session->socket_fd, 1);
* be sure
*/
session_nonblock(session->socket_fd, 0);
} }
session->startup_state = libssh2_NB_state_created; session->startup_state = libssh2_NB_state_created;
@ -588,8 +618,8 @@ libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
} }
if (session->startup_state == libssh2_NB_state_sent3) { if (session->startup_state == libssh2_NB_state_sent3) {
rc = _libssh2_packet_write(session, session->startup_service, rc = _libssh2_transport_write(session, session->startup_service,
sizeof("ssh-userauth") + 5 - 1); sizeof("ssh-userauth") + 5 - 1);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block asking for ssh-userauth service", 0); "Would block asking for ssh-userauth service", 0);
@ -638,14 +668,33 @@ libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
return LIBSSH2_ERROR_INVAL; return LIBSSH2_ERROR_INVAL;
} }
/*
* proto libssh2_session_startup
*
* session: LIBSSH2_SESSION struct allocated and owned by the calling program
* Returns: 0 on success, or non-zero on failure
* Any memory allocated by libssh2 will use alloc/realloc/free
* callbacks in session.
* The 'sock' socket *must* be populated with an opened and connected socket.
*/
LIBSSH2_API int
libssh2_session_startup(LIBSSH2_SESSION *session, int sock)
{
int rc;
BLOCK_ADJUST(rc, session, session_startup(session, sock) );
return rc;
}
/* /*
* libssh2_session_free * libssh2_session_free
* *
* Frees the memory allocated to the session * Frees the memory allocated to the session
* Also closes and frees any channels attached to this session * Also closes and frees any channels attached to this session
*/ */
LIBSSH2_API int static int
libssh2_session_free(LIBSSH2_SESSION * session) session_free(LIBSSH2_SESSION *session)
{ {
int rc; int rc;
@ -869,16 +918,37 @@ libssh2_session_free(LIBSSH2_SESSION * session)
LIBSSH2_FREE(session, tmp); LIBSSH2_FREE(session, tmp);
} }
if(session->socket_prev_blockstate)
/* if the socket was previously blocking, put it back so */
session_nonblock(session->socket_fd, 0);
LIBSSH2_FREE(session, session); LIBSSH2_FREE(session, session);
return 0; return 0;
} }
/* libssh2_session_disconnect_ex /*
* libssh2_session_free
*
* Frees the memory allocated to the session
* Also closes and frees any channels attached to this session
*/ */
LIBSSH2_API int LIBSSH2_API int
libssh2_session_disconnect_ex(LIBSSH2_SESSION * session, int reason, libssh2_session_free(LIBSSH2_SESSION * session)
const char *description, const char *lang) {
int rc;
BLOCK_ADJUST(rc, session, session_free(session) );
return rc;
}
/*
* libssh2_session_disconnect_ex
*/
static int
session_disconnect(LIBSSH2_SESSION *session, int reason,
const char *description, const char *lang)
{ {
unsigned char *s; unsigned char *s;
unsigned long descr_len = 0, lang_len = 0; unsigned long descr_len = 0, lang_len = 0;
@ -928,8 +998,8 @@ libssh2_session_disconnect_ex(LIBSSH2_SESSION * session, int reason,
session->disconnect_state = libssh2_NB_state_created; session->disconnect_state = libssh2_NB_state_created;
} }
rc = _libssh2_packet_write(session, session->disconnect_data, rc = _libssh2_transport_write(session, session->disconnect_data,
session->disconnect_data_len); session->disconnect_data_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} }
@ -941,10 +1011,27 @@ libssh2_session_disconnect_ex(LIBSSH2_SESSION * session, int reason,
return 0; return 0;
} }
/*
* libssh2_session_disconnect_ex
*/
LIBSSH2_API int
libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason,
const char *desc, const char *lang)
{
int rc;
BLOCK_ADJUST(rc, session,
session_disconnect(session, reason, desc, lang));
return rc;
}
/* libssh2_session_methods /* libssh2_session_methods
*
* Return the currently active methods for method_type * Return the currently active methods for method_type
* NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation *
* Strings should NOT be freed * NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string
* regardless of actual negotiation Strings should NOT be freed
*/ */
LIBSSH2_API const char * LIBSSH2_API const char *
libssh2_session_methods(LIBSSH2_SESSION * session, int method_type) libssh2_session_methods(LIBSSH2_SESSION * session, int method_type)
@ -1019,9 +1106,10 @@ libssh2_session_abstract(LIBSSH2_SESSION * session)
} }
/* libssh2_session_last_error /* 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 * Returns error code and populates an error string into errmsg If want_buf is
* Otherwise it is assumed to be owned by libssh2 * 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_API int
libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg, libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg,
@ -1101,22 +1189,17 @@ libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value)
/* _libssh2_session_set_blocking /* _libssh2_session_set_blocking
* *
* Set a session's blocking mode on or off, return the previous status * Set a session's blocking mode on or off, return the previous status when
* when this function is called. * this function is called. Note this function does not alter the state of the
* actual socket involved.
*/ */
int int
_libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking) _libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking)
{ {
int bl = session->socket_block; int bl = session->api_block_mode;
_libssh2_debug(session, LIBSSH2_DBG_CONN, _libssh2_debug(session, LIBSSH2_DBG_CONN,
"Setting blocking mode on session %d", blocking); "Setting blocking mode %s", blocking?"ON":"OFF");
if (blocking == session->socket_block) { session->api_block_mode = blocking;
/* avoid if already correct */
return bl;
}
session->socket_block = blocking;
session_nonblock(session->socket_fd, !blocking);
return bl; return bl;
} }
@ -1139,7 +1222,7 @@ libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
LIBSSH2_API int LIBSSH2_API int
libssh2_session_get_blocking(LIBSSH2_SESSION * session) libssh2_session_get_blocking(LIBSSH2_SESSION * session)
{ {
return session->socket_block; return session->api_block_mode;
} }
/* /*
@ -1418,7 +1501,7 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
case LIBSSH2_POLLFD_CHANNEL: case LIBSSH2_POLLFD_CHANNEL:
if (sockets[i].events & POLLIN) { if (sockets[i].events & POLLIN) {
/* Spin session until no data available */ /* Spin session until no data available */
while (_libssh2_packet_read(fds[i].fd.channel->session) while (_libssh2_transport_read(fds[i].fd.channel->session)
> 0); > 0);
} }
if (sockets[i].revents & POLLHUP) { if (sockets[i].revents & POLLHUP) {
@ -1431,7 +1514,7 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
case LIBSSH2_POLLFD_LISTENER: case LIBSSH2_POLLFD_LISTENER:
if (sockets[i].events & POLLIN) { if (sockets[i].events & POLLIN) {
/* Spin session until no data available */ /* Spin session until no data available */
while (_libssh2_packet_read(fds[i].fd.listener->session) while (_libssh2_transport_read(fds[i].fd.listener->session)
> 0); > 0);
} }
if (sockets[i].revents & POLLHUP) { if (sockets[i].revents & POLLHUP) {
@ -1484,7 +1567,7 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
case LIBSSH2_POLLFD_CHANNEL: case LIBSSH2_POLLFD_CHANNEL:
if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) { if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
/* Spin session until no data available */ /* Spin session until no data available */
while (_libssh2_packet_read(fds[i].fd.channel->session) while (_libssh2_transport_read(fds[i].fd.channel->session)
> 0); > 0);
} }
break; break;
@ -1493,7 +1576,7 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
if (FD_ISSET if (FD_ISSET
(fds[i].fd.listener->session->socket_fd, &rfds)) { (fds[i].fd.listener->session->socket_fd, &rfds)) {
/* Spin session until no data available */ /* Spin session until no data available */
while (_libssh2_packet_read(fds[i].fd.listener->session) while (_libssh2_transport_read(fds[i].fd.listener->session)
> 0); > 0);
} }
break; break;

Просмотреть файл

@ -89,7 +89,7 @@
* Add a packet to the SFTP packet brigade * Add a packet to the SFTP packet brigade
*/ */
static int static int
sftp_packet_add(LIBSSH2_SFTP * sftp, unsigned char *data, sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data,
unsigned long data_len) unsigned long data_len)
{ {
LIBSSH2_SESSION *session = sftp->channel->session; LIBSSH2_SESSION *session = sftp->channel->session;
@ -127,7 +127,7 @@ sftp_packet_add(LIBSSH2_SFTP * sftp, unsigned char *data,
* Frame an SFTP packet off the channel * Frame an SFTP packet off the channel
*/ */
static int static int
sftp_packet_read(LIBSSH2_SFTP * sftp) sftp_packet_read(LIBSSH2_SFTP *sftp)
{ {
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session; LIBSSH2_SESSION *session = channel->session;
@ -225,7 +225,7 @@ sftp_packet_read(LIBSSH2_SFTP * sftp)
* Checks if there's a matching SFTP packet available. * Checks if there's a matching SFTP packet available.
*/ */
static int static int
sftp_packet_ask(LIBSSH2_SFTP * sftp, unsigned char packet_type, sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type,
unsigned long request_id, unsigned char **data, unsigned long request_id, unsigned char **data,
unsigned long *data_len) unsigned long *data_len)
{ {
@ -280,7 +280,7 @@ sftp_packet_ask(LIBSSH2_SFTP * sftp, unsigned char packet_type,
* A la libssh2_packet_require * A la libssh2_packet_require
*/ */
static int static int
sftp_packet_require(LIBSSH2_SFTP * sftp, unsigned char packet_type, sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type,
unsigned long request_id, unsigned char **data, unsigned long request_id, unsigned char **data,
unsigned long *data_len) unsigned long *data_len)
{ {
@ -322,7 +322,7 @@ sftp_packet_require(LIBSSH2_SFTP * sftp, unsigned char packet_type,
* Require one of N possible reponses * Require one of N possible reponses
*/ */
static int static int
sftp_packet_requirev(LIBSSH2_SFTP * sftp, int num_valid_responses, sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses,
const unsigned char *valid_responses, const unsigned char *valid_responses,
unsigned long request_id, unsigned char **data, unsigned long request_id, unsigned char **data,
unsigned long *data_len) unsigned long *data_len)
@ -360,12 +360,8 @@ sftp_packet_requirev(LIBSSH2_SFTP * sftp, int num_valid_responses,
if (left <= 0) { if (left <= 0) {
sftp->requirev_start = 0; sftp->requirev_start = 0;
return PACKET_TIMEOUT; return PACKET_TIMEOUT;
} else if (sftp->channel->session->socket_block }
&& (_libssh2_waitsocket(sftp->channel->session, left) <= else if (ret == PACKET_EAGAIN) {
0)) {
sftp->requirev_start = 0;
return PACKET_TIMEOUT;
} else if (ret == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} }
} }
@ -521,12 +517,11 @@ LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor)
} }
/* /*
* libssh2_sftp_init * sftp_init
* *
* Startup an SFTP session * Startup an SFTP session
*/ */
LIBSSH2_API LIBSSH2_SFTP * static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session)
libssh2_sftp_init(LIBSSH2_SESSION * session)
{ {
unsigned char *data, *s; unsigned char *data, *s;
unsigned long data_len; unsigned long data_len;
@ -693,11 +688,23 @@ libssh2_sftp_init(LIBSSH2_SESSION * session)
return NULL; return NULL;
} }
/*
* libssh2_sftp_init
*
* Startup an SFTP session
*/
LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
{
LIBSSH2_SFTP *ptr;
BLOCK_ADJUST_ERRNO(ptr, session, sftp_init(session));
return ptr;
}
/* libssh2_sftp_shutdown /* libssh2_sftp_shutdown
* Shutsdown the SFTP subsystem * Shutsdown the SFTP subsystem
*/ */
LIBSSH2_API int LIBSSH2_API int
libssh2_sftp_shutdown(LIBSSH2_SFTP * sftp) libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp)
{ {
/* /*
* Make sure all memory used in the state variables are free * Make sure all memory used in the state variables are free
@ -754,12 +761,12 @@ libssh2_sftp_shutdown(LIBSSH2_SFTP * sftp)
* SFTP File and Directory Ops * * SFTP File and Directory Ops *
******************************* */ ******************************* */
/* libssh2_sftp_open_ex /* sftp_open
*/ */
LIBSSH2_API LIBSSH2_SFTP_HANDLE * static LIBSSH2_SFTP_HANDLE *
libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename, sftp_open(LIBSSH2_SFTP *sftp, const char *filename,
unsigned int filename_len, unsigned long flags, long mode, unsigned int filename_len, unsigned long flags, long mode,
int open_type) int open_type)
{ {
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session; LIBSSH2_SESSION *session = channel->session;
@ -932,12 +939,25 @@ libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename,
return fp; return fp;
} }
/* libssh2_sftp_read /* libssh2_sftp_open_ex
*/
LIBSSH2_API LIBSSH2_SFTP_HANDLE *
libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename,
unsigned int filename_len, unsigned long flags, long mode,
int open_type)
{
LIBSSH2_SFTP_HANDLE *hnd;
BLOCK_ADJUST_ERRNO(hnd, sftp->channel->session,
sftp_open(sftp, filename, filename_len, flags, mode,
open_type));
return hnd;
}
/* sftp_read
* Read from an SFTP file handle * Read from an SFTP file handle
*/ */
LIBSSH2_API ssize_t static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
libssh2_sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, size_t buffer_maxlen)
size_t buffer_maxlen)
{ {
LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_SFTP *sftp = handle->sftp;
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
@ -1108,14 +1128,26 @@ libssh2_sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
return total_read; return total_read;
} }
/* libssh2_sftp_readdir /* libssh2_sftp_read
* Read from an SFTP file handle
*/
LIBSSH2_API ssize_t
libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *hnd, char *buffer,
size_t buffer_maxlen)
{
ssize_t rc;
BLOCK_ADJUST(rc, hnd->sftp->channel->session,
sftp_read(hnd, buffer, buffer_maxlen));
return rc;
}
/* sftp_readdir
* Read from an SFTP directory handle * Read from an SFTP directory handle
*/ */
LIBSSH2_API int static int sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
size_t buffer_maxlen, char *longentry, size_t buffer_maxlen, char *longentry,
size_t longentry_maxlen, size_t longentry_maxlen,
LIBSSH2_SFTP_ATTRIBUTES * attrs) LIBSSH2_SFTP_ATTRIBUTES *attrs)
{ {
LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_SFTP *sftp = handle->sftp;
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
@ -1311,12 +1343,27 @@ libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
longentry_maxlen, attrs); longentry_maxlen, attrs);
} }
/* libssh2_sftp_write /* libssh2_sftp_readdir_ex
* Read from an SFTP directory handle
*/
LIBSSH2_API int
libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *hnd, char *buffer,
size_t buffer_maxlen, char *longentry,
size_t longentry_maxlen,
LIBSSH2_SFTP_ATTRIBUTES *attrs)
{
int rc;
BLOCK_ADJUST(rc, hnd->sftp->channel->session,
sftp_readdir(hnd, buffer, buffer_maxlen, longentry,
longentry_maxlen, attrs));
return rc;
}
/* sftp_write
* Write data to a file handle * Write data to a file handle
*/ */
LIBSSH2_API ssize_t static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE * handle, const char *buffer,
libssh2_sftp_write(LIBSSH2_SFTP_HANDLE * handle, const char *buffer, size_t count)
size_t count)
{ {
LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_SFTP *sftp = handle->sftp;
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
@ -1405,12 +1452,27 @@ libssh2_sftp_write(LIBSSH2_SFTP_HANDLE * handle, const char *buffer,
return -1; return -1;
} }
/* libssh2_sftp_fstat_ex /* libssh2_sftp_write
* Write data to a file handle
*/
LIBSSH2_API ssize_t
libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *hnd, const char *buffer,
size_t count)
{
ssize_t rc;
BLOCK_ADJUST(rc, hnd->sftp->channel->session,
sftp_write(hnd, buffer, count));
return rc;
}
/*
* sftp_fstat
*
* Get or Set stat on a file * Get or Set stat on a file
*/ */
LIBSSH2_API int static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle,
libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE * handle, LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat)
LIBSSH2_SFTP_ATTRIBUTES * attrs, int setstat)
{ {
LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_SFTP *sftp = handle->sftp;
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
@ -1506,6 +1568,19 @@ libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE * handle,
return 0; return 0;
} }
/* libssh2_sftp_fstat_ex
* Get or Set stat on a file
*/
LIBSSH2_API int
libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE * hnd,
LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat)
{
int rc;
BLOCK_ADJUST(rc, hnd->sftp->channel->session,
sftp_fstat(hnd, attrs, setstat));
return rc;
}
/* libssh2_sftp_seek /* libssh2_sftp_seek
* Set the read/write pointer to an arbitrary position within the file * Set the read/write pointer to an arbitrary position within the file
*/ */
@ -1542,12 +1617,13 @@ libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE * handle)
return handle->u.file.offset; return handle->u.file.offset;
} }
/* libssh2_sftp_close_handle /* sftp_close_handle
*
* Close a file or directory handle * Close a file or directory handle
* Also frees handle resource and unlinks it from the SFTP structure * Also frees handle resource and unlinks it from the SFTP structure
*/ */
LIBSSH2_API int static int
libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE * handle) sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
{ {
LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_SFTP *sftp = handle->sftp;
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
@ -1647,16 +1723,23 @@ libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE * handle)
return 0; return 0;
} }
/* ********************** /* libssh2_sftp_close_handle
* SFTP Miscellaneous * *
********************** */ * Close a file or directory handle
* Also frees handle resource and unlinks it from the SFTP structure
*/
LIBSSH2_API int
libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *hnd)
{
int rc;
BLOCK_ADJUST(rc, hnd->sftp->channel->session, sftp_close_handle(hnd));
return rc;
}
/* libssh2_sftp_unlink_ex /* sftp_unlink
* Delete a file from the remote server * Delete a file from the remote server
*/ */
/* libssh2_sftp_unlink_ex - NB-UNSAFE?? */ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename,
LIBSSH2_API int
libssh2_sftp_unlink_ex(LIBSSH2_SFTP * sftp, const char *filename,
unsigned int filename_len) unsigned int filename_len)
{ {
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
@ -1738,11 +1821,25 @@ libssh2_sftp_unlink_ex(LIBSSH2_SFTP * sftp, const char *filename,
} }
} }
/* libssh2_sftp_rename_ex /* libssh2_sftp_unlink_ex
* Rename a file on the remote server * Delete a file from the remote server
*/ */
LIBSSH2_API int LIBSSH2_API int
libssh2_sftp_rename_ex(LIBSSH2_SFTP * sftp, const char *source_filename, libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename,
unsigned int filename_len)
{
int rc;
BLOCK_ADJUST(rc, sftp->channel->session,
sftp_unlink(sftp, filename, filename_len));
return rc;
}
/*
* sftp_rename
*
* Rename a file on the remote server
*/
static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename,
unsigned int source_filename_len, unsigned int source_filename_len,
const char *dest_filename, const char *dest_filename,
unsigned int dest_filename_len, long flags) unsigned int dest_filename_len, long flags)
@ -1865,11 +1962,28 @@ libssh2_sftp_rename_ex(LIBSSH2_SFTP * sftp, const char *source_filename,
return retcode; return retcode;
} }
/* libssh2_sftp_mkdir_ex /* libssh2_sftp_rename_ex
* Create an SFTP directory * Rename a file on the remote server
*/ */
LIBSSH2_API int LIBSSH2_API int
libssh2_sftp_mkdir_ex(LIBSSH2_SFTP * sftp, const char *path, libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename,
unsigned int source_filename_len,
const char *dest_filename,
unsigned int dest_filename_len, long flags)
{
int rc;
BLOCK_ADJUST(rc, sftp->channel->session,
sftp_rename(sftp, source_filename, source_filename_len,
dest_filename, dest_filename_len, flags));
return rc;
}
/*
* sftp_mkdir
*
* Create an SFTP directory
*/
static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path,
unsigned int path_len, long mode) unsigned int path_len, long mode)
{ {
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
@ -1957,12 +2071,25 @@ libssh2_sftp_mkdir_ex(LIBSSH2_SFTP * sftp, const char *path,
} }
} }
/* libssh2_sftp_rmdir_ex /*
* libssh2_sftp_mkdir_ex
*
* Create an SFTP directory
*/
LIBSSH2_API int
libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path,
unsigned int path_len, long mode)
{
int rc;
BLOCK_ADJUST(rc, sftp->channel->session,
sftp_mkdir(sftp, path, path_len, mode));
return rc;
}
/* sftp_rmdir
* Remove a directory * Remove a directory
*/ */
/* libssh2_sftp_rmdir_ex - NB-UNSAFE?? */ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path,
LIBSSH2_API int
libssh2_sftp_rmdir_ex(LIBSSH2_SFTP * sftp, const char *path,
unsigned int path_len) unsigned int path_len)
{ {
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
@ -2042,12 +2169,23 @@ libssh2_sftp_rmdir_ex(LIBSSH2_SFTP * sftp, const char *path,
} }
} }
/* libssh2_sftp_stat_ex /* libssh2_sftp_rmdir_ex
* Remove a directory
*/
LIBSSH2_API int
libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path,
unsigned int path_len)
{
int rc;
BLOCK_ADJUST(rc, sftp->channel->session,
sftp_rmdir(sftp, path, path_len));
return rc;
}
/* sftp_stat
* Stat a file or symbolic link * Stat a file or symbolic link
*/ */
/* libssh2_sftp_stat_ex - NB-UNSAFE?? */ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path,
LIBSSH2_API int
libssh2_sftp_stat_ex(LIBSSH2_SFTP * sftp, const char *path,
unsigned int path_len, int stat_type, unsigned int path_len, int stat_type,
LIBSSH2_SFTP_ATTRIBUTES * attrs) LIBSSH2_SFTP_ATTRIBUTES * attrs)
{ {
@ -2159,11 +2297,24 @@ libssh2_sftp_stat_ex(LIBSSH2_SFTP * sftp, const char *path,
return 0; return 0;
} }
/* libssh2_sftp_symlink_ex /* libssh2_sftp_stat_ex
* Read or set a symlink * Stat a file or symbolic link
*/ */
LIBSSH2_API int LIBSSH2_API int
libssh2_sftp_symlink_ex(LIBSSH2_SFTP * sftp, const char *path, libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path,
unsigned int path_len, int stat_type,
LIBSSH2_SFTP_ATTRIBUTES *attrs)
{
int rc;
BLOCK_ADJUST(rc, sftp->channel->session,
sftp_stat(sftp, path, path_len, stat_type, attrs));
return rc;
}
/* sftp_symlink
* Read or set a symlink
*/
static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path,
unsigned int path_len, char *target, unsigned int path_len, char *target,
unsigned int target_len, int link_type) unsigned int target_len, int link_type)
{ {
@ -2301,11 +2452,26 @@ libssh2_sftp_symlink_ex(LIBSSH2_SFTP * sftp, const char *path,
return link_len; return link_len;
} }
/* libssh2_sftp_symlink_ex
* Read or set a symlink
*/
LIBSSH2_API int
libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path,
unsigned int path_len, char *target,
unsigned int target_len, int link_type)
{
int rc;
BLOCK_ADJUST(rc, sftp->channel->session,
sftp_symlink(sftp, path, path_len, target, target_len,
link_type));
return rc;
}
/* libssh2_sftp_last_error /* libssh2_sftp_last_error
* Returns the last error code reported by SFTP * Returns the last error code reported by SFTP
*/ */
LIBSSH2_API unsigned long LIBSSH2_API unsigned long
libssh2_sftp_last_error(LIBSSH2_SFTP * sftp) libssh2_sftp_last_error(LIBSSH2_SFTP *sftp)
{ {
return sftp->last_errno; return sftp->last_errno;
} }

Просмотреть файл

@ -44,6 +44,8 @@
#include <assert.h> #include <assert.h>
#include "transport.h"
#define MAX_BLOCKSIZE 32 /* MUST fit biggest crypto block size we use/get */ #define MAX_BLOCKSIZE 32 /* MUST fit biggest crypto block size we use/get */
#define MAX_MACSIZE 20 /* MUST fit biggest MAC length we support */ #define MAX_MACSIZE 20 /* MUST fit biggest MAC length we support */
@ -220,7 +222,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
session->fullpacket_packet_type = p->payload[0]; session->fullpacket_packet_type = p->payload[0];
debugdump(session, "libssh2_packet_read() plain", debugdump(session, "libssh2_transport_read() plain",
p->payload, session->fullpacket_payload_len); p->payload, session->fullpacket_payload_len);
session->fullpacket_state = libssh2_NB_state_created; session->fullpacket_state = libssh2_NB_state_created;
@ -244,7 +246,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
/* /*
* _libssh2_packet_read * _libssh2_transport_read
* *
* Collect a packet into the input brigade block only controls whether or not * Collect a packet into the input brigade block only controls whether or not
* to wait for a packet to start. * to wait for a packet to start.
@ -259,7 +261,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
* "The Secure Shell (SSH) Transport Layer Protocol" * "The Secure Shell (SSH) Transport Layer Protocol"
*/ */
libssh2pack_t libssh2pack_t
_libssh2_packet_read(LIBSSH2_SESSION * session) _libssh2_transport_read(LIBSSH2_SESSION * session)
{ {
libssh2pack_t rc; libssh2pack_t rc;
struct transportpacket *p = &session->packet; struct transportpacket *p = &session->packet;
@ -313,7 +315,7 @@ _libssh2_packet_read(LIBSSH2_SESSION * session)
if (session->readPack_state == libssh2_NB_state_jump1) { if (session->readPack_state == libssh2_NB_state_jump1) {
session->readPack_state = libssh2_NB_state_idle; session->readPack_state = libssh2_NB_state_idle;
encrypted = session->readPack_encrypted; encrypted = session->readPack_encrypted;
goto libssh2_packet_read_point1; goto libssh2_transport_read_point1;
} }
do { do {
@ -373,7 +375,7 @@ _libssh2_packet_read(LIBSSH2_SESSION * session)
} }
return PACKET_FAIL; return PACKET_FAIL;
} }
debugdump(session, "libssh2_packet_read() raw", debugdump(session, "libssh2_transport_read() raw",
&p->buf[remainbuf], nread); &p->buf[remainbuf], nread);
/* advance write pointer */ /* advance write pointer */
p->writeidx += nread; p->writeidx += nread;
@ -542,7 +544,7 @@ _libssh2_packet_read(LIBSSH2_SESSION * session)
if (!remainpack) { if (!remainpack) {
/* we have a full packet */ /* we have a full packet */
libssh2_packet_read_point1: libssh2_transport_read_point1:
rc = fullpacket(session, encrypted); rc = fullpacket(session, encrypted);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
@ -618,7 +620,7 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
return PACKET_EAGAIN; return PACKET_EAGAIN;
} }
debugdump(session, "libssh2_packet_write send()", &p->outbuf[p->osent], debugdump(session, "libssh2_transport_write send()", &p->outbuf[p->osent],
length); length);
p->osent += length; /* we sent away this much data */ p->osent += length; /* we sent away this much data */
@ -626,7 +628,7 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
} }
/* /*
* libssh2_packet_write * libssh2_transport_write
* *
* Send a packet, encrypting it and adding a MAC code if necessary * Send a packet, encrypting it and adding a MAC code if necessary
* Returns 0 on success, non-zero on failure. * Returns 0 on success, non-zero on failure.
@ -641,8 +643,8 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
* (RFC4253 section 6.1) * (RFC4253 section 6.1)
*/ */
int int
_libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data, _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
unsigned long data_len) unsigned long data_len)
{ {
int blocksize = int blocksize =
(session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt-> (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->
@ -663,7 +665,7 @@ _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
unsigned char *orgdata = data; unsigned char *orgdata = data;
unsigned long orgdata_len = data_len; unsigned long orgdata_len = data_len;
debugdump(session, "libssh2_packet_write plain", data, data_len); debugdump(session, "libssh2_transport_write plain", data, data_len);
/* FIRST, check if we have a pending write to complete */ /* FIRST, check if we have a pending write to complete */
rc = send_existing(session, data, data_len, &ret); rc = send_existing(session, data, data_len, &ret);
@ -769,7 +771,7 @@ _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
LIBSSH2_SOCKET_SEND_FLAGS(session)); LIBSSH2_SOCKET_SEND_FLAGS(session));
if (ret != -1) { if (ret != -1) {
debugdump(session, "libssh2_packet_write send()", p->outbuf, ret); debugdump(session, "libssh2_transport_write send()", p->outbuf, ret);
} }
if (ret != total_length) { if (ret != total_length) {
if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) { if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {

80
src/transport.h Обычный файл
Просмотреть файл

@ -0,0 +1,80 @@
#ifndef __LIBSSH2_TRANSPORT_H
#define __LIBSSH2_TRANSPORT_H
/* Copyright (C) 2007 The Written Word, Inc. All rights reserved.
* Copyright (C) 2009 by Daniel Stenberg
* Author: Daniel Stenberg <daniel@haxx.se>
*
* 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.
*
* This file handles reading and writing to the SECSH transport layer. RFC4253.
*/
#include "libssh2_priv.h"
/*
* libssh2_transport_write
*
* Send a packet, encrypting it and adding a MAC code if necessary
* Returns 0 on success, non-zero on failure.
*
* Returns PACKET_EAGAIN if it would block - and if it does so, you should
* call this function again as soon as it is likely that more data can be
* sent, and this function should then be called with the same argument set
* (same data pointer and same data_len) until zero or failure is returned.
*
* NOTE: this function does not verify that 'data_len' is less than ~35000
* which is what all implementations should support at least as packet size.
* (RFC4253 section 6.1)
*/
int _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
unsigned long data_len);
/*
* _libssh2_transport_read
*
* Collect a packet into the input brigade block only controls whether or not
* to wait for a packet to start.
*
* Returns packet type added to input brigade (PACKET_NONE if nothing added),
* or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full
* packet.
*/
/*
* This function reads the binary stream as specified in chapter 6 of RFC4253
* "The Secure Shell (SSH) Transport Layer Protocol"
*/
libssh2pack_t _libssh2_transport_read(LIBSSH2_SESSION * session);
#endif /* __LIBSSH2_TRANSPORT_H */

Просмотреть файл

@ -1,4 +1,5 @@
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
* Copyright (c) 2009 by Daniel Stenberg
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@ -45,16 +46,17 @@
#include <sys/uio.h> #include <sys/uio.h>
#endif #endif
#include "transport.h"
/* {{{ proto libssh2_userauth_list /* libssh2_userauth_list
*
* List authentication methods * List authentication methods
* Will yield successful login if "none" happens to be allowable for this user * Will yield successful login if "none" happens to be allowable for this user
* Not a common configuration for any SSH server though * Not a common configuration for any SSH server though
* username should be NULL, or a null terminated string * username should be NULL, or a null terminated string
*/ */
LIBSSH2_API char * static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
libssh2_userauth_list(LIBSSH2_SESSION * session, const char *username, unsigned int username_len)
unsigned int username_len)
{ {
static const unsigned char reply_codes[3] = static const unsigned char reply_codes[3] =
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
@ -101,7 +103,7 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *username,
} }
if (session->userauth_list_state == libssh2_NB_state_created) { if (session->userauth_list_state == libssh2_NB_state_created) {
rc = _libssh2_packet_write(session, session->userauth_list_data, rc = _libssh2_transport_write(session, session->userauth_list_data,
session->userauth_list_data_len); session->userauth_list_data_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
@ -161,6 +163,23 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *username,
return (char *) session->userauth_list_data; return (char *) session->userauth_list_data;
} }
/* libssh2_userauth_list
*
* List authentication methods
* Will yield successful login if "none" happens to be allowable for this user
* Not a common configuration for any SSH server though
* username should be NULL, or a null terminated string
*/
LIBSSH2_API char *
libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user,
unsigned int user_len)
{
char *ptr;
BLOCK_ADJUST_ERRNO(ptr, session,
userauth_list(session, user, user_len));
return ptr;
}
/* /*
* libssh2_userauth_authenticated * libssh2_userauth_authenticated
* *
@ -173,16 +192,16 @@ libssh2_userauth_authenticated(LIBSSH2_SESSION * session)
return session->state & LIBSSH2_STATE_AUTHENTICATED; return session->state & LIBSSH2_STATE_AUTHENTICATED;
} }
/* }}} */
/* {{{ libssh2_userauth_password
/* userauth_password
* Plain ol' login * Plain ol' login
*/ */
LIBSSH2_API int static int
libssh2_userauth_password_ex(LIBSSH2_SESSION * session, const char *username, userauth_password(LIBSSH2_SESSION *session, const char *username,
unsigned int username_len, const char *password, unsigned int username_len, const char *password,
unsigned int password_len, unsigned int password_len,
LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))) LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
{ {
unsigned char *s; unsigned char *s;
static const unsigned char reply_codes[4] = static const unsigned char reply_codes[4] =
@ -208,8 +227,8 @@ libssh2_userauth_password_ex(LIBSSH2_SESSION * session, const char *username,
LIBSSH2_ALLOC(session, session->userauth_pswd_data_len); LIBSSH2_ALLOC(session, session->userauth_pswd_data_len);
if (!session->userauth_pswd_data) { if (!session->userauth_pswd_data) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for userauth-password request", "Unable to allocate memory for userauth-password"
0); " request", 0);
return -1; return -1;
} }
@ -244,7 +263,7 @@ libssh2_userauth_password_ex(LIBSSH2_SESSION * session, const char *username,
} }
if (session->userauth_pswd_state == libssh2_NB_state_created) { if (session->userauth_pswd_state == libssh2_NB_state_created) {
rc = _libssh2_packet_write(session, session->userauth_pswd_data, rc = _libssh2_transport_write(session, session->userauth_pswd_data,
session->userauth_pswd_data_len); session->userauth_pswd_data_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
@ -378,7 +397,7 @@ libssh2_userauth_password_ex(LIBSSH2_SESSION * session, const char *username,
} }
if (session->userauth_pswd_state == libssh2_NB_state_sent2) { if (session->userauth_pswd_state == libssh2_NB_state_sent2) {
rc = _libssh2_packet_write(session, rc = _libssh2_transport_write(session,
session->userauth_pswd_data, session->userauth_pswd_data,
session-> session->
userauth_pswd_data_len); userauth_pswd_data_len);
@ -425,7 +444,25 @@ libssh2_userauth_password_ex(LIBSSH2_SESSION * session, const char *username,
return -1; return -1;
} }
/* }}} */ /*
* libssh2_userauth_password_ex
*
* Plain ol' login
*/
LIBSSH2_API int
libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username,
unsigned int username_len, const char *password,
unsigned int password_len,
LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
{
int rc;
BLOCK_ADJUST(rc, session,
userauth_password(session, username, username_len,
password, password_len,
passwd_change_cb));
return rc;
}
/* /*
* file_read_publickey * file_read_publickey
@ -529,9 +566,9 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
return 0; return 0;
} }
/* }}} */
/* {{{ libssh2_file_read_privatekey
/* libssh2_file_read_privatekey
* Read a PEM encoded private key from an id_??? style file * Read a PEM encoded private key from an id_??? style file
*/ */
static int static int
@ -574,22 +611,19 @@ libssh2_file_read_privatekey(LIBSSH2_SESSION * session,
return 0; return 0;
} }
/* }}} */
/* {{{ libssh2_userauth_hostbased_fromfile_ex
/* userauth_hostbased_fromfile
* Authenticate using a keypair found in the named files * Authenticate using a keypair found in the named files
*/ */
LIBSSH2_API int static int
libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session, userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
const char *username, const char *username, unsigned int username_len,
unsigned int username_len, const char *publickey, const char *privatekey,
const char *publickey, const char *passphrase, const char *hostname,
const char *privatekey, unsigned int hostname_len,
const char *passphrase, const char *local_username,
const char *hostname, unsigned int local_username_len)
unsigned int hostname_len,
const char *local_username,
unsigned int local_username_len)
{ {
static const unsigned char reply_codes[3] = static const unsigned char reply_codes[3] =
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
@ -632,10 +666,9 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session,
*/ */
session->userauth_host_s = session->userauth_host_packet = session->userauth_host_s = session->userauth_host_packet =
LIBSSH2_ALLOC(session, LIBSSH2_ALLOC(session,
session->userauth_host_packet_len + 4 + (4 + session->userauth_host_packet_len + 4 +
session-> (4 + session->userauth_host_method_len) +
userauth_host_method_len) (4 + pubkeydata_len));
+ (4 + pubkeydata_len));
if (!session->userauth_host_packet) { if (!session->userauth_host_packet) {
LIBSSH2_FREE(session, session->userauth_host_method); LIBSSH2_FREE(session, session->userauth_host_method);
session->userauth_host_method = NULL; session->userauth_host_method = NULL;
@ -716,10 +749,14 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session,
if (sig_len > pubkeydata_len) { if (sig_len > pubkeydata_len) {
unsigned char *newpacket; unsigned char *newpacket;
/* Should *NEVER* happen, but...well.. better safe than sorry */ /* Should *NEVER* happen, but...well.. better safe than sorry */
newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet, session->userauth_host_packet_len + 4 + (4 + session->userauth_host_method_len) + (4 + sig_len)); /* PK sigblob */ newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet,
session->userauth_host_packet_len + 4 +
(4 + session->userauth_host_method_len)
+ (4 + sig_len)); /* PK sigblob */
if (!newpacket) { if (!newpacket) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Failed allocating additional space for userauth-hostbased packet", "Failed allocating additional space for "
"userauth-hostbased packet",
0); 0);
LIBSSH2_FREE(session, sig); LIBSSH2_FREE(session, sig);
LIBSSH2_FREE(session, session->userauth_host_packet); LIBSSH2_FREE(session, session->userauth_host_packet);
@ -760,7 +797,7 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session,
} }
if (session->userauth_host_state == libssh2_NB_state_created) { if (session->userauth_host_state == libssh2_NB_state_created) {
rc = _libssh2_packet_write(session, session->userauth_host_packet, rc = _libssh2_transport_write(session, session->userauth_host_packet,
session->userauth_host_s - session->userauth_host_s -
session->userauth_host_packet); session->userauth_host_packet);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
@ -809,24 +846,50 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session,
LIBSSH2_FREE(session, session->userauth_host_data); LIBSSH2_FREE(session, session->userauth_host_data);
session->userauth_host_data = NULL; session->userauth_host_data = NULL;
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
"Invalid signature for supplied public key, or bad username/public key combination", "Invalid signature for supplied public key, or bad "
"username/public key combination",
0); 0);
session->userauth_host_state = libssh2_NB_state_idle; session->userauth_host_state = libssh2_NB_state_idle;
return -1; return -1;
} }
/* }}} */ /* libssh2_userauth_hostbased_fromfile_ex
/* {{{ libssh2_userauth_publickey_fromfile_ex
* Authenticate using a keypair found in the named files * Authenticate using a keypair found in the named files
*/ */
LIBSSH2_API int LIBSSH2_API int
libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session, libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
const char *username, const char *user,
unsigned int username_len, unsigned int user_len,
const char *publickey, const char *publickey,
const char *privatekey, const char *privatekey,
const char *passphrase) const char *passphrase,
const char *host,
unsigned int host_len,
const char *localuser,
unsigned int localuser_len)
{
int rc;
BLOCK_ADJUST(rc, session,
userauth_hostbased_fromfile(session, user, user_len,
publickey, privatekey,
passphrase, host, host_len,
localuser, localuser_len));
return rc;
}
/*
* userauth_publickey_fromfile
* Authenticate using a keypair found in the named files
*/
static int
userauth_publickey_fromfile(LIBSSH2_SESSION *session,
const char *username,
unsigned int username_len,
const char *publickey,
const char *privatekey,
const char *passphrase)
{ {
unsigned long pubkeydata_len = 0; unsigned long pubkeydata_len = 0;
unsigned char reply_codes[4] = unsigned char reply_codes[4] =
@ -865,9 +928,8 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,
*/ */
session->userauth_pblc_s = session->userauth_pblc_packet = session->userauth_pblc_s = session->userauth_pblc_packet =
LIBSSH2_ALLOC(session, LIBSSH2_ALLOC(session,
session->userauth_pblc_packet_len + 4 + (4 + session->userauth_pblc_packet_len + 4 +
session-> (4 + session->userauth_pblc_method_len)
userauth_pblc_method_len)
+ (4 + pubkeydata_len)); + (4 + pubkeydata_len));
if (!session->userauth_pblc_packet) { if (!session->userauth_pblc_packet) {
LIBSSH2_FREE(session, session->userauth_pblc_method); LIBSSH2_FREE(session, session->userauth_pblc_method);
@ -916,7 +978,7 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,
} }
if (session->userauth_pblc_state == libssh2_NB_state_created) { if (session->userauth_pblc_state == libssh2_NB_state_created) {
rc = _libssh2_packet_write(session, session->userauth_pblc_packet, rc = _libssh2_transport_write(session, session->userauth_pblc_packet,
session->userauth_pblc_packet_len); session->userauth_pblc_packet_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
@ -1039,10 +1101,15 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,
if (sig_len > pubkeydata_len) { if (sig_len > pubkeydata_len) {
unsigned char *newpacket; unsigned char *newpacket;
/* Should *NEVER* happen, but...well.. better safe than sorry */ /* Should *NEVER* happen, but...well.. better safe than sorry */
newpacket = LIBSSH2_REALLOC(session, session->userauth_pblc_packet, session->userauth_pblc_packet_len + 4 + (4 + session->userauth_pblc_method_len) + (4 + sig_len)); /* PK sigblob */ newpacket = LIBSSH2_REALLOC(session,
session->userauth_pblc_packet,
session->userauth_pblc_packet_len + 4 +
(4 + session->userauth_pblc_method_len)
+ (4 + sig_len)); /* PK sigblob */
if (!newpacket) { if (!newpacket) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Failed allocating additional space for userauth-publickey packet", "Failed allocating additional space for "
"userauth-publickey packet",
0); 0);
LIBSSH2_FREE(session, sig); LIBSSH2_FREE(session, sig);
LIBSSH2_FREE(session, session->userauth_pblc_packet); LIBSSH2_FREE(session, session->userauth_pblc_packet);
@ -1085,7 +1152,7 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,
} }
if (session->userauth_pblc_state == libssh2_NB_state_sent1) { if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
rc = _libssh2_packet_write(session, session->userauth_pblc_packet, rc = _libssh2_transport_write(session, session->userauth_pblc_packet,
session->userauth_pblc_s - session->userauth_pblc_s -
session->userauth_pblc_packet); session->userauth_pblc_packet);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
@ -1133,22 +1200,44 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,
LIBSSH2_FREE(session, session->userauth_pblc_data); LIBSSH2_FREE(session, session->userauth_pblc_data);
session->userauth_pblc_data = NULL; session->userauth_pblc_data = NULL;
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
"Invalid signature for supplied public key, or bad username/public key combination", "Invalid signature for supplied public key, or bad "
"username/public key combination",
0); 0);
session->userauth_pblc_state = libssh2_NB_state_idle; session->userauth_pblc_state = libssh2_NB_state_idle;
return -1; return -1;
} }
/* }}} */ /* libssh2_userauth_publickey_fromfile_ex
* Authenticate using a keypair found in the named files
/* {{{ libssh2_userauth_keyboard_interactive
* Authenticate using a challenge-response authentication
*/ */
LIBSSH2_API int LIBSSH2_API int
libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session, libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
const char *username, const char *user,
unsigned int username_len, unsigned int user_len,
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback))) const char *publickey,
const char *privatekey,
const char *passphrase)
{
int rc;
BLOCK_ADJUST(rc, session,
userauth_publickey_fromfile(session, user, user_len,
publickey, privatekey,
passphrase));
return rc;
}
/*
* userauth_keyboard_interactive
*
* Authenticate using a challenge-response authentication
*/
static int
userauth_keyboard_interactive(LIBSSH2_SESSION * session,
const char *username,
unsigned int username_len,
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
{ {
unsigned char *s; unsigned char *s;
int rc; int rc;
@ -1171,19 +1260,23 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
memset(&session->userauth_kybd_packet_requirev_state, 0, memset(&session->userauth_kybd_packet_requirev_state, 0,
sizeof(session->userauth_kybd_packet_requirev_state)); sizeof(session->userauth_kybd_packet_requirev_state));
session->userauth_kybd_packet_len = 1 /* byte SSH_MSG_USERAUTH_REQUEST */ session->userauth_kybd_packet_len =
+ 4 + username_len /* string user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */ 1 /* byte SSH_MSG_USERAUTH_REQUEST */
+ 4 + 14 /* string service name (US-ASCII) */ + 4 + username_len /* string user name (ISO-10646 UTF-8, as
+ 4 + 20 /* string "keyboard-interactive" (US-ASCII) */ defined in [RFC-3629]) */
+ 4 + 0 /* string language tag (as defined in [RFC-3066]) */ + 4 + 14 /* string service name (US-ASCII) */
+ 4 + 0 /* string submethods (ISO-10646 UTF-8) */ + 4 + 20 /* string "keyboard-interactive" (US-ASCII) */
+ 4 + 0 /* string language tag (as defined in
[RFC-3066]) */
+ 4 + 0 /* string submethods (ISO-10646 UTF-8) */
; ;
session->userauth_kybd_data = s = session->userauth_kybd_data = s =
LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len); LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
if (!s) { if (!s) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive authentication", "Unable to allocate memory for "
"keyboard-interactive authentication",
0); 0);
return -1; return -1;
} }
@ -1223,7 +1316,7 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
} }
if (session->userauth_kybd_state == libssh2_NB_state_created) { if (session->userauth_kybd_state == libssh2_NB_state_created) {
rc = _libssh2_packet_write(session, session->userauth_kybd_data, rc = _libssh2_transport_write(session, session->userauth_kybd_data,
session->userauth_kybd_packet_len); session->userauth_kybd_packet_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
@ -1284,7 +1377,8 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
LIBSSH2_ALLOC(session, session->userauth_kybd_auth_name_len); LIBSSH2_ALLOC(session, session->userauth_kybd_auth_name_len);
if (!session->userauth_kybd_auth_name) { if (!session->userauth_kybd_auth_name) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive 'name' request field", "Unable to allocate memory for "
"keyboard-interactive 'name' request field",
0); 0);
goto cleanup; goto cleanup;
} }
@ -1300,7 +1394,9 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
session->userauth_kybd_auth_instruction_len); session->userauth_kybd_auth_instruction_len);
if (!session->userauth_kybd_auth_instruction) { if (!session->userauth_kybd_auth_instruction) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive 'instruction' request field", "Unable to allocate memory for "
"keyboard-interactive 'instruction' "
"request field",
0); 0);
goto cleanup; goto cleanup;
} }
@ -1324,7 +1420,8 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
session->userauth_kybd_num_prompts); session->userauth_kybd_num_prompts);
if (!session->userauth_kybd_prompts) { if (!session->userauth_kybd_prompts) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive prompts array", "Unable to allocate memory for "
"keyboard-interactive prompts array",
0); 0);
goto cleanup; goto cleanup;
} }
@ -1338,7 +1435,8 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
session->userauth_kybd_num_prompts); session->userauth_kybd_num_prompts);
if (!session->userauth_kybd_responses) { if (!session->userauth_kybd_responses) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive responses array", "Unable to allocate memory for "
"keyboard-interactive responses array",
0); 0);
goto cleanup; goto cleanup;
} }
@ -1355,7 +1453,8 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
session->userauth_kybd_prompts[i].length); session->userauth_kybd_prompts[i].length);
if (!session->userauth_kybd_prompts[i].text) { if (!session->userauth_kybd_prompts[i].text) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive prompt message", "Unable to allocate memory for "
"keyboard-interactive prompt message",
0); 0);
goto cleanup; goto cleanup;
} }
@ -1377,9 +1476,11 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
&session->abstract); &session->abstract);
_libssh2_debug(session, LIBSSH2_DBG_AUTH, _libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Keyboard-interactive response callback function invoked"); "Keyboard-interactive response callback function"
" invoked");
session->userauth_kybd_packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */ session->userauth_kybd_packet_len =
1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
+ 4 /* int num-responses */ + 4 /* int num-responses */
; ;
@ -1393,7 +1494,8 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len); LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
if (!s) { if (!s) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive response packet", "Unable to allocate memory for keyboard-"
"interactive response packet",
0); 0);
goto cleanup; goto cleanup;
} }
@ -1415,14 +1517,15 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
} }
if (session->userauth_kybd_state == libssh2_NB_state_sent1) { if (session->userauth_kybd_state == libssh2_NB_state_sent1) {
rc = _libssh2_packet_write(session, session->userauth_kybd_data, rc = _libssh2_transport_write(session, session->userauth_kybd_data,
session->userauth_kybd_packet_len); session->userauth_kybd_packet_len);
if (rc == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} }
if (rc) { if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send userauth-keyboard-interactive request", "Unable to send userauth-keyboard-interactive"
" request",
0); 0);
goto cleanup; goto cleanup;
} }
@ -1468,4 +1571,21 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
} }
} }
/* }}} */ /*
* libssh2_userauth_keyboard_interactive_ex
*
* Authenticate using a challenge-response authentication
*/
LIBSSH2_API int
libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session,
const char *user,
unsigned int user_len,
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
{
int rc;
BLOCK_ADJUST(rc, session,
userauth_keyboard_interactive(session, user, user_len,
response_callback));
return rc;
}