Compare commits
202 Commits
RELEASE.0.
...
beforenb-0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c63ef86075 | ||
![]() |
1b733d1196 | ||
![]() |
3c61a44224 | ||
![]() |
20527d9688 | ||
![]() |
09ee2d4086 | ||
![]() |
5859642888 | ||
![]() |
ba1eb9f8fc | ||
![]() |
e2f6518d95 | ||
![]() |
a139ab0b45 | ||
![]() |
f1e7eb7ae8 | ||
![]() |
b790cabf6a | ||
![]() |
d2be40421a | ||
![]() |
b1d855d1ac | ||
![]() |
1826e7365d | ||
![]() |
7f9ea39a5d | ||
![]() |
6cf4420264 | ||
![]() |
bfb71f3075 | ||
![]() |
1f232d69ed | ||
![]() |
f252d350ec | ||
![]() |
4c2c468b08 | ||
![]() |
a86a4e0cfc | ||
![]() |
b1f8bafb64 | ||
![]() |
c9d40afa14 | ||
![]() |
51b9ff0f16 | ||
![]() |
0d9a7e3c2e | ||
![]() |
75115045ae | ||
![]() |
be984707e2 | ||
![]() |
2afd706ca1 | ||
![]() |
fe979040a2 | ||
![]() |
0fab9e9614 | ||
![]() |
576d37dafd | ||
![]() |
a0eda7365e | ||
![]() |
1f79c7da95 | ||
![]() |
6ede32c5e2 | ||
![]() |
10efccbb83 | ||
![]() |
2e8d9217b4 | ||
![]() |
d3c334c3d6 | ||
![]() |
e1bebf979b | ||
![]() |
50d587e2bc | ||
![]() |
e0fe196e45 | ||
![]() |
dc994f64a9 | ||
![]() |
46cd4f42d8 | ||
![]() |
19690441cd | ||
![]() |
dc7cdb8cb0 | ||
![]() |
be4461e4cd | ||
![]() |
23d772867e | ||
![]() |
c090ac7ed1 | ||
![]() |
6873ada0b7 | ||
![]() |
5c904b112e | ||
![]() |
b4d7a4eede | ||
![]() |
22225099bc | ||
![]() |
2d8ee8b37c | ||
![]() |
219fa19a5f | ||
![]() |
5443c76c8e | ||
![]() |
79761a6455 | ||
![]() |
362d3466cf | ||
![]() |
6d65428511 | ||
![]() |
677005375b | ||
![]() |
8a2421bad1 | ||
![]() |
5cd3efc297 | ||
![]() |
f527a88095 | ||
![]() |
fd2368d2b1 | ||
![]() |
036bb51421 | ||
![]() |
c92d1a5a23 | ||
![]() |
862a758026 | ||
![]() |
f7f897df07 | ||
![]() |
ef8d1a2af8 | ||
![]() |
556cafc457 | ||
![]() |
75b5e06773 | ||
![]() |
91e496ff41 | ||
![]() |
6b1dc88b14 | ||
![]() |
14b9deef24 | ||
![]() |
82d762cae5 | ||
![]() |
1c1c74479e | ||
![]() |
3a33680e14 | ||
![]() |
38fea1973d | ||
![]() |
c63a212559 | ||
![]() |
a8451f58df | ||
![]() |
1dbe8ff365 | ||
![]() |
82424d6735 | ||
![]() |
3b1b45e644 | ||
![]() |
84f10fca87 | ||
![]() |
077ba3efd5 | ||
![]() |
ab26693769 | ||
![]() |
1854b4536f | ||
![]() |
1baaa31792 | ||
![]() |
7058b7fc2a | ||
![]() |
1e889ca947 | ||
![]() |
bebd14a011 | ||
![]() |
7063d24724 | ||
![]() |
8069fa6f9a | ||
![]() |
1961e07287 | ||
![]() |
ace0c8f00b | ||
![]() |
adee5e5653 | ||
![]() |
5f85317efa | ||
![]() |
09b93e4bb6 | ||
![]() |
19cad102f4 | ||
![]() |
4d7726c551 | ||
![]() |
37307a8778 | ||
![]() |
fbcdff2161 | ||
![]() |
c45992da55 | ||
![]() |
2207b99afb | ||
![]() |
1d7522bc06 | ||
![]() |
a4e61c265b | ||
![]() |
502a48afa1 | ||
![]() |
efc3841fd2 | ||
![]() |
f9d65b0984 | ||
![]() |
edcdf43264 | ||
![]() |
722470994a | ||
![]() |
14f00247a8 | ||
![]() |
78048973c5 | ||
![]() |
e15f5d97a0 | ||
![]() |
01de39e585 | ||
![]() |
6cc50263e2 | ||
![]() |
beca3742a2 | ||
![]() |
d6cfa7c6b9 | ||
![]() |
ae17fbcd2c | ||
![]() |
0c53895bc0 | ||
![]() |
dc446eff08 | ||
![]() |
aa6e9c6eca | ||
![]() |
2e097c7760 | ||
![]() |
77bd3c1215 | ||
![]() |
0e5eb4d9c5 | ||
![]() |
8ee79a5118 | ||
![]() |
0ad861d74c | ||
![]() |
b6d13ebe8a | ||
![]() |
06e1136ea0 | ||
![]() |
2a6c49a73a | ||
![]() |
da653774aa | ||
![]() |
9203a62789 | ||
![]() |
6de7ed8a7b | ||
![]() |
8937980044 | ||
![]() |
cc7703092f | ||
![]() |
7502920c7f | ||
![]() |
ff6f2dbe52 | ||
![]() |
e5ee4a5be3 | ||
![]() |
30bb7db0d1 | ||
![]() |
8d90bbfc28 | ||
![]() |
e9b0710b4b | ||
![]() |
379e510c87 | ||
![]() |
ebfbd22e59 | ||
![]() |
9a0ba35457 | ||
![]() |
023c54d95d | ||
![]() |
ba2f21eb85 | ||
![]() |
3ea661a574 | ||
![]() |
30755999c5 | ||
![]() |
8e0e6d81dd | ||
![]() |
cba673de6f | ||
![]() |
11b27e52c3 | ||
![]() |
f289bcdd54 | ||
![]() |
66e7462f01 | ||
![]() |
ed88c32368 | ||
![]() |
83b95eb13e | ||
![]() |
ba420fc7bf | ||
![]() |
ae9ad1ef6f | ||
![]() |
d3f854c21b | ||
![]() |
5d9c0d50f3 | ||
![]() |
35a3e7a6c0 | ||
![]() |
15b8489046 | ||
![]() |
dce388e9c5 | ||
![]() |
0138e36352 | ||
![]() |
d6039f39e4 | ||
![]() |
0e0ed2aff4 | ||
![]() |
7c64e21df6 | ||
![]() |
c67bb667aa | ||
![]() |
141ac5b856 | ||
![]() |
9f64f34dfe | ||
![]() |
a1b87a952c | ||
![]() |
7db9aeecf8 | ||
![]() |
99e5547442 | ||
![]() |
ef7496b29a | ||
![]() |
37c55becdc | ||
![]() |
47b96a9771 | ||
![]() |
0a9a5ffc22 | ||
![]() |
c6e5188fb4 | ||
![]() |
fe7ea0df58 | ||
![]() |
500169bf97 | ||
![]() |
10a0c20eae | ||
![]() |
2427c1b803 | ||
![]() |
159120f844 | ||
![]() |
fc1563a41d | ||
![]() |
c6bbe0d42f | ||
![]() |
a05bf84ecf | ||
![]() |
2c5c54e999 | ||
![]() |
5f2864c0b4 | ||
![]() |
4675d1242b | ||
![]() |
b59f2ccc1b | ||
![]() |
b25446d0a5 | ||
![]() |
064c6cde3a | ||
![]() |
2c5a8480b0 | ||
![]() |
87d61a39e8 | ||
![]() |
0e878271db | ||
![]() |
bc16411dd3 | ||
![]() |
096ef86627 | ||
![]() |
2b414db02e | ||
![]() |
5f7470700e | ||
![]() |
bfc2f5039e | ||
![]() |
a3735795dd | ||
![]() |
a891971a63 | ||
![]() |
d4677dba5b | ||
![]() |
d1ae5a501f | ||
![]() |
72c4c38e37 |
16
.cvsignore
16
.cvsignore
@@ -1,3 +1,5 @@
|
||||
.deps
|
||||
.libs
|
||||
*.lib
|
||||
*.pdb
|
||||
*.dll
|
||||
@@ -7,3 +9,17 @@
|
||||
Debug
|
||||
Release
|
||||
*.exp
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
config.guess
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
ssh2_sample
|
||||
|
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
|
19
Makefile.am
Normal file
19
Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
|
||||
SUBDIRS = src tests
|
||||
|
||||
include_HEADERS = include/libssh2.h include/libssh2_publickey.h \
|
||||
include/libssh2_sftp.h
|
||||
|
||||
# and a sample tool
|
||||
noinst_PROGRAMS = ssh2_sample
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include
|
||||
|
||||
ssh2_sample_SOURCES = ssh2_sample.c
|
||||
|
||||
ssh2_sample_LDADD = src/libssh2.la
|
||||
|
||||
EXTRA_DIST = LICENSE win32
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
62
Makefile.in
62
Makefile.in
@@ -1,62 +0,0 @@
|
||||
subdirs = src/
|
||||
top_srcdir = @top_srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
libdir = @exec_prefix@/lib
|
||||
incldir = @prefix@/include
|
||||
distdir = @top_srcdir@/dist
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = -c @CFLAGS@ -Iinclude/ -Wall -g
|
||||
LIBS = -lssh2 -Lsrc/
|
||||
INSTALL = @INSTALL@
|
||||
VERSION=@PACKAGE_VERSION@
|
||||
DISTLIB=libssh2-$(VERSION)
|
||||
|
||||
all:
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) all) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
$(CC) -o ssh2_sample.o ssh2_sample.c $(CFLAGS)
|
||||
$(CC) -o ssh2_sample ssh2_sample.o $(LIBS)
|
||||
install:
|
||||
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(incldir)
|
||||
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(libdir)
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) install) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
$(INSTALL) -m 644 include/libssh2.h $(DESTDIR)$(incldir)/
|
||||
$(INSTALL) -m 644 include/libssh2_sftp.h $(DESTDIR)$(incldir)/
|
||||
clean:
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) clean) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
rm -f ssh2_sample.o ssh2_sample
|
||||
dist:
|
||||
autoheader
|
||||
autoconf
|
||||
rm -f $(DISTLIB)
|
||||
ln -s . $(DISTLIB)
|
||||
tar -zcf $(DISTLIB).tar.gz \
|
||||
$(DISTLIB)/configure $(DISTLIB)/Makefile.in $(DISTLIB)/ssh2_sample.c \
|
||||
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \
|
||||
$(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh $(DISTLIB)/config.sub $(DISTLIB)/config.guess \
|
||||
$(DISTLIB)/src/*.c $(DISTLIB)/src/Makefile.in \
|
||||
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \
|
||||
$(DISTLIB)/include/libssh2_config.h.in
|
||||
rm -f $(DISTLIB)
|
||||
dist_nmake:
|
||||
autoheader
|
||||
autoconf
|
||||
rm -f $(DISTLIB)
|
||||
ln -s . $(DISTLIB)
|
||||
tar -zcf $(DISTLIB)-win32.tar.gz \
|
||||
$(DISTLIB)/NMakefile $(DISTLIB)/ssh2_sample.c $(DISTLIB)/src/*.c \
|
||||
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \
|
||||
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \
|
||||
$(DISTLIB)/win32/config.mk $(DISTLIB)/win32/libssh2_config.h $(DISTLIB)/win32/rules.mk
|
||||
rm -f $(DISTLIB)
|
||||
|
160
README
160
README
@@ -1,6 +1,166 @@
|
||||
libssh2 - SSH2 library
|
||||
======================
|
||||
|
||||
libssh2 is a library implementing the SSH2 protocol
|
||||
|
||||
Version
|
||||
------------
|
||||
|
||||
maximum SSH packet size is now some 35000 bytes
|
||||
|
||||
private include files are now in src/ and only public headers are in include/
|
||||
|
||||
automake and libtool are being used (increased portability)
|
||||
|
||||
fixed OpenSSL detection using pkg-config
|
||||
|
||||
simple self test added to tests/
|
||||
|
||||
libgcrypt is fully supported
|
||||
|
||||
Version 0.14
|
||||
------------
|
||||
|
||||
Plug leaks in EVP cipher init/shutdown. (Selcuk Gueney)
|
||||
|
||||
Allow socket_fd == 0 in libssh2_session_startup(). (puudeli)
|
||||
|
||||
Swap ordering of packet_add/packet-inspection to avoid inspect after free. (Selcuk)
|
||||
|
||||
Swap KEX_INIT ordering, send our KEX_INIT first.
|
||||
|
||||
Add check for oportunistic KEX_INIT packets. Burn bad guess if necessary.
|
||||
|
||||
Fix OpenSSL detection using pkg-config. (Dan Casey)
|
||||
|
||||
Version 0.13
|
||||
------------
|
||||
|
||||
Fixed channel not being marked closed when CHANNEL_CLOSE package cannot be sent. (David Robins)
|
||||
|
||||
Fixed payload packet allocation bug when invalid packet length received. (David Robins)
|
||||
|
||||
Fixed `make install' target for MacOSX.
|
||||
|
||||
Add terminating NULL character to readlink()/realpath() results.
|
||||
|
||||
BugFix#1436593: Apply build options for HPUX targets.
|
||||
|
||||
Version 0.12
|
||||
------------
|
||||
|
||||
Added support for publickey subsytem (not the same as publickey auth).
|
||||
|
||||
Fix x11_req. Multiple packet_len issues and error handling logic.
|
||||
(Thanks Simon Hart)
|
||||
|
||||
Fix generation of 'e' portion of Diffie-Hellman keyset.
|
||||
Use appropriate order for BN_rand() rather than fixed group1-specific value.
|
||||
|
||||
Re-fixed libssh2_sftp_rename_ex()
|
||||
Transport had right packet_len, but sftp layer still had extra 4 bytes.
|
||||
|
||||
Fixed build with newer OpenSSL headers.
|
||||
|
||||
Added extern "C" declarations to libssh2_sftp.h for C++ compatability.
|
||||
|
||||
Version 0.11
|
||||
------------
|
||||
|
||||
Added libssh2_chnnale_get_exit_status() -- Mikhail
|
||||
|
||||
Added libssh2_channel_wait_closed() -- Mikhail
|
||||
|
||||
Added libssh2_userauth_keyboard_interactive_ex() -- Mikhail
|
||||
|
||||
Added libssh2_channel_receive_window_adjust() to be able to increase the size of the receive window.
|
||||
|
||||
Added queueing for small window_adjust packets to avoid unnecessary packet conversation.
|
||||
|
||||
Fixed libssh2_sftp_rename_ex() to only send flags parameter if version >= 5 negotiated
|
||||
(not currently possible, but will be and might as well keep the API consistent).
|
||||
|
||||
Version 0.10
|
||||
------------
|
||||
|
||||
Added developer debugging hooks. See --enable-debug-* options to ./configure
|
||||
|
||||
Ignore extended data in the SFTP layer. With no other mechanism to deal with that data it'd just fill up and get stuck.
|
||||
|
||||
(Re)Fixed channel_write() to provide an opportunity for window space to become available again.
|
||||
|
||||
(Re)Fixed SFTP INIT to send the correct SFTP packet length.
|
||||
|
||||
Fixed segfault when client and host can't agree on a hostkey/crypt/mac/comp method. (Thanks puudeli)
|
||||
|
||||
Fixed major issue with sftp packet buffering mechanism. Using wrong blocking semantics. (No puudeli, YOU the man)
|
||||
|
||||
Reduced busy-looping of libssh2_sftp_packet_requirev.
|
||||
|
||||
Version 0.9
|
||||
-----------
|
||||
|
||||
Changed blocking_read to only block as much as necessary and not an arbitrary length of time. (Thanks Felix)
|
||||
|
||||
Fixed SFTP INIT/VERSION to exclude request_id and send correct maximum version number.
|
||||
|
||||
Fixed SFTP to be properly BC with version 1 and 2 servers.
|
||||
|
||||
Fixed libssh2_poll() to recognized closed sessions/channels.
|
||||
|
||||
Fixed libssh2_channel_write_ex() to fully block when set to blocking mode. Return actual bytes written as well. (Thanks deadem)
|
||||
|
||||
Added tests for -lm and -lsocket and add them when necessary.
|
||||
|
||||
Added libssh2_channel_window_read_ex() and libssh2_channel_window_write_ex()
|
||||
for examining the ssh transport windowing states.
|
||||
|
||||
Version 0.8
|
||||
-----------
|
||||
|
||||
Fix potential segfault in compression/decompression.
|
||||
|
||||
Fix compatability with older versions of OpenSSL
|
||||
|
||||
Swapped order of none,zlib compression modes to prefer no compression by default.
|
||||
|
||||
Added sys/uio.h for platforms (FBSD) which need it in order to define struct iovec.
|
||||
|
||||
Added libssh2_poll() to check status of sockets/channels/listeners.
|
||||
|
||||
Removed unnecessary inclusion of stdio.h (holdover from debugging)
|
||||
|
||||
Version 0.7
|
||||
-----------
|
||||
|
||||
Added libssh2_userauth_hostbased_fromfile_ex() for authenticating from hostkey.
|
||||
|
||||
Added configure recognition for MacOSX (Darwin) (Thanks Gabe)
|
||||
|
||||
Fixed extended data identification in libssh2_channel_read().
|
||||
|
||||
Fixed window adjust code. Hadn't acknowledged adjustments correctly.
|
||||
|
||||
Removed initial_window_size requirement for sending window adjust packet.
|
||||
|
||||
|
||||
Version 0.6
|
||||
-----------
|
||||
|
||||
Added LIBSSH2_FLAG_SIGPIPE to enable/disable SIGPIPE generated by send()/recv() calls. Default off.
|
||||
|
||||
Added libssh2_session_flag() to set optional session flags.
|
||||
|
||||
Collapsed exchanging_keys/newkeys/authenticated flags into single state attribute.
|
||||
|
||||
Fix zlib compression issue when internal buffer state misses partial sync.
|
||||
|
||||
Fix segfault when libssh2_session_methods() is called prior to session_startup().
|
||||
|
||||
Fixed client to server channel windowing. Pervent send queue overruns.
|
||||
|
||||
Swapped banner send/receive order (send first, then wait for response).
|
||||
|
||||
Version 0.5
|
||||
-----------
|
||||
|
||||
|
149
acinclude.m4
Normal file
149
acinclude.m4
Normal file
@@ -0,0 +1,149 @@
|
||||
|
||||
dnl **********************************************************************
|
||||
dnl CURL_DETECT_ICC ([ACTION-IF-YES])
|
||||
dnl
|
||||
dnl check if this is the Intel ICC compiler, and if so run the ACTION-IF-YES
|
||||
dnl sets the $ICC variable to "yes" or "no"
|
||||
dnl **********************************************************************
|
||||
AC_DEFUN([CURL_DETECT_ICC],
|
||||
[
|
||||
ICC="no"
|
||||
AC_MSG_CHECKING([for icc in use])
|
||||
if test "$GCC" = "yes"; then
|
||||
dnl check if this is icc acting as gcc in disguise
|
||||
AC_EGREP_CPP([^__INTEL_COMPILER], [__INTEL_COMPILER],
|
||||
dnl action if the text is found, this it has not been replaced by the
|
||||
dnl cpp
|
||||
ICC="no",
|
||||
dnl the text was not found, it was replaced by the cpp
|
||||
ICC="yes"
|
||||
AC_MSG_RESULT([yes])
|
||||
[$1]
|
||||
)
|
||||
fi
|
||||
if test "$ICC" = "no"; then
|
||||
# this is not ICC
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl We create a function for detecting which compiler we use and then set as
|
||||
dnl pendantic compiler options as possible for that particular compiler. The
|
||||
dnl options are only used for debug-builds.
|
||||
|
||||
AC_DEFUN([CURL_CC_DEBUG_OPTS],
|
||||
[
|
||||
if test "z$ICC" = "z"; then
|
||||
CURL_DETECT_ICC
|
||||
fi
|
||||
|
||||
if test "$GCC" = "yes"; then
|
||||
|
||||
dnl figure out gcc version!
|
||||
AC_MSG_CHECKING([gcc version])
|
||||
gccver=`$CC -dumpversion`
|
||||
num1=`echo $gccver | cut -d . -f1`
|
||||
num2=`echo $gccver | cut -d . -f2`
|
||||
gccnum=`(expr $num1 "*" 100 + $num2) 2>/dev/null`
|
||||
AC_MSG_RESULT($gccver)
|
||||
|
||||
if test "$ICC" = "yes"; then
|
||||
dnl this is icc, not gcc.
|
||||
|
||||
dnl ICC warnings we ignore:
|
||||
dnl * 269 warns on our "%Od" printf formatters for curl_off_t output:
|
||||
dnl "invalid format string conversion"
|
||||
dnl * 279 warns on static conditions in while expressions
|
||||
dnl * 981 warns on "operands are evaluated in unspecified order"
|
||||
dnl * 1418 "external definition with no prior declaration"
|
||||
dnl * 1419 warns on "external declaration in primary source file"
|
||||
dnl which we know and do on purpose.
|
||||
|
||||
WARN="-wd279,269,981,1418,1419"
|
||||
|
||||
if test "$gccnum" -gt "600"; then
|
||||
dnl icc 6.0 and older doesn't have the -Wall flag
|
||||
WARN="-Wall $WARN"
|
||||
fi
|
||||
else dnl $ICC = yes
|
||||
dnl this is a set of options we believe *ALL* gcc versions support:
|
||||
WARN="-W -Wall -Wwrite-strings -pedantic -Wpointer-arith -Wnested-externs -Winline -Wmissing-prototypes"
|
||||
|
||||
dnl -Wcast-align is a bit too annoying on all gcc versions ;-)
|
||||
|
||||
if test "$gccnum" -ge "207"; then
|
||||
dnl gcc 2.7 or later
|
||||
WARN="$WARN -Wmissing-declarations"
|
||||
fi
|
||||
|
||||
if test "$gccnum" -gt "295"; then
|
||||
dnl only if the compiler is newer than 2.95 since we got lots of
|
||||
dnl "`_POSIX_C_SOURCE' is not defined" in system headers with
|
||||
dnl gcc 2.95.4 on FreeBSD 4.9!
|
||||
WARN="$WARN -Wundef -Wno-long-long -Wsign-compare"
|
||||
fi
|
||||
|
||||
if test "$gccnum" -ge "296"; then
|
||||
dnl gcc 2.96 or later
|
||||
WARN="$WARN -Wfloat-equal"
|
||||
fi
|
||||
|
||||
if test "$gccnum" -gt "296"; then
|
||||
dnl this option does not exist in 2.96
|
||||
WARN="$WARN -Wno-format-nonliteral"
|
||||
fi
|
||||
|
||||
dnl -Wunreachable-code seems totally unreliable on my gcc 3.3.2 on
|
||||
dnl on i686-Linux as it gives us heaps with false positives.
|
||||
dnl Also, on gcc 4.0.X it is totally unbearable and complains all
|
||||
dnl over making it unusable for generic purposes. Let's not use it.
|
||||
|
||||
if test "$gccnum" -ge "303"; then
|
||||
dnl gcc 3.3 and later
|
||||
WARN="$WARN -Wendif-labels -Wstrict-prototypes"
|
||||
fi
|
||||
|
||||
if test "$gccnum" -ge "304"; then
|
||||
# try these on gcc 3.4
|
||||
WARN="$WARN -Wdeclaration-after-statement"
|
||||
fi
|
||||
|
||||
for flag in $CPPFLAGS; do
|
||||
case "$flag" in
|
||||
-I*)
|
||||
dnl Include path, provide a -isystem option for the same dir
|
||||
dnl to prevent warnings in those dirs. The -isystem was not very
|
||||
dnl reliable on earlier gcc versions.
|
||||
add=`echo $flag | sed 's/^-I/-isystem /g'`
|
||||
WARN="$WARN $add"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
fi dnl $ICC = no
|
||||
|
||||
CFLAGS="$CFLAGS $WARN"
|
||||
|
||||
AC_MSG_NOTICE([Added this set of compiler options: $WARN])
|
||||
|
||||
else dnl $GCC = yes
|
||||
|
||||
AC_MSG_NOTICE([Added no extra compiler options])
|
||||
|
||||
fi dnl $GCC = yes
|
||||
|
||||
dnl strip off optimizer flags
|
||||
NEWFLAGS=""
|
||||
for flag in $CFLAGS; do
|
||||
case "$flag" in
|
||||
-O*)
|
||||
dnl echo "cut off $flag"
|
||||
;;
|
||||
*)
|
||||
NEWFLAGS="$NEWFLAGS $flag"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
CFLAGS=$NEWFLAGS
|
||||
|
||||
]) dnl end of AC_DEFUN()
|
7
buildconf
Executable file
7
buildconf
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
${LIBTOOLIZE:-libtoolize} --copy --automake --force
|
||||
${ACLOCAL:-aclocal} -I m4 $ACLOCAL_FLAGS
|
||||
${AUTOHEADER:-autoheader}
|
||||
${AUTOCONF:-autoconf}
|
||||
${AUTOMAKE:-automake} --add-missing --copy
|
1415
config.guess
vendored
1415
config.guess
vendored
File diff suppressed because it is too large
Load Diff
1510
config.sub
vendored
1510
config.sub
vendored
File diff suppressed because it is too large
Load Diff
152
configure.in
152
configure.in
@@ -1,34 +1,62 @@
|
||||
# AC_PREREQ(2.57)
|
||||
AC_INIT(libssh2,0.5,sarag@libssh2.org)
|
||||
AC_INIT(libssh2, 0.15, libssh2-devel@lists.sourceforge.net)
|
||||
AM_INIT_AUTOMAKE(libssh2, 0.15)
|
||||
AC_CONFIG_SRCDIR([src])
|
||||
AC_CONFIG_HEADER([include/libssh2_config.h])
|
||||
AC_CONFIG_HEADER([src/libssh2_config.h])
|
||||
AB_INIT
|
||||
|
||||
# Check for the OS.
|
||||
# Daniel's note: this should not be necessary and we need to work to
|
||||
# get this removed.
|
||||
AC_CANONICAL_HOST
|
||||
case "$host" in
|
||||
*-cygwin)
|
||||
SHLIB_SUFFIX_NAME="dll"
|
||||
SHLIB_LDFLAGS="-shared"
|
||||
CFLAGS="$CFLAGS -DLIBSSH2_WIN32"
|
||||
;;
|
||||
*darwin*)
|
||||
CFLAGS="$CFLAGS -DLIBSSH2_DARWIN"
|
||||
;;
|
||||
*hpux*)
|
||||
;;
|
||||
*)
|
||||
SHLIB_SUFFIX_NAME="so"
|
||||
SHLIB_LDFLAGS="-shared"
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CHECK_LIB(socket, socket, [
|
||||
SHLIB_LDFLAGS="$SHLIB_LDFLAGS -lsocket"
|
||||
LIBS="$LIBS -lsocket"
|
||||
])
|
||||
AC_CHECK_LIB(m, ceil, [ SHLIB_LDFLAGS="$SHLIB_LDFLAGS -lm" ])
|
||||
|
||||
|
||||
AC_SUBST(SHLIB_SUFFIX_NAME)
|
||||
AC_SUBST(SHLIB_LDFLAGS)
|
||||
AC_SUBST(LIBS)
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_LIBTOOL
|
||||
AC_C_BIGENDIAN
|
||||
if test -z "$PKG_CONFIG"; then
|
||||
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
|
||||
fi
|
||||
|
||||
# Look for libgcrypt.
|
||||
AC_ARG_WITH(libgcrypt,
|
||||
AC_HELP_STRING([--with-libgcrypt],[Use libgcrypt for crypto]),
|
||||
use_libgcrypt=$withval,use_libgcrypt=no)
|
||||
if test "$use_libgcrypt" != "no"; then
|
||||
AM_PATH_LIBGCRYPT(1:1.2.2,,use_libgcrypt=no)
|
||||
fi
|
||||
if test "$use_libgcrypt" != "no"; then
|
||||
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
|
||||
LDFLAGS="$LDFLAGS $LIBGCRYPT_LIBS"
|
||||
AC_DEFINE(LIBSSH2_LIBGCRYPT, 1, [Use libgcrypt])
|
||||
fi
|
||||
AM_CONDITIONAL(LIBGCRYPT, test "$use_libgcrypt" != "no")
|
||||
|
||||
#
|
||||
# Look for OpenSSL
|
||||
#
|
||||
@@ -36,20 +64,25 @@ AC_ARG_WITH(openssl,
|
||||
AC_HELP_STRING([--with-openssl=DIR],[Look for OpenSSL in PATH]),
|
||||
[LIBSSH2_OPENSSL_DIR=$withval],[LIBSSH2_OPENSSL_DIR=yes])
|
||||
|
||||
if test "$use_libgcrypt" = "no"; then
|
||||
|
||||
if test "$LIBSSH2_OPENSSL_DIR" = "no" || test "$LIBSSH2_OPENSSL_DIR" = "yes"; then
|
||||
unset LIBSSH2_OPENSSL_DIR
|
||||
fi
|
||||
|
||||
found_openssl=no
|
||||
pkgcfg_openssl=no
|
||||
unset OPENSSL_INCDIR
|
||||
unset OPENSSL_LIBDIR
|
||||
unset OPENSSL_INCLINE
|
||||
unset OPENSSL_LIBLINE
|
||||
|
||||
AC_MSG_CHECKING([for OpenSSL])
|
||||
|
||||
# Explicit path given, use it rather than pkg-config
|
||||
if test ! -z "$LIBSSH2_OPENSSL_DIR"; then
|
||||
found_openssl=yes
|
||||
OPENSSL_LIBDIR=$LIBSSH2_OPENSSL_DIR/lib
|
||||
OPENSSL_LIBLINE="-L$LIBSSH2_OPENSSL_DIR/lib -lcrypto"
|
||||
OPENSSL_INCLINE="-I$LIBSSH2_OPENSSL_DIR/include"
|
||||
OPENSSL_INCDIR=$LIBSSH2_OPENSSL_DIR/include
|
||||
AC_MSG_RESULT([Using explicit path $LIBSSH2_OPENSSL_DIR])
|
||||
fi
|
||||
@@ -57,8 +90,9 @@ fi
|
||||
# If pkg-config is found try using it
|
||||
if test "$found_openssl" = "no" && test -x "$PKG_CONFIG" && $PKG_CONFIG --exists openssl; then
|
||||
found_openssl=yes
|
||||
OPENSSL_LIBDIR=`$PKG_CONFIG --libs openssl`
|
||||
OPENSSL_INCDIR=`$PKG_CONFIG --variable=includedir openssl`
|
||||
pkgcfg_openssl=yes
|
||||
OPENSSL_LIBLINE=`$PKG_CONFIG --libs openssl`
|
||||
OPENSSL_INCLINE=`$PKG_CONFIG --cflags-only-I openssl`
|
||||
AC_MSG_RESULT([Using paths from pkg-config])
|
||||
fi
|
||||
|
||||
@@ -68,39 +102,45 @@ if test "$found_openssl" = "no"; then
|
||||
|
||||
for i in $OPENSSL_SEARCH_PATH; do
|
||||
if test -r $i/include/openssl/evp.h; then
|
||||
OPENSSL_INCLINE="-I$i/include"
|
||||
OPENSSL_INCDIR=$i/include
|
||||
fi
|
||||
if test -r $i/include/openssl/hmac.h; then
|
||||
OPENSSL_INCLINE="-I$i/include"
|
||||
OPENSSL_INCDIR=$i/include
|
||||
fi
|
||||
if test -r $i/lib/libcrypto.a -o -r $i/lib/libcrypto.$SHLIB_SUFFIX_NAME; then
|
||||
OPENSSL_LIBDIR=$i/lib
|
||||
OPENSSL_LIBLINE="-L$i/lib -lcrypto"
|
||||
fi
|
||||
test -n "$OPENSSL_INCDIR" && test -n "$OPENSSL_LIBDIR" && break
|
||||
test -n "$OPENSSL_INCLINE" && test -n "$OPENSSL_LIBLINE" && break
|
||||
done
|
||||
|
||||
if test -z "$OPENSSL_INCDIR"; then
|
||||
if test -z "$OPENSSL_INCLINE"; then
|
||||
AC_MSG_ERROR([Cannot find OpenSSL's <evp.h> or <hmac.h>])
|
||||
fi
|
||||
|
||||
if test -z "$OPENSSL_LIBDIR"; then
|
||||
if test -z "$OPENSSL_LIBLINE"; then
|
||||
AC_MSG_ERROR([Cannot find OpenSSL's libcrypto])
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT([$OPENSSL_INCDIR $OPENSSL_LIBDIR])
|
||||
AC_MSG_RESULT([$OPENSSL_INCLINE $OPENSSL_LIBLINE])
|
||||
fi
|
||||
|
||||
#
|
||||
# Confirm required OpenSSL libs
|
||||
#
|
||||
if test ! -r $OPENSSL_INCDIR/openssl/bn.h || test ! -r $OPENSSL_INCDIR/openssl/evp.h || \
|
||||
if test ! "$pkgcfg_openssl" = "yes"; then
|
||||
if test ! -r $OPENSSL_INCDIR/openssl/bn.h || test ! -r $OPENSSL_INCDIR/openssl/evp.h || \
|
||||
test ! -r $OPENSSL_INCDIR/openssl/hmac.h || test ! -r $OPENSSL_INCDIR/openssl/pem.h || \
|
||||
test ! -r $OPENSSL_INCDIR/openssl/sha.h; then
|
||||
AC_MSG_ERROR([Missing one or more of <openssl/bn.h>, <openssl/evp.h>, <openssl/hmac.h>, <openssl/pem.h>, <openssl/sha.h>])
|
||||
fi
|
||||
fi
|
||||
|
||||
CFLAGS="$CFLAGS -I$OPENSSL_INCDIR"
|
||||
LDFLAGS="$LDFLAGS -L$OPENSSL_LIBDIR -lcrypto"
|
||||
CFLAGS="$CFLAGS $OPENSSL_INCLINE"
|
||||
LDFLAGS="$LDFLAGS $OPENSSL_LIBLINE"
|
||||
|
||||
fi
|
||||
|
||||
#
|
||||
# zlib
|
||||
@@ -155,13 +195,83 @@ if test "$GEX_NEW" != "no"; then
|
||||
AC_DEFINE(LIBSSH2_DH_GEX_NEW, 1, [Enable newer diffie-hellman-group-exchange-sha1 syntax])
|
||||
fi
|
||||
|
||||
#
|
||||
# Optional debugging -- Meant for developer maintenance only
|
||||
# When enabled, the relevant debugging information will be written on stderr
|
||||
#
|
||||
AC_ARG_ENABLE(debug-transport,
|
||||
AC_HELP_STRING([--enable-debug-transport],[Output transport layer debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_TRANSPORT, 1, [Output transport layer debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-kex,
|
||||
AC_HELP_STRING([--enable-debug-kex],[Output Key Exchange debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_KEX, 1, [Output Key Exchange debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-userauth,
|
||||
AC_HELP_STRING([--enable-debug-userauth],[Output userauth debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_USERAUTH, 1, [Output userauth layer debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-channel,
|
||||
AC_HELP_STRING([--enable-debug-connection],[Output connection layer debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_CONNECTION, 1, [Output connection layer debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-scp,
|
||||
AC_HELP_STRING([--enable-debug-scp],[Output scp subsystem debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_SCP, 1, [Output scp subsystem debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-sftp,
|
||||
AC_HELP_STRING([--enable-debug-sftp],[Output sftp subsystem debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_SFTP, 1, [Output sftp subsystem debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-publickey,
|
||||
AC_HELP_STRING([--enable-debug-publickey],[Output publickey subsystem debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_PUBLICKEY, 1, [Output publickey subsystem debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-errors,
|
||||
AC_HELP_STRING([--enable-debug-errors],[Output failure events to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr])])
|
||||
AC_ARG_ENABLE(debug-all,
|
||||
AC_HELP_STRING([--enable-debug-all],[Output debugging info for all layers to stderr]),
|
||||
[
|
||||
AC_DEFINE(LIBSSH2_DEBUG_TRANSPORT, 1, [Output transport layer debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_KEX, 1, [Output Key Exchange debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_USERAUTH, 1, [Output userauth layer debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_CONNECTION, 1, [Output connection layer debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_SCP, 1, [Output scp subsystem debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_SFTP, 1, [Output sftp subsystem debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_PUBLICKEY, 1, [Output publickey subsystem debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr])
|
||||
])
|
||||
|
||||
|
||||
dnl ************************************************************
|
||||
dnl option to switch on compiler debug options
|
||||
dnl
|
||||
AC_MSG_CHECKING([whether to enable pedantic and debug compiler options])
|
||||
AC_ARG_ENABLE(debug-build,
|
||||
AC_HELP_STRING([--enable-debug-build],[Enable pedantic debug options])
|
||||
AC_HELP_STRING([--disable-debug-build],[Disable debug options]),
|
||||
[ case "$enableval" in
|
||||
no)
|
||||
AC_MSG_RESULT(no)
|
||||
;;
|
||||
*) AC_MSG_RESULT(yes)
|
||||
|
||||
CPPFLAGS="$CPPFLAGS -DLIBSSH2DEBUG"
|
||||
CFLAGS="$CFLAGS -g"
|
||||
|
||||
dnl set compiler "debug" options to become more picky, and remove
|
||||
dnl optimize options from CFLAGS
|
||||
CURL_CC_DEBUG_OPTS
|
||||
;;
|
||||
esac
|
||||
],
|
||||
AC_MSG_RESULT(no)
|
||||
)
|
||||
|
||||
# Checks for header files.
|
||||
# AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h])
|
||||
AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h sys/uio.h sys/select.h])
|
||||
AC_CHECK_FUNCS(poll gettimeofday select)
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
src/Makefile])
|
||||
src/Makefile
|
||||
tests/Makefile])
|
||||
AC_OUTPUT
|
||||
|
16
docs/libssh2_channel_forward_accept.3
Normal file
16
docs/libssh2_channel_forward_accept.3
Normal file
@@ -0,0 +1,16 @@
|
||||
.\" $Id: libssh2_channel_forward_accept.3,v 1.1 2006/12/21 14:09:12 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_forward_accept 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_forward_accept - accept a queued connection
|
||||
.SH SYNOPSIS
|
||||
.B #include <libssh2.h>
|
||||
|
||||
.B LIBSSH2_CHANNEL * libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
|
||||
.SH DESCRIPTION
|
||||
\fIlistener\fP is a forwarding listener instance as returned by
|
||||
\fBlibssh2_channel_forward_listen(3)\fP.
|
||||
.SH RETURN VALUE
|
||||
A newly allocated channel instance or NULL on failure.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_channel_forward_listen(3)
|
40
docs/libssh2_channel_forward_listen_ex.3
Normal file
40
docs/libssh2_channel_forward_listen_ex.3
Normal file
@@ -0,0 +1,40 @@
|
||||
.\" $Id: libssh2_channel_forward_listen_ex.3,v 1.1 2006/12/21 14:09:13 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_forward_listen_ex 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_forward_listen_ex - listen to inbound connections
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
LIBSSH2_LISTENER * libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session,
|
||||
char *host,
|
||||
int port,
|
||||
int *bound_port,
|
||||
int queue_maxsize);
|
||||
|
||||
LIBSSH2_LISTENER * libssh2_channel_forward_listen(LIBSSH2_SESSION *session,
|
||||
int port);
|
||||
.SH DESCRIPTION
|
||||
Instruct the remote SSH server to begin listening for inbound TCP/IP
|
||||
connections. New connections will be queued by the library until accepted by
|
||||
\fIlibssh2_channel_forward_accept(3)\fP.
|
||||
|
||||
\fIsession\fP - instance as returned by libssh2_session_init().
|
||||
|
||||
\fIhost\fP - specific address to bind to on the remote host. Binding to
|
||||
0.0.0.0 (default when NULL is passed) will bind to all available addresses.
|
||||
|
||||
\fIport\fP - port to bind to on the remote host. When 0 is passed, the remote
|
||||
host will select the first available dynamic port.
|
||||
|
||||
\fIbound_port\fP - Populated with the actual port bound on the remote
|
||||
host. Useful when requesting dynamic port numbers.
|
||||
|
||||
\fIqueue_maxsize\fP - Maximum nuber of pending connections to queue before
|
||||
rejecting further attempts.
|
||||
|
||||
\fIlibssh2_channel_forward_listen(3)\fP is a macro.
|
||||
.SH RETURN VALUE
|
||||
A newly allocated LIBSSH2_LISTENER instance or NULL on failure.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_channel_forward_accept(3)
|
36
docs/libssh2_channel_read_ex.3
Normal file
36
docs/libssh2_channel_read_ex.3
Normal file
@@ -0,0 +1,36 @@
|
||||
.\" $Id: libssh2_channel_read_ex.3,v 1.4 2007/02/02 16:11:55 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_read_ex 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_read_ex - read data from a channel stream
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
int libssh2_channel_read(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
|
||||
int libssh2_channel_read_stderr(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
.SH DESCRIPTION
|
||||
Attempt to read data from an active channel stream. All channel streams have
|
||||
one standard I/O substream (stream_id == 0), and may have up to 2^32 extended
|
||||
data streams as identified by the selected \fIstream_id\fP. The SSH2 protocol
|
||||
currently defines a stream ID of 1 to be the stderr substream.
|
||||
|
||||
\fIchannel\fP - active channel stream to read from.
|
||||
|
||||
\fIstream_id\fP - substream ID number (e.g. 0 or SSH_EXTENDED_DATA_STDERR)
|
||||
|
||||
\fIbuf\fP - pointer to storage buffer to read data into
|
||||
|
||||
\fIbuflen\fP - size of the buf storage
|
||||
|
||||
\fIlibssh2_channel_read(3)\fP and \fIlibssh2_channel_read_stderr(3)\fP are
|
||||
macros.
|
||||
.SH RETURN VALUE
|
||||
Actual number of bytes read or negative on failure.
|
||||
.SH "SEE ALSO"
|
||||
|
37
docs/libssh2_channel_readnb_ex.3
Normal file
37
docs/libssh2_channel_readnb_ex.3
Normal file
@@ -0,0 +1,37 @@
|
||||
.\" $Id: libssh2_channel_readnb_ex.3,v 1.1 2007/02/02 16:09:12 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_read_ex 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_read_ex - read data from a channel stream
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_channel_readnb_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
int libssh2_channel_readnb(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
|
||||
int libssh2_channel_readnb_stderr(LIBSSH2_CHANNEL *channel, char *buf,
|
||||
size_t buflen);
|
||||
.SH DESCRIPTION
|
||||
Attempt to read data from an active channel stream. All channel streams have
|
||||
one standard I/O substream (stream_id == 0), and may have up to 2^32 extended
|
||||
data streams as identified by the selected \fIstream_id\fP. The SSH2 protocol
|
||||
currently defines a stream ID of 1 to be the stderr substream.
|
||||
|
||||
\fIchannel\fP - active channel stream to read from.
|
||||
|
||||
\fIstream_id\fP - substream ID number (e.g. 0 or SSH_EXTENDED_DATA_STDERR)
|
||||
|
||||
\fIbuf\fP - pointer to storage buffer to read data into
|
||||
|
||||
\fIbuflen\fP - size of the buf storage
|
||||
|
||||
\fIlibssh2_channel_read(3)\fP and \fIlibssh2_channel_read_stderr(3)\fP are
|
||||
macros.
|
||||
.SH RETURN VALUE
|
||||
Actual number of bytes read or negative on failure. It returns
|
||||
LIBSSH2CHANNEL_EAGAIN when it would otherwise block. While
|
||||
LIBSSH2CHANNEL_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
.SH "SEE ALSO"
|
23
docs/libssh2_channel_set_blocking.3
Normal file
23
docs/libssh2_channel_set_blocking.3
Normal file
@@ -0,0 +1,23 @@
|
||||
.\" $Id: libssh2_channel_set_blocking.3,v 1.1 2006/12/21 14:09:13 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_channel_set_blocking 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_set_blocking - set or clear blocking mode on channel
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
|
||||
.SH DESCRIPTION
|
||||
Set or clear blocking mode on the selected channel. If a read is performed on
|
||||
a channel with no data currently available, a blocking channel will wait for
|
||||
data to arrive and return what it receives. A non-blocking channel will return
|
||||
immediately with an empty buffer.
|
||||
|
||||
\fIchannel\fP - channel stream to set or clean blocking status on.
|
||||
|
||||
\fIblocking\fP - Set to a non-zero value to make the channel block, or zero to
|
||||
make it non-blocking.
|
||||
.SH RETURN VALUE
|
||||
None
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_channel_read_ex(3)
|
17
docs/libssh2_session_free.3
Normal file
17
docs/libssh2_session_free.3
Normal file
@@ -0,0 +1,17 @@
|
||||
.\" $Id: libssh2_session_free.3,v 1.1 2006/12/21 14:09:13 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_session_free 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_free - frees resources associated with a session instance
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
void libssh2_session_free(LIBSSH2_SESSION *session);
|
||||
.SH DESCRIPTION
|
||||
Frees resources associated with a session instance. Typically called after
|
||||
\fIlibssh2_session_disconnect(3)\fP.
|
||||
.SH RETURN VALUE
|
||||
None
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_session_init(3),
|
||||
.BI libssh2_session_disconnect(3)
|
29
docs/libssh2_session_init.3
Normal file
29
docs/libssh2_session_init.3
Normal file
@@ -0,0 +1,29 @@
|
||||
.\" $Id: libssh2_session_init.3,v 1.1 2006/12/21 14:09:13 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_session_init 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_init - initializes an SSH session object
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
LIBSSH2_SESSION *libssh2_session_init_ex(
|
||||
LIBSSH2_ALLOC_FUNC((*myalloc)),
|
||||
LIBSSH2_FREE_FUNC((*myfree)),
|
||||
LIBSSH2_REALLOC_FUNC((*myrealloc)),
|
||||
void *abstract);
|
||||
|
||||
LIBSSH2_SESSION *libssh2_session_init(void);
|
||||
.SH DESCRIPTION
|
||||
Initializes an SSH session object. By default system memory allocators
|
||||
(malloc(), free(), realloc()) will be used for any dynamicly allocated memory
|
||||
blocks. Alternate memory allocation functions may be specified using the
|
||||
extended version of this API call, and/or optional application specific data
|
||||
may be attached to the session object.
|
||||
|
||||
This method must be called first, prior to configuring session options or
|
||||
starting up an SSH session with a remote server.
|
||||
.SH RETURN VALUE
|
||||
Pointer to a newly allocated LIBSSH2_SESSION instance, or NULL on errors.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_session_free(3),
|
||||
.BI libssh2_session_startup(3)
|
16
docs/libssh2_session_startup.3
Normal file
16
docs/libssh2_session_startup.3
Normal file
@@ -0,0 +1,16 @@
|
||||
.\" $Id: libssh2_session_startup.3,v 1.2 2007/01/02 05:47:00 gusarov Exp $
|
||||
.\"
|
||||
.TH libssh2_session_startup 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_startup - begin transport layer
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
|
||||
.SH DESCRIPTION
|
||||
Begin transport layer protocol negotiation with the connected host.
|
||||
.SH RETURN VALUE
|
||||
0 on success, \-1 on failure
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_session_free(3),
|
||||
.BI libssh2_session_init(3)
|
20
docs/libssh2_sftp_init.3
Normal file
20
docs/libssh2_sftp_init.3
Normal file
@@ -0,0 +1,20 @@
|
||||
.\" $Id: libssh2_sftp_init.3,v 1.1 2007/02/02 16:09:12 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_sftp_init 3 "23 Jan 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_sftp_init -
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session);
|
||||
.SH DESCRIPTION
|
||||
Open a channel and initialize the SFTP subsystem. Although the SFTP subsystem
|
||||
operates over the same type of channel as those exported by the Channel API,
|
||||
the protocol itself implements its own unique binary packet protocol which
|
||||
must be managed with the libssh2_sftp_*() family of functions. When an SFTP
|
||||
session is complete, it must be destroyed using the
|
||||
\fIlibssh2_sftp_shutdown(3)\fP function.
|
||||
.SH RETURN VALUE
|
||||
A pointer to the newly allocated SFTP instance or NULL on failure.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh2_sftp_shutdown(3), libssh2_sftp_open_ex(3)
|
47
docs/libssh2_sftp_open_ex.3
Normal file
47
docs/libssh2_sftp_open_ex.3
Normal file
@@ -0,0 +1,47 @@
|
||||
.\" $Id: libssh2_sftp_open_ex.3,v 1.1 2007/02/02 16:09:12 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_sftp_open_ex 3 "23 Jan 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_sftp_open -
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp,
|
||||
char *filename, int filename_len,
|
||||
unsigned long flags, long mode, int open_type);
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *libssh2_sftp_open(LIBSSH2_SFTP *sftp,
|
||||
char *filename, unsigned long flags, long mode);
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *libssh2_sftp_opendir(LIBSSH2_SFTP *sftp,
|
||||
char *path);
|
||||
.SH DESCRIPTION
|
||||
* sftp
|
||||
|
||||
SFTP instance as returned by libssh2_sftp_init().
|
||||
|
||||
* filename
|
||||
|
||||
Remote file/directory resource to open
|
||||
|
||||
* filename_len
|
||||
|
||||
Length of filename
|
||||
|
||||
* flags
|
||||
|
||||
Any (reasonable) combination of the LIBSSH2_FXF_* constants corresponding fopen modes.
|
||||
|
||||
* mode
|
||||
|
||||
POSIX file permissions to assign if the file is being newly created.
|
||||
|
||||
* open_type
|
||||
|
||||
Either of LIBSSH2_SFTP_OPENFILE (to open a file) or LIBSSH2_SFTP_OPENDIR (to open a directory).
|
||||
.SH RETURN VALUE
|
||||
A pointer to the newly created LIBSSH2_SFTP_HANDLE instance or NULL on
|
||||
failure.
|
||||
.SH "SEE ALSO"
|
||||
.BI libssh_sftp_close(3)
|
||||
|
15
docs/template.3
Normal file
15
docs/template.3
Normal file
@@ -0,0 +1,15 @@
|
||||
.\" $Id: template.3,v 1.1 2007/02/02 16:09:12 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_template 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_template - short function description
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
void libssh2_template(void);
|
||||
.SH DESCRIPTION
|
||||
Long text describing the function and its input arguments.
|
||||
.SH RETURN VALUE
|
||||
Describe what the funtion returns.
|
||||
.SH "SEE ALSO"
|
||||
Add related functions
|
158
example/simple/scp.c
Normal file
158
example/simple/scp.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* $Id: scp.c,v 1.3 2007/02/01 22:39:45 bagder Exp $
|
||||
*
|
||||
* Sample showing how to do a simple SCP transfer.
|
||||
*/
|
||||
|
||||
#include <libssh2.h>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *scppath=(char *)"/tmp/TEST";
|
||||
struct stat fileinfo;
|
||||
int rc;
|
||||
off_t got=0;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = htonl(0x7F000001);
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(argc > 1) {
|
||||
username = argv[1];
|
||||
}
|
||||
if(argc > 2) {
|
||||
password = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
scppath = argv[3];
|
||||
}
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
/* Request a file via SCP */
|
||||
channel = libssh2_scp_recv(session, scppath, &fileinfo);
|
||||
|
||||
if (!channel) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
|
||||
while(got < fileinfo.st_size) {
|
||||
char mem[1024];
|
||||
int amount=sizeof(mem);
|
||||
|
||||
if((fileinfo.st_size -got) < amount) {
|
||||
amount = fileinfo.st_size -got;
|
||||
}
|
||||
|
||||
rc = libssh2_channel_read(channel, mem, amount);
|
||||
if(rc == amount) {
|
||||
write(2, mem, rc);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "libssh2_channel_read() failed: %d\n",
|
||||
rc);
|
||||
break;
|
||||
}
|
||||
got += rc;
|
||||
}
|
||||
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
}
|
159
example/simple/sftp.c
Normal file
159
example/simple/sftp.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* $Id: sftp.c,v 1.1 2007/01/24 14:15:36 bagder Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP transfers.
|
||||
*/
|
||||
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
char *sftppath=(char *)"/tmp/TEST";
|
||||
int rc;
|
||||
LIBSSH2_SFTP *sftp_session;
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = htonl(0x7F000001);
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(argc > 1) {
|
||||
username = argv[1];
|
||||
}
|
||||
if(argc > 2) {
|
||||
password = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
sftppath = argv[3];
|
||||
}
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
|
||||
if (!sftp_session) {
|
||||
fprintf(stderr, "Unable to init SFTP session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* Request a file via SFTP */
|
||||
sftp_handle =
|
||||
libssh2_sftp_open(sftp_session, sftppath, LIBSSH2_FXF_READ, 0);
|
||||
|
||||
if (!sftp_handle) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
goto shutdown;
|
||||
}
|
||||
fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
|
||||
do {
|
||||
char mem[512];
|
||||
|
||||
/* loop until we fail */
|
||||
rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem));
|
||||
if(rc > 0) {
|
||||
write(2, mem, rc);
|
||||
}
|
||||
else
|
||||
break;
|
||||
break;
|
||||
|
||||
} while (1);
|
||||
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
}
|
152
example/simple/ssh2.c
Normal file
152
example/simple/ssh2.c
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "libssh2.h"
|
||||
|
||||
#ifndef WIN32
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
#ifndef WIN32
|
||||
fcntl(sock, F_SETFL, 0);
|
||||
#endif
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = htonl(0x7F000001);
|
||||
if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance and start it up
|
||||
* This will trade welcome banners, exchange keys, and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if (libssh2_session_startup(session, sock)) {
|
||||
fprintf(stderr, "Failure establishing SSH session\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't authenticated,
|
||||
* The first thing to do is check the hostkey's fingerprint against our known hosts
|
||||
* Your app may have it hard coded, may go to a file, may present it to the user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(argc > 1) {
|
||||
username = argv[1];
|
||||
}
|
||||
if(argc > 2) {
|
||||
password = argv[2];
|
||||
}
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username, "/home/username/.ssh/id_rsa.pub", "/home/username/.ssh/id_rsa", password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
/* Request a shell */
|
||||
if (!(channel = libssh2_channel_open_session(session))) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* Some environment variables may be set,
|
||||
* It's up to the server which ones it'll allow though
|
||||
*/
|
||||
libssh2_channel_setenv(channel, (char *)"FOO", (char *)"bar");
|
||||
|
||||
/* Request a terminal with 'vanilla' terminal emulation
|
||||
* See /etc/termcap for more options
|
||||
*/
|
||||
if (libssh2_channel_request_pty(channel, (char *)"vanilla")) {
|
||||
fprintf(stderr, "Failed requesting pty\n");
|
||||
goto skip_shell;
|
||||
}
|
||||
|
||||
/* Open a SHELL on that pty */
|
||||
if (libssh2_channel_shell(channel)) {
|
||||
fprintf(stderr, "Unable to request shell on allocated pty\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* At this point the shell can be interacted with using
|
||||
* libssh2_channel_read()
|
||||
* libssh2_channel_read_stderr()
|
||||
* libssh2_channel_write()
|
||||
* libssh2_channel_write_stderr()
|
||||
*
|
||||
* Blocking mode may be (en|dis)abled with: libssh2_channel_set_blocking()
|
||||
* If the server send EOF, libssh2_channel_eof() will return non-0
|
||||
* To send EOF to the server use: libssh2_channel_send_eof()
|
||||
* A channel can be closed with: libssh2_channel_close()
|
||||
* A channel can be freed with: libssh2_channel_free()
|
||||
*/
|
||||
|
||||
skip_shell:
|
||||
if (channel) {
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
}
|
||||
|
||||
/* Other channel types are supported via:
|
||||
* libssh2_scp_send()
|
||||
* libssh2_scp_recv()
|
||||
* libssh2_channel_direct_tcpip()
|
||||
*/
|
||||
|
||||
shutdown:
|
||||
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -38,27 +38,32 @@
|
||||
#ifndef LIBSSH2_H
|
||||
#define LIBSSH2_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* Allow alternate API prefix from CFLAGS or calling app */
|
||||
#ifndef LIBSSH2_API
|
||||
#ifdef LIBSSH2_WIN32
|
||||
# ifdef LIBSSH2_WIN32
|
||||
# ifdef LIBSSH2_LIBRARY
|
||||
# define LIBSSH2_API __declspec(dllexport)
|
||||
# else
|
||||
# define LIBSSH2_API __declspec(dllimport)
|
||||
# endif
|
||||
# ifndef _MSC_VER
|
||||
# include <sys/uio.h>
|
||||
# endif
|
||||
#else
|
||||
# endif /* LIBSSH2_LIBRARY */
|
||||
# else /* !LIBSSH2_WIN32 */
|
||||
# define LIBSSH2_API
|
||||
#endif
|
||||
# endif /* LIBSSH2_WIN32 */
|
||||
#endif /* LIBSSH2_API */
|
||||
|
||||
#if defined(LIBSSH2_DARWIN) || (defined(LIBSSH2_WIN32) && !defined(_MSC_VER))
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if _MSC_VER < 1300
|
||||
#if defined(LIBSSH2_WIN32) && _MSC_VER < 1300
|
||||
typedef unsigned __int64 libssh2_uint64_t;
|
||||
typedef __int64 libssh2_int64_t;
|
||||
#else
|
||||
@@ -66,8 +71,8 @@ typedef unsigned long long libssh2_uint64_t;
|
||||
typedef long long libssh2_int64_t;
|
||||
#endif
|
||||
|
||||
#define LIBSSH2_VERSION "0.5"
|
||||
#define LIBSSH2_APINO 200412301450
|
||||
#define LIBSSH2_VERSION "0.14"
|
||||
#define LIBSSH2_APINO 200507211326
|
||||
|
||||
/* Part of every banner, user specified or not */
|
||||
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
|
||||
@@ -76,51 +81,6 @@ typedef long long libssh2_int64_t;
|
||||
#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 */
|
||||
|
||||
/* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 */
|
||||
#define LIBSSH2_DH_GEX_MINGROUP 1024
|
||||
#define LIBSSH2_DH_GEX_OPTGROUP 1536
|
||||
@@ -151,6 +111,22 @@ typedef long long libssh2_int64_t;
|
||||
#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, void **abstract)
|
||||
#define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract)
|
||||
|
||||
typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
|
||||
{
|
||||
char* text;
|
||||
unsigned int length;
|
||||
unsigned char echo;
|
||||
} LIBSSH2_USERAUTH_KBDINT_PROMPT;
|
||||
|
||||
typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
|
||||
{
|
||||
char* text;
|
||||
unsigned int length;
|
||||
} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
|
||||
|
||||
/* 'keyboard-interactive' authentication callback */
|
||||
#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) void name_(const char* name, int name_len, const char* instruction, int instruction_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses, void **abstract)
|
||||
|
||||
/* Callbacks for special SSH packets */
|
||||
#define LIBSSH2_IGNORE_FUNC(name) void name(LIBSSH2_SESSION *session, const char *message, int message_len, void **abstract)
|
||||
#define LIBSSH2_DEBUG_FUNC(name) void name(LIBSSH2_SESSION *session, int always_display, const char *message, int message_len, const char *language, int language_len,void **abstract)
|
||||
@@ -180,10 +156,47 @@ typedef long long libssh2_int64_t;
|
||||
#define LIBSSH2_METHOD_LANG_CS 8
|
||||
#define LIBSSH2_METHOD_LANG_SC 9
|
||||
|
||||
/* session.flags bits */
|
||||
#define LIBSSH2_FLAG_SIGPIPE 0x00000001
|
||||
|
||||
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
|
||||
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
||||
typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
|
||||
|
||||
typedef struct _LIBSSH2_POLLFD {
|
||||
unsigned char type; /* LIBSSH2_POLLFD_* below */
|
||||
|
||||
union {
|
||||
int socket; /* File descriptors -- examined with system select() call */
|
||||
LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */
|
||||
LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound connections waiting to be accepted? */
|
||||
} fd;
|
||||
|
||||
unsigned long events; /* Requested Events */
|
||||
unsigned long revents; /* Returned Events */
|
||||
} LIBSSH2_POLLFD;
|
||||
|
||||
/* Poll FD Descriptor Types */
|
||||
#define LIBSSH2_POLLFD_SOCKET 1
|
||||
#define LIBSSH2_POLLFD_CHANNEL 2
|
||||
#define LIBSSH2_POLLFD_LISTENER 3
|
||||
|
||||
/* Note: Win32 Doesn't actually have a poll() implementation, so some of these values are faked with select() data */
|
||||
/* Poll FD events/revents -- Match sys/poll.h where possible */
|
||||
#define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or connection available -- All */
|
||||
#define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to be read -- Socket only */
|
||||
#define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to be read -- Channel only */
|
||||
#define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written -- Socket/Channel */
|
||||
/* revents only */
|
||||
#define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */
|
||||
#define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket */
|
||||
#define LIBSSH2_POLLFD_SESSION_CLOSED 0x0010 /* Session Disconnect */
|
||||
#define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket Only */
|
||||
#define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition -- Socket/Win32 */
|
||||
#define LIBSSH2_POLLFD_CHANNEL_CLOSED 0x0080 /* Channel Disconnect */
|
||||
#define LIBSSH2_POLLFD_LISTENER_CLOSED 0x0080 /* Listener Disconnect */
|
||||
|
||||
/* Hash Types */
|
||||
#define LIBSSH2_HOSTKEY_HASH_MD5 1
|
||||
#define LIBSSH2_HOSTKEY_HASH_SHA1 2
|
||||
|
||||
@@ -239,6 +252,8 @@ typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
|
||||
#define LIBSSH2_ERROR_REQUEST_DENIED -32
|
||||
#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33
|
||||
#define LIBSSH2_ERROR_INVAL -34
|
||||
#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35
|
||||
#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36
|
||||
|
||||
/* 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);
|
||||
@@ -246,34 +261,57 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_all
|
||||
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_banner_set(LIBSSH2_SESSION *session, char *banner);
|
||||
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner);
|
||||
|
||||
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
|
||||
LIBSSH2_API int 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, const char *description, const 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 const 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 char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
|
||||
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs);
|
||||
LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
|
||||
LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
|
||||
|
||||
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
|
||||
|
||||
/* Userauth API */
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len);
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len);
|
||||
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
|
||||
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *username, int username_len, char *password, int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
|
||||
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)));
|
||||
#define libssh2_userauth_password(session, username, password) libssh2_userauth_password_ex((session), (username), strlen(username), (password), strlen(password), NULL)
|
||||
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len,
|
||||
char *publickey, char *privatekey,
|
||||
char *passphrase);
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase);
|
||||
#define libssh2_userauth_publickey_fromfile(session, username, publickey, privatekey, passphrase) \
|
||||
libssh2_userauth_publickey_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase))
|
||||
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase,
|
||||
const char *hostname, unsigned int hostname_len,
|
||||
const char *local_username, unsigned int local_username_len);
|
||||
#define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \
|
||||
libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username))
|
||||
|
||||
/*
|
||||
* response_callback is provided with filled by library prompts array,
|
||||
* but client must allocate and fill individual responses. Responses
|
||||
* array is already allocated. Responses data will be freed by libssh2
|
||||
* after callback return, but before subsequent callback invokation.
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, const char *username, unsigned int username_len,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)));
|
||||
#define libssh2_userauth_keyboard_interactive(session, username, response_callback) \
|
||||
libssh2_userauth_keyboard_interactive_ex((session), (username), strlen(username), (response_callback))
|
||||
|
||||
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
|
||||
|
||||
/* Channel API */
|
||||
#define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536
|
||||
#define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384
|
||||
#define LIBSSH2_CHANNEL_MINADJUST 1024
|
||||
|
||||
/* Extended Data Handling */
|
||||
#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0
|
||||
@@ -282,7 +320,7 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
|
||||
#define SSH_EXTENDED_DATA_STDERR 1
|
||||
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size, char *message, int message_len);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, unsigned int channel_type_len, unsigned int window_size, unsigned int packet_size, const char *message, unsigned 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);
|
||||
@@ -295,16 +333,16 @@ LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
|
||||
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
|
||||
|
||||
LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varname, int varname_len, char *value, int value_len);
|
||||
LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varname, unsigned int varname_len, char *value, unsigned int value_len);
|
||||
#define libssh2_channel_setenv(channel, varname, value) libssh2_channel_setenv_ex((channel), (varname), strlen(varname), (value), strlen(value))
|
||||
|
||||
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *term, int term_len, char *modes, int modes_len, int width, int height, int width_px, int height_px);
|
||||
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *term, unsigned int term_len, char *modes, unsigned int modes_len, int width, int height, int width_px, int height_px);
|
||||
#define libssh2_channel_request_pty(channel, term) libssh2_channel_request_pty_ex((channel), (term), strlen(term), NULL, 0, LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX)
|
||||
|
||||
LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, char *auth_proto, char *auth_cookie, int screen_number);
|
||||
#define libssh2_channel_x11_req(channel, screen_number) libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number))
|
||||
|
||||
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, char *request, int request_len, char *message, int message_len);
|
||||
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, unsigned int request_len, const char *message, unsigned int message_len);
|
||||
#define libssh2_channel_shell(channel) libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, NULL, 0)
|
||||
#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))
|
||||
@@ -313,10 +351,20 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
#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))
|
||||
|
||||
LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended);
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial);
|
||||
#define libssh2_channel_window_read(channel) libssh2_channel_window_read_ex((channel), NULL, NULL)
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force);
|
||||
|
||||
LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, const char *buf, size_t buflen);
|
||||
#define libssh2_channel_write(channel, buf, buflen) libssh2_channel_write_ex((channel), 0, (buf), (buflen))
|
||||
#define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, unsigned long *window_size_initial);
|
||||
#define libssh2_channel_window_write(channel) libssh2_channel_window_write_ex((channel), NULL)
|
||||
|
||||
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
|
||||
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
|
||||
@@ -331,16 +379,22 @@ LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel,
|
||||
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_get_exit_status(LIBSSH2_CHANNEL* channel);
|
||||
|
||||
LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel);
|
||||
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *path, struct stat *sb);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char *path, int mode, size_t size, long mtime, long atime);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime);
|
||||
#define libssh2_scp_send(session, path, mode, size) libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0)
|
||||
|
||||
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, int *dest_len, char *src, int src_len);
|
||||
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, unsigned int *dest_len, char *src, unsigned int src_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LIBSSH2_H */
|
||||
|
@@ -1,74 +0,0 @@
|
||||
/* include/libssh2_config.h.in. Generated from configure.in by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#undef HAVE_ERRNO_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Enable "none" cipher -- NOT RECOMMENDED */
|
||||
#undef LIBSSH2_CRYPT_NONE
|
||||
|
||||
/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
|
||||
#undef LIBSSH2_DH_GEX_NEW
|
||||
|
||||
/* Compile in zlib support */
|
||||
#undef LIBSSH2_HAVE_ZLIB
|
||||
|
||||
/* Enable "none" MAC -- NOT RECOMMENDED */
|
||||
#undef LIBSSH2_MAC_NONE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
#undef WORDS_BIGENDIAN
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
101
include/libssh2_publickey.h
Normal file
101
include/libssh2_publickey.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* Copyright (c) 2004-2006, 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.
|
||||
*/
|
||||
|
||||
/* Note: This include file is only needed for using the
|
||||
* publickey SUBSYSTEM which is not the same as publickey
|
||||
* authentication. For authentication you only need libssh2.h
|
||||
*
|
||||
* For more information on the publickey subsystem,
|
||||
* refer to IETF draft: secsh-publickey
|
||||
*/
|
||||
|
||||
#ifndef LIBSSH2_PUBLICKEY_H
|
||||
#define LIBSSH2_PUBLICKEY_H 1
|
||||
|
||||
typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY;
|
||||
|
||||
typedef struct _libssh2_publickey_attribute {
|
||||
char *name;
|
||||
unsigned long name_len;
|
||||
char *value;
|
||||
unsigned long value_len;
|
||||
char mandatory;
|
||||
} libssh2_publickey_attribute;
|
||||
|
||||
typedef struct _libssh2_publickey_list {
|
||||
unsigned char *packet; /* For freeing */
|
||||
|
||||
unsigned char *name;
|
||||
unsigned long name_len;
|
||||
unsigned char *blob;
|
||||
unsigned long blob_len;
|
||||
unsigned long num_attrs;
|
||||
libssh2_publickey_attribute *attrs; /* free me */
|
||||
} libssh2_publickey_list;
|
||||
|
||||
/* Generally use the first macro here, but if both name and value are string literals, you can use _fast() to take advantage of preprocessing */
|
||||
#define libssh2_publickey_attribute(name, value, mandatory) { (name), strlen(name), (value), strlen(value), (mandatory) },
|
||||
#define libssh2_publickey_attribute_fast(name, value, mandatory) { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) },
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Publickey Subsystem */
|
||||
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session);
|
||||
|
||||
LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len, char overwrite,
|
||||
unsigned long num_attrs, libssh2_publickey_attribute attrs[]);
|
||||
#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, num_attrs, attrs) \
|
||||
libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), (overwrite), (num_attrs), (attrs))
|
||||
|
||||
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len);
|
||||
#define libssh2_publickey_remove(pkey, name, blob, blob_len) \
|
||||
libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len))
|
||||
|
||||
LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list);
|
||||
LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, libssh2_publickey_list *pkey_list);
|
||||
|
||||
LIBSSH2_API void libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* ndef: LIBSSH2_PUBLICKEY_H */
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -38,6 +38,10 @@
|
||||
#ifndef LIBSSH2_SFTP_H
|
||||
#define LIBSSH2_SFTP_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Note: Version 6 was documented at the time of writing
|
||||
* However it was marked as "DO NOT IMPLEMENT" due to pending changes
|
||||
*
|
||||
@@ -99,6 +103,39 @@ struct _LIBSSH2_SFTP_ATTRIBUTES {
|
||||
#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8
|
||||
#define LIBSSH2_SFTP_TYPE_FIFO 9
|
||||
|
||||
/*
|
||||
* Reproduce the POSIX file modes here for systems that are not
|
||||
* POSIX compliant.
|
||||
*
|
||||
* These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES"
|
||||
*/
|
||||
/* File type */
|
||||
#define LIBSSH2_SFTP_S_IFMT 0170000 /* type of file mask */
|
||||
#define LIBSSH2_SFTP_S_IFIFO 0010000 /* named pipe (fifo) */
|
||||
#define LIBSSH2_SFTP_S_IFCHR 0020000 /* character special */
|
||||
#define LIBSSH2_SFTP_S_IFDIR 0040000 /* directory */
|
||||
#define LIBSSH2_SFTP_S_IFBLK 0060000 /* block special */
|
||||
#define LIBSSH2_SFTP_S_IFREG 0100000 /* regular */
|
||||
#define LIBSSH2_SFTP_S_IFLNK 0120000 /* symbolic link */
|
||||
#define LIBSSH2_SFTP_S_IFSOCK 0140000 /* socket */
|
||||
|
||||
/* File mode */
|
||||
/* Read, write, execute/search by owner */
|
||||
#define LIBSSH2_SFTP_S_IRWXU 0000700 /* RWX mask for owner */
|
||||
#define LIBSSH2_SFTP_S_IRUSR 0000400 /* R for owner */
|
||||
#define LIBSSH2_SFTP_S_IWUSR 0000200 /* W for owner */
|
||||
#define LIBSSH2_SFTP_S_IXUSR 0000100 /* X for owner */
|
||||
/* Read, write, execute/search by group */
|
||||
#define LIBSSH2_SFTP_S_IRWXG 0000070 /* RWX mask for group */
|
||||
#define LIBSSH2_SFTP_S_IRGRP 0000040 /* R for group */
|
||||
#define LIBSSH2_SFTP_S_IWGRP 0000020 /* W for group */
|
||||
#define LIBSSH2_SFTP_S_IXGRP 0000010 /* X for group */
|
||||
/* Read, write, execute/search by others */
|
||||
#define LIBSSH2_SFTP_S_IRWXO 0000007 /* RWX mask for other */
|
||||
#define LIBSSH2_SFTP_S_IROTH 0000004 /* R for other */
|
||||
#define LIBSSH2_SFTP_S_IWOTH 0000002 /* W for other */
|
||||
#define LIBSSH2_SFTP_S_IXOTH 0000001 /* X for other */
|
||||
|
||||
/* 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
|
||||
@@ -138,7 +175,7 @@ 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);
|
||||
LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *filename, unsigned 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)
|
||||
|
||||
@@ -162,29 +199,33 @@ LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_
|
||||
|
||||
|
||||
/* 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,
|
||||
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filename, unsigned int srouce_filename_len,
|
||||
char *dest_filename, unsigned 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);
|
||||
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, unsigned 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);
|
||||
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned 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);
|
||||
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned 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);
|
||||
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, unsigned 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);
|
||||
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);
|
||||
#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)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LIBSSH2_SFTP_H */
|
||||
|
44
m4/autobuild.m4
Normal file
44
m4/autobuild.m4
Normal file
@@ -0,0 +1,44 @@
|
||||
# autobuild.m4 serial 3
|
||||
# Copyright (C) 2004, 2006 Simon Josefsson
|
||||
#
|
||||
# This file is free software, distributed under the terms of the GNU
|
||||
# General Public License. As a special exception to the GNU General
|
||||
# Public License, this file may be distributed as part of a program
|
||||
# that contains a configuration script generated by Autoconf, under
|
||||
# the same distribution terms as the rest of that program.
|
||||
#
|
||||
# This file can can be used in projects which are not available under
|
||||
# the GNU General Public License or the GNU Library General Public
|
||||
# License but which still want to provide support for Autobuild.
|
||||
|
||||
# Usage: AB_INIT([MODE]).
|
||||
AC_DEFUN([AB_INIT],
|
||||
[
|
||||
AC_REQUIRE([AC_CANONICAL_BUILD])
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
|
||||
if test -z "$AB_PACKAGE"; then
|
||||
AB_PACKAGE=${PACKAGE_NAME:-$PACKAGE}
|
||||
fi
|
||||
AC_MSG_NOTICE([autobuild project... $AB_PACKAGE])
|
||||
|
||||
if test -z "$AB_VERSION"; then
|
||||
AB_VERSION=${PACKAGE_VERSION:-$VERSION}
|
||||
fi
|
||||
AC_MSG_NOTICE([autobuild revision... $AB_VERSION])
|
||||
|
||||
hostname=`hostname`
|
||||
if test "$hostname"; then
|
||||
AC_MSG_NOTICE([autobuild hostname... $hostname])
|
||||
fi
|
||||
|
||||
ifelse([$1],[],,[AC_MSG_NOTICE([autobuild mode... $1])])
|
||||
|
||||
date=`date +%Y%m%d-%H%M%S`
|
||||
if test "$?" != 0; then
|
||||
date=`date`
|
||||
fi
|
||||
if test "$date"; then
|
||||
AC_MSG_NOTICE([autobuild timestamp... $date])
|
||||
fi
|
||||
])
|
108
m4/libgcrypt.m4
Normal file
108
m4/libgcrypt.m4
Normal file
@@ -0,0 +1,108 @@
|
||||
dnl Autoconf macros for libgcrypt
|
||||
dnl Copyright (C) 2002, 2004 Free Software Foundation, Inc.
|
||||
dnl
|
||||
dnl This file is free software; as a special exception the author gives
|
||||
dnl unlimited permission to copy and/or distribute it, with or without
|
||||
dnl modifications, as long as this notice is preserved.
|
||||
dnl
|
||||
dnl This file is distributed in the hope that it will be useful, but
|
||||
dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION,
|
||||
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
|
||||
dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS.
|
||||
dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed
|
||||
dnl with the API version to also check the API compatibility. Example:
|
||||
dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed
|
||||
dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using
|
||||
dnl this features allows to prevent build against newer versions of libgcrypt
|
||||
dnl with a changed API.
|
||||
dnl
|
||||
AC_DEFUN([AM_PATH_LIBGCRYPT],
|
||||
[ AC_ARG_WITH(libgcrypt-prefix,
|
||||
AC_HELP_STRING([--with-libgcrypt-prefix=PFX],
|
||||
[prefix where LIBGCRYPT is installed (optional)]),
|
||||
libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="")
|
||||
if test x$libgcrypt_config_prefix != x ; then
|
||||
if test x${LIBGCRYPT_CONFIG+set} != xset ; then
|
||||
LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config, no)
|
||||
tmp=ifelse([$1], ,1:1.2.0,$1)
|
||||
if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then
|
||||
req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'`
|
||||
min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'`
|
||||
else
|
||||
req_libgcrypt_api=0
|
||||
min_libgcrypt_version="$tmp"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version)
|
||||
ok=no
|
||||
if test "$LIBGCRYPT_CONFIG" != "no" ; then
|
||||
req_major=`echo $min_libgcrypt_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
|
||||
req_minor=`echo $min_libgcrypt_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
|
||||
req_micro=`echo $min_libgcrypt_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
|
||||
libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version`
|
||||
major=`echo $libgcrypt_config_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
|
||||
minor=`echo $libgcrypt_config_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
|
||||
micro=`echo $libgcrypt_config_version | \
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
|
||||
if test "$major" -gt "$req_major"; then
|
||||
ok=yes
|
||||
else
|
||||
if test "$major" -eq "$req_major"; then
|
||||
if test "$minor" -gt "$req_minor"; then
|
||||
ok=yes
|
||||
else
|
||||
if test "$minor" -eq "$req_minor"; then
|
||||
if test "$micro" -ge "$req_micro"; then
|
||||
ok=yes
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test $ok = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
if test $ok = yes; then
|
||||
# If we have a recent libgcrypt, we should also check that the
|
||||
# API is compatible
|
||||
if test "$req_libgcrypt_api" -gt 0 ; then
|
||||
tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0`
|
||||
if test "$tmp" -gt 0 ; then
|
||||
AC_MSG_CHECKING([LIBGCRYPT API version])
|
||||
if test "$req_libgcrypt_api" -eq "$tmp" ; then
|
||||
AC_MSG_RESULT(okay)
|
||||
else
|
||||
ok=no
|
||||
AC_MSG_RESULT([does not match. want=$req_libgcrypt_api got=$tmp])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test $ok = yes; then
|
||||
LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags`
|
||||
LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
|
||||
ifelse([$2], , :, [$2])
|
||||
else
|
||||
LIBGCRYPT_CFLAGS=""
|
||||
LIBGCRYPT_LIBS=""
|
||||
ifelse([$3], , :, [$3])
|
||||
fi
|
||||
AC_SUBST(LIBGCRYPT_CFLAGS)
|
||||
AC_SUBST(LIBGCRYPT_LIBS)
|
||||
])
|
@@ -1,3 +1,5 @@
|
||||
.deps
|
||||
.libs
|
||||
*.lib
|
||||
*.pdb
|
||||
*.dll
|
||||
@@ -7,3 +9,10 @@
|
||||
Debug
|
||||
Release
|
||||
*.exp
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.lo
|
||||
libssh2.la
|
||||
libssh2_config.h
|
||||
libssh2_config.h.in
|
||||
stamp-h1
|
||||
|
52
src/Makefile.am
Normal file
52
src/Makefile.am
Normal file
@@ -0,0 +1,52 @@
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
|
||||
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 \
|
||||
libssh2_priv.h openssl.h libgcrypt.h pem.c
|
||||
|
||||
if LIBGCRYPT
|
||||
libssh2_la_SOURCES += libgcrypt.c
|
||||
else
|
||||
libssh2_la_SOURCES += openssl.c
|
||||
endif
|
||||
|
||||
EXTRA_DIST = libssh2_config.h.in
|
||||
|
||||
lib_LTLIBRARIES = libssh2.la
|
||||
|
||||
# srcdir/include for the shipped headers
|
||||
# builddir/src for the generated config header when building out of the source
|
||||
# tree
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/src
|
||||
|
||||
VERSION=-version-info 0:0:0
|
||||
|
||||
# This flag accepts an argument of the form current[:revision[:age]]. So,
|
||||
# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to
|
||||
# 1.
|
||||
#
|
||||
# If either revision or age are omitted, they default to 0. Also note that age
|
||||
# must be less than or equal to the current interface number.
|
||||
#
|
||||
# Here are a set of rules to help you update your library version information:
|
||||
#
|
||||
# 1.Start with version information of 0:0:0 for each libtool library.
|
||||
#
|
||||
# 2.Update the version information only immediately before a public release of
|
||||
# your software. More frequent updates are unnecessary, and only guarantee
|
||||
# that the current interface number gets larger faster.
|
||||
#
|
||||
# 3.If the library source code has changed at all since the last update, then
|
||||
# increment revision (c:r+1:a)
|
||||
#
|
||||
# 4.If any interfaces have been added, removed, or changed since the last
|
||||
# update, increment current, and set revision to 0. (c+1:r=0:a)
|
||||
#
|
||||
# 5.If any interfaces have been added since the last public release, then
|
||||
# increment age. (c:r:a+1)
|
||||
#
|
||||
# 6.If any interfaces have been removed since the last public release, then
|
||||
# set age to 0. (c:r:a=0)
|
||||
#
|
||||
|
||||
libssh2_la_LDFLAGS = $(VERSION)
|
@@ -1,63 +0,0 @@
|
||||
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@
|
||||
exec_prefix = @exec_prefix@
|
||||
libdir = @exec_prefix@/lib
|
||||
incldir = @prefix@/include
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = -c @CFLAGS@ -Wall -g -I../include/ -fPIC
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
channel.o: channel.c
|
||||
$(CC) -o channel.o channel.c $(CFLAGS) $(LIBS)
|
||||
|
||||
comp.o: comp.c
|
||||
$(CC) -o comp.o comp.c $(CFLAGS) $(LIBS)
|
||||
|
||||
crypt.o: crypt.c
|
||||
$(CC) -o crypt.o crypt.c $(CFLAGS) $(LIBS)
|
||||
|
||||
hostkey.o: hostkey.c
|
||||
$(CC) -o hostkey.o hostkey.c $(CFLAGS) $(LIBS)
|
||||
|
||||
kex.o: kex.c
|
||||
$(CC) -o kex.o kex.c $(CFLAGS) $(LIBS)
|
||||
|
||||
mac.o: mac.c
|
||||
$(CC) -o mac.o mac.c $(CFLAGS) $(LIBS)
|
||||
|
||||
misc.o: misc.c
|
||||
$(CC) -o misc.o misc.c $(CFLAGS) $(LIBS)
|
||||
|
||||
packet.o: packet.c
|
||||
$(CC) -o packet.o packet.c $(CFLAGS) $(LIBS)
|
||||
|
||||
scp.o: scp.c
|
||||
$(CC) -o scp.o scp.c $(CFLAGS) $(LIBS)
|
||||
|
||||
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)
|
||||
|
||||
all: libssh2.@SHLIB_SUFFIX_NAME@
|
||||
|
||||
libssh2.@SHLIB_SUFFIX_NAME@: $(OBJECTS)
|
||||
$(CC) -o libssh2.@SHLIB_SUFFIX_NAME@ $(SHLIB_LDFLAGS) $(OBJECTS) $(LIBS) $(LDFLAGS) @SHLIB_LDFLAGS@
|
||||
libssh2.a: $(OBJECTS)
|
||||
rm -f libssh2.a
|
||||
ar q libssh2.a $(OBJECTS)
|
||||
@RANLIB@ libssh2.a
|
||||
install: all
|
||||
$(INSTALL) libssh2.@SHLIB_SUFFIX_NAME@ $(DESTDIR)$(libdir)
|
||||
clean:
|
||||
rm -f *~ libssh2.a libssh2.@SHLIB_SUFFIX_NAME@ *.o
|
||||
|
457
src/channel.c
457
src/channel.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,7 +36,6 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/rand.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -64,7 +63,9 @@ unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session)
|
||||
* Gets picked up by the new one.... Pretty unlikely all told...
|
||||
*/
|
||||
session->next_channel = id + 1;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Allocated new channel ID#%lu", id);
|
||||
#endif
|
||||
return id;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -103,9 +104,10 @@ LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long
|
||||
/* {{{ libssh2_channel_open_session
|
||||
* Establish a generic session channel
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size,
|
||||
char *message, int message_len)
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, unsigned int channel_type_len, unsigned int window_size,
|
||||
unsigned int packet_size, const char *message, unsigned int message_len)
|
||||
{
|
||||
unsigned char reply_codes[3] = { SSH_MSG_CHANNEL_OPEN_CONFIRMATION, SSH_MSG_CHANNEL_OPEN_FAILURE, 0 };
|
||||
LIBSSH2_CHANNEL *channel = NULL;
|
||||
unsigned long local_channel = libssh2_channel_nextid(session);
|
||||
unsigned char *s, *packet = NULL;
|
||||
@@ -113,8 +115,10 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
|
||||
window_size(4) + packet_size(4) */
|
||||
unsigned char *data = NULL;
|
||||
unsigned long data_len;
|
||||
int polls = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Opening Channel - win %d pack %d", window_size, packet_size);
|
||||
#endif
|
||||
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
|
||||
if (!channel) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for channel data", 0);
|
||||
@@ -161,35 +165,30 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
|
||||
goto channel_error;
|
||||
}
|
||||
|
||||
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &data, &data_len, 1, packet + 5 + channel_type_len, 4, 1) == 0) {
|
||||
/* YAY! You like me! */
|
||||
break;
|
||||
}
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_OPEN_FAILURE, &data, &data_len, 1, packet + 5 + channel_type_len, 4, 0) == 0) {
|
||||
/* But! Dear! I thought we had something! */
|
||||
|
||||
/* TODO: provide reason code and description */
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0);
|
||||
if (libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len, 1, packet + 5 + channel_type_len, 4)) {
|
||||
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);
|
||||
goto channel_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
|
||||
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);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Connection Established - ID: %lu/%lu win: %lu/%lu pack: %lu/%lu",
|
||||
channel->local.id, channel->remote.id,
|
||||
channel->local.window_size, channel->remote.window_size,
|
||||
channel->local.packet_size, channel->remote.packet_size);
|
||||
#endif
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0);
|
||||
}
|
||||
|
||||
channel_error:
|
||||
|
||||
@@ -240,6 +239,10 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *se
|
||||
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) */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Requesting direct-tcpip session to from %s:%d to %s:%d", shost, sport, host, port);
|
||||
#endif
|
||||
|
||||
s = message = LIBSSH2_ALLOC(session, message_len);
|
||||
if (!message) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for direct-tcpip connection", 0);
|
||||
@@ -253,7 +256,11 @@ 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;
|
||||
|
||||
channel = 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,
|
||||
(char *)message, message_len);
|
||||
LIBSSH2_FREE(session, message);
|
||||
|
||||
return channel;
|
||||
@@ -265,11 +272,16 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *se
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, char *host, int port, int *bound_port, int queue_maxsize)
|
||||
{
|
||||
unsigned char *packet, *s;
|
||||
unsigned char *packet, *s, *data, reply_codes[3] = { SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 };
|
||||
unsigned long data_len;
|
||||
unsigned long host_len = (host ? strlen(host) : (sizeof("0.0.0.0") - 1));
|
||||
unsigned long packet_len = host_len + (sizeof("tcpip-forward") - 1) + 14;
|
||||
/* packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Requesting tcpip-forward session for %s:%d", host, port);
|
||||
#endif
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memeory for setenv packet", 0);
|
||||
@@ -292,11 +304,11 @@ LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_REQUEST_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
if (data[0] == SSH_MSG_REQUEST_SUCCESS) {
|
||||
LIBSSH2_LISTENER *listener;
|
||||
|
||||
listener = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_LISTENER));
|
||||
@@ -318,6 +330,9 @@ LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION
|
||||
listener->host[host_len] = 0;
|
||||
if (data_len >= 5 && !port) {
|
||||
listener->port = libssh2_ntohu32(data + 1);
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Dynamic tcpip-forward port allocated: %d", listener->port);
|
||||
#endif
|
||||
} else {
|
||||
listener->port = port;
|
||||
}
|
||||
@@ -340,12 +355,11 @@ LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION
|
||||
return listener;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_REQUEST_FAILURE, &data, &data_len, 0) == 0) {
|
||||
if (data[0] == SSH_MSG_REQUEST_FAILURE) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_REQUEST_DENIED, "Unable to complete request for forward-listen", 0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -364,6 +378,10 @@ LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener)
|
||||
unsigned long packet_len = host_len + 14 + sizeof("cancel-tcpip-forward") - 1;
|
||||
/* packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Cancelling tcpip-forward session for %s:%d", listener->host, listener->port);
|
||||
#endif
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memeory for setenv packet", 0);
|
||||
@@ -448,13 +466,18 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *li
|
||||
/* {{{ libssh2_channel_setenv_ex
|
||||
* Set an environment variable prior to requesting a shell/program/subsystem
|
||||
*/
|
||||
LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varname, int varname_len, char *value, int value_len)
|
||||
LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varname, unsigned int varname_len, char *value, unsigned int value_len)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *s, *packet;
|
||||
unsigned char *s, *packet, *data, reply_codes[3] = { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }, local_channel[4];
|
||||
unsigned long data_len;
|
||||
unsigned long packet_len = varname_len + value_len + 21; /* packet_type(1) + channel_id(4) + request_len(4) + request(3)"env" +
|
||||
want_reply(1) + varname_len(4) + value_len(4) */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Setting remote environment variable: %s=%s on channel %lu/%lu", varname, value, channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memeory for setenv packet", 0);
|
||||
@@ -481,43 +504,40 @@ LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varnam
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
unsigned char local_channel[4];
|
||||
|
||||
libssh2_htonu32(local_channel, channel->local.id);
|
||||
if (libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len, 1, local_channel, 4)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_SUCCESS, &data, &data_len, 1, local_channel, 4, 1) == 0) {
|
||||
if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_FAILURE, &data, &data_len, 1, local_channel, 4, 0) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, "Unable to complete request for channel-setenv", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached, just giving the compiler something to not complain about */
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_channel_request_pty_ex
|
||||
* Duh... Request a PTY
|
||||
*/
|
||||
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *term, int term_len,
|
||||
char *modes, int modes_len,
|
||||
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *term, unsigned int term_len,
|
||||
char *modes, unsigned int modes_len,
|
||||
int width, int height,
|
||||
int width_px, int height_px)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *s, *packet;
|
||||
unsigned char *s, *packet, *data, reply_codes[3] = { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }, local_channel[4];
|
||||
unsigned long data_len;
|
||||
unsigned long packet_len = term_len + modes_len + 41; /* packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) + want_reply(1) +
|
||||
term_len(4) + width(4) + height(4) + width_px(4) + height_px(4) + modes_len(4) */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Allocating tty on channel %lu/%lu", channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for pty-request", 0);
|
||||
@@ -553,27 +573,19 @@ LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *t
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
unsigned char local_channel[4];
|
||||
|
||||
libssh2_htonu32(local_channel, channel->local.id);
|
||||
if (libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len, 1, local_channel, 4)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_SUCCESS, &data, &data_len, 1, local_channel, 4, 1) == 0) {
|
||||
if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_FAILURE, &data, &data_len, 1, local_channel, 4, 1) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, "Unable to complete request for channel request-pty", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached, just giving the compiler something to not complain about */
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -585,11 +597,19 @@ LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *t
|
||||
LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, char *auth_proto, char *auth_cookie, int screen_number)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *s, *packet;
|
||||
unsigned char *s, *packet, *data, reply_codes[3] = { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }, local_channel[4];
|
||||
unsigned long data_len;
|
||||
unsigned long proto_len = auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1);
|
||||
unsigned long cookie_len = auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN;
|
||||
unsigned long packet_len = proto_len + cookie_len + 41; /* packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + want_reply(1) +
|
||||
single_cnx(4) + proto_len(4) + cookie_len(4) + screen_num(4) */
|
||||
unsigned long packet_len = proto_len + cookie_len + 30; /* packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + want_reply(1) +
|
||||
single_cnx(1) + proto_len(4) + cookie_len(4) + screen_num(4) */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Requesting x11-req for channel %lu/%lu: single=%d proto=%s cookie=%s screen=%d",
|
||||
channel->local.id, channel->remote.id, single_connection,
|
||||
auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1",
|
||||
auth_cookie ? auth_cookie : "<random>", screen_number);
|
||||
#endif
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
@@ -609,16 +629,16 @@ LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_
|
||||
memcpy(s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len);
|
||||
s += proto_len;
|
||||
|
||||
libssh2_htonu32(s, cookie_len);
|
||||
libssh2_htonu32(s, cookie_len); s += 4;
|
||||
if (auth_cookie) {
|
||||
memcpy(s, auth_cookie, cookie_len);
|
||||
} else {
|
||||
int i;
|
||||
char buffer[LIBSSH2_X11_RANDOM_COOKIE_LEN / 2];
|
||||
unsigned char buffer[LIBSSH2_X11_RANDOM_COOKIE_LEN / 2];
|
||||
|
||||
RAND_bytes(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2);
|
||||
libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2);
|
||||
for (i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) {
|
||||
snprintf(s + (i * 2), 2, "%02X", buffer[i]);
|
||||
snprintf((char *)s + (i * 2), 2, "%02X", buffer[i]);
|
||||
}
|
||||
}
|
||||
s += cookie_len;
|
||||
@@ -626,49 +646,47 @@ LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_
|
||||
libssh2_htonu32(s, screen_number); s += 4;
|
||||
|
||||
if (libssh2_packet_write(session, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send pty-request packet", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send x11-req packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
unsigned char local_channel[4];
|
||||
|
||||
libssh2_htonu32(local_channel, channel->local.id);
|
||||
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_SUCCESS, &data, &data_len, 1, local_channel, 4, 1) == 0) {
|
||||
if (libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len, 1, local_channel, 4)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_FAILURE, &data, &data_len, 1, local_channel, 4, 1) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, "Unable to complete request for channel x11-req", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached, just giving the compiler something to not complain about */
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_channel_process_startup
|
||||
* Primitive for libssh2_channel_(shell|exec|subsystem)
|
||||
*/
|
||||
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, char *request, int request_len, char *message, int message_len)
|
||||
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, unsigned int request_len, const char *message, unsigned int message_len)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *s, *packet;
|
||||
unsigned char *s, *packet, *data, reply_codes[3] = { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }, local_channel[4];
|
||||
unsigned long data_len;
|
||||
unsigned long packet_len = request_len + 10; /* packet_type(1) + channel(4) + request_len(4) + want_reply(1) */
|
||||
|
||||
if (message) {
|
||||
packet_len += message_len + 4;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "starting request(%s) on channel %lu/%lu, message=%s", request, channel->local.id, channel->remote.id, message);
|
||||
#endif
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for channel-process request", 0);
|
||||
@@ -694,27 +712,19 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, char *
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
unsigned char local_channel[4];
|
||||
|
||||
libssh2_htonu32(local_channel, channel->local.id);
|
||||
if (libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len, 1, local_channel, 4)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_SUCCESS, &data, &data_len, 1, local_channel, 4, 1) == 0) {
|
||||
if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_FAILURE, &data, &data_len, 1, local_channel, 4, 0) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, "Unable to complete request for channel-process-startup", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached, just giving the compiler something to not complain about */
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -723,6 +733,9 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, char *
|
||||
*/
|
||||
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking)
|
||||
{
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(channel->session, LIBSSH2_DBG_CONN, "Setting blocking mode on channel %lu/%lu to %d", channel->local.id, channel->remote.id, blocking);
|
||||
#endif
|
||||
channel->blocking = blocking;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -743,13 +756,19 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid)
|
||||
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 */
|
||||
unsigned long packet_stream_id = (packet_type == SSH_MSG_CHANNEL_DATA) ? 0 : libssh2_ntohu32(packet->data + 5);
|
||||
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_EXTENDED_DATA) && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) || (streamid == packet_stream_id))) ||
|
||||
((packet_type == SSH_MSG_CHANNEL_DATA) && (streamid == 0))) {
|
||||
int bytes_to_flush = packet->data_len - packet->data_head;
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(channel->session, LIBSSH2_DBG_CONN, "Flushing %d bytes of data from stream %lu on channel %lu/%lu", bytes_to_flush,
|
||||
packet_stream_id, channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
|
||||
/* It's one of the streams we wanted to flush */
|
||||
refund_bytes += packet->data_len - 13;
|
||||
flush_bytes += packet->data_len - packet->data_head;
|
||||
flush_bytes += bytes_to_flush;
|
||||
|
||||
LIBSSH2_FREE(channel->session, packet->data);
|
||||
if (packet->prev) {
|
||||
@@ -768,23 +787,67 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid)
|
||||
packet = next;
|
||||
}
|
||||
|
||||
if (refund_bytes && channel->remote.window_size_initial) {
|
||||
if (refund_bytes) {
|
||||
libssh2_channel_receive_window_adjust(channel, refund_bytes, 0);
|
||||
}
|
||||
|
||||
return flush_bytes;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_channel_get_exit_status
|
||||
* Return the channel's program exit status
|
||||
*/
|
||||
LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel)
|
||||
{
|
||||
return channel->exit_status;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ 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
|
||||
*
|
||||
* Returns the new size of the receive window (as understood by remote end)
|
||||
*/
|
||||
LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force)
|
||||
{
|
||||
unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */
|
||||
|
||||
if (!force && (adjustment + channel->adjust_queue < LIBSSH2_CHANNEL_MINADJUST)) {
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(channel->session, LIBSSH2_DBG_CONN, "Queing %lu bytes for receive window adjustment for channel %lu/%lu", adjustment, channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
channel->adjust_queue += adjustment;
|
||||
return channel->remote.window_size;
|
||||
}
|
||||
|
||||
if (!adjustment && !channel->adjust_queue) {
|
||||
return channel->remote.window_size;
|
||||
}
|
||||
|
||||
adjustment += channel->adjust_queue;
|
||||
channel->adjust_queue = 0;
|
||||
|
||||
|
||||
/* 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);
|
||||
libssh2_htonu32(adjust + 5, adjustment);
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(channel->session, LIBSSH2_DBG_CONN, "Adjusting window %lu bytes for data flushed from channel %lu/%lu", adjustment, channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
|
||||
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;
|
||||
libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet, deferring", 0);
|
||||
channel->adjust_queue = adjustment;
|
||||
} else {
|
||||
channel->remote.window_size += refund_bytes;
|
||||
}
|
||||
channel->remote.window_size += adjustment;
|
||||
}
|
||||
|
||||
return flush_bytes;
|
||||
return channel->remote.window_size;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -796,6 +859,9 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid)
|
||||
*/
|
||||
LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode)
|
||||
{
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(channel->session, LIBSSH2_DBG_CONN, "Setting channel %lu/%lu handle_extended_data mode to %d", channel->local.id, channel->remote.id, ignore_mode);
|
||||
#endif
|
||||
channel->remote.extended_data_ignore_mode = ignore_mode;
|
||||
|
||||
if (ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) {
|
||||
@@ -812,6 +878,9 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
int bytes_read = 0, blocking_read = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Attempting to read %d bytes from channel %lu/%lu stream #%d", (int)buflen, channel->local.id, channel->remote.id, stream_id);
|
||||
#endif
|
||||
do {
|
||||
LIBSSH2_PACKET *packet;
|
||||
|
||||
@@ -827,7 +896,7 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
* or the standard stream (and data was available),
|
||||
* or the standard stream with extended_data_merge enabled and data was available
|
||||
*/
|
||||
if ((stream_id && (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
|
||||
if ((stream_id && (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1)) && (stream_id == libssh2_ntohu32(packet->data + 5))) ||
|
||||
(!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;
|
||||
@@ -838,13 +907,14 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
unlink_packet = 1;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Reading %d of buffered data from %lu/%lu/%d", want, channel->local.id, channel->remote.id, stream_id);
|
||||
#endif
|
||||
memcpy(buf + bytes_read, packet->data + packet->data_head, want);
|
||||
packet->data_head += want;
|
||||
bytes_read += want;
|
||||
|
||||
if (unlink_packet) {
|
||||
unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */
|
||||
|
||||
if (packet->prev) {
|
||||
packet->prev->next = packet->next;
|
||||
} else {
|
||||
@@ -857,20 +927,13 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
}
|
||||
LIBSSH2_FREE(session, packet->data);
|
||||
|
||||
if (channel->remote.window_size_initial) {
|
||||
/* 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, packet->data_len - (stream_id ? 13 : 9));
|
||||
|
||||
if (libssh2_packet_write(session, adjust, 9)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0);
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Unlinking empty packet buffer from channel %lu/%lu", channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
libssh2_channel_receive_window_adjust(channel, packet->data_len - (stream_id ? 13 : 9), 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
packet = next;
|
||||
}
|
||||
blocking_read = 1;
|
||||
@@ -890,9 +953,12 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, const char *buf, size_t buflen)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *packet, *s;
|
||||
unsigned long packet_len;
|
||||
unsigned char *packet;
|
||||
unsigned long packet_len, bufwrote = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Writing %d bytes on channel %lu/%lu, stream #%d", (int)buflen, channel->local.id, channel->remote.id, stream_id);
|
||||
#endif
|
||||
if (channel->local.close) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED, "We've already closed this channel", 0);
|
||||
return -1;
|
||||
@@ -902,48 +968,78 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_EOF_SENT, "EOF has already been sight, data might be ignored", 0);
|
||||
}
|
||||
|
||||
if (channel->blocking && channel->local.window_size_initial && (channel->local.window_size <= 0)) {
|
||||
/* twiddle our thumbs until there's window space available */
|
||||
if (libssh2_packet_read(session, 1) < 0) {
|
||||
/* Error occured, disconnect? */
|
||||
return -1;
|
||||
}
|
||||
if (!channel->blocking && (channel->local.window_size <= 0)) {
|
||||
/* Can't write anything */
|
||||
return 0;
|
||||
}
|
||||
|
||||
packet_len = buflen + (stream_id ? 13 : 9); /* packet_type(1) + channelno(4) [ + streamid(4) ] + buflen(4) */
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocte space for data transmission packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (buflen > 0) {
|
||||
size_t bufwrite = buflen;
|
||||
unsigned char *s = packet;
|
||||
|
||||
*(s++) = stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA : SSH_MSG_CHANNEL_DATA;
|
||||
libssh2_htonu32(s, channel->remote.id); s += 4;
|
||||
if (stream_id) {
|
||||
libssh2_htonu32(s, stream_id); s += 4;
|
||||
}
|
||||
|
||||
/* twiddle our thumbs until there's window space available */
|
||||
while (channel->local.window_size <= 0) {
|
||||
/* Don't worry -- This is never hit unless it's a blocking channel anyway */
|
||||
if (libssh2_packet_read(session, 1) < 0) {
|
||||
/* Error occured, disconnect? */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't exceed the remote end's limits */
|
||||
/* REMEMBER local means local as the SOURCE of the data */
|
||||
if (channel->local.window_size_initial && (buflen > channel->local.window_size)) {
|
||||
buflen = channel->local.window_size;
|
||||
if (bufwrite > channel->local.window_size) {
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Splitting write block due to %lu byte window_size on %lu/%lu/%d", channel->local.window_size, channel->local.id, channel->remote.id, stream_id);
|
||||
#endif
|
||||
bufwrite = channel->local.window_size;
|
||||
}
|
||||
if (buflen > channel->local.packet_size) {
|
||||
buflen = channel->local.packet_size;
|
||||
if (bufwrite > channel->local.packet_size) {
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Splitting write block due to %lu byte packet_size on %lu/%lu/%d", channel->local.packet_size, channel->local.id, channel->remote.id, stream_id);
|
||||
#endif
|
||||
bufwrite = channel->local.packet_size;
|
||||
}
|
||||
libssh2_htonu32(s, buflen); s += 4;
|
||||
memcpy(s, buf, buflen); s += buflen;
|
||||
libssh2_htonu32(s, bufwrite); s += 4;
|
||||
memcpy(s, buf, bufwrite); s += bufwrite;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Sending %d bytes on channel %lu/%lu, stream_id=%d", (int)bufwrite, channel->local.id, channel->remote.id, stream_id);
|
||||
#endif
|
||||
if (libssh2_packet_write(session, packet, s - packet)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel data", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
/* Shrink local window size */
|
||||
channel->local.window_size -= buflen;
|
||||
channel->local.window_size -= bufwrite;
|
||||
|
||||
/* Adjust buf for next iteration */
|
||||
buflen -= bufwrite;
|
||||
buf += bufwrite;
|
||||
bufwrote += bufwrite;
|
||||
|
||||
if (!channel->blocking) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
return buflen;
|
||||
return bufwrote;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -955,6 +1051,9 @@ LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel)
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char packet[5]; /* packet_type(1) + channelno(4) */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Sending EOF on channel %lu/%lu",channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
packet[0] = SSH_MSG_CHANNEL_EOF;
|
||||
libssh2_htonu32(packet + 1, channel->remote.id);
|
||||
if (libssh2_packet_write(session, packet, 5)) {
|
||||
@@ -1001,9 +1100,14 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Closing channel %lu/%lu", channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
|
||||
if (channel->close_cb) {
|
||||
LIBSSH2_CHANNEL_CLOSE(session, channel);
|
||||
}
|
||||
channel->local.close = 1;
|
||||
|
||||
packet[0] = SSH_MSG_CHANNEL_CLOSE;
|
||||
libssh2_htonu32(packet + 1, channel->remote.id);
|
||||
@@ -1011,7 +1115,6 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel)
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send close-channel request", 0);
|
||||
return -1;
|
||||
}
|
||||
channel->local.close = 1;
|
||||
|
||||
/* TODO: Wait up to a timeout value for a CHANNEL_CLOSE to come back, to avoid the problem alluded to in channel_nextid */
|
||||
|
||||
@@ -1019,6 +1122,35 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_channel_wait_closed
|
||||
* Awaiting channel close after EOF
|
||||
*/
|
||||
LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel)
|
||||
{
|
||||
LIBSSH2_SESSION* session = channel->session;
|
||||
|
||||
if (!libssh2_channel_eof(channel)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_INVAL, "libssh2_channel_wait_closed() invoked when channel is not in EOF state", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Awaiting close of channel %lu/%lu", channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
|
||||
/* while channel is not closed, read more
|
||||
* packets from the network.
|
||||
* Either or channel will be closed
|
||||
* or network timeout will occur
|
||||
*/
|
||||
while (!channel->remote.close && libssh2_packet_read(session, 1) > 0)
|
||||
;
|
||||
|
||||
return 1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ libssh2_channel_free
|
||||
* Make sure a channel is closed, then remove the channel from the session and free its resource(s)
|
||||
*/
|
||||
@@ -1028,6 +1160,9 @@ LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel)
|
||||
unsigned char channel_id[4], *data;
|
||||
unsigned long data_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Freeing channel %lu/%lu resources", channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
/* Allow channel freeing even when the socket has lost its connection */
|
||||
if (!channel->local.close && (session->socket_state == LIBSSH2_SOCKET_CONNECTED) &&
|
||||
libssh2_channel_close(channel)) {
|
||||
@@ -1068,3 +1203,53 @@ LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel)
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_channel_window_read_ex
|
||||
* Check the status of the read window
|
||||
* Returns the number of bytes which the remote end may send without overflowing the window limit
|
||||
* read_avail (if passed) will be populated with the number of bytes actually available to be read
|
||||
* window_size_initial (if passed) will be populated with the window_size_initial as defined by the channel_open request
|
||||
*/
|
||||
LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial)
|
||||
{
|
||||
if (window_size_initial) {
|
||||
*window_size_initial = channel->remote.window_size_initial;
|
||||
}
|
||||
|
||||
if (read_avail) {
|
||||
unsigned long bytes_queued = 0;
|
||||
LIBSSH2_PACKET *packet = channel->session->packets.head;
|
||||
|
||||
while (packet) {
|
||||
unsigned char packet_type = packet->data[0];
|
||||
|
||||
if (((packet_type == SSH_MSG_CHANNEL_DATA) || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)) &&
|
||||
(libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
|
||||
bytes_queued += packet->data_len - packet->data_head;
|
||||
}
|
||||
|
||||
packet = packet->next;
|
||||
}
|
||||
|
||||
*read_avail = bytes_queued;
|
||||
}
|
||||
|
||||
return channel->remote.window_size;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_channel_window_write_ex
|
||||
* Check the status of the write window
|
||||
* Returns the number of bytes which may be safely writen on the channel without blocking
|
||||
* window_size_initial (if passed) will be populated with the size of the initial window as defined by the channel_open request
|
||||
*/
|
||||
LIBSSH2_API unsigned long libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, unsigned long *window_size_initial)
|
||||
{
|
||||
if (window_size_initial) {
|
||||
/* For locally initiated channels this is very often 0, so it's not *that* useful as information goes */
|
||||
*window_size_initial = channel->local.window_size_initial;
|
||||
}
|
||||
|
||||
return channel->local.window_size;
|
||||
}
|
||||
/* }}} */
|
||||
|
107
src/comp.c
107
src/comp.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -45,10 +45,20 @@
|
||||
/* {{{ libssh2_comp_method_none_comp
|
||||
* Minimalist compression: Absolutely none
|
||||
*/
|
||||
static int libssh2_comp_method_none_comp(LIBSSH2_SESSION *session, int compress,
|
||||
unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
|
||||
const unsigned char *src, unsigned long src_len, void **abstract)
|
||||
static int libssh2_comp_method_none_comp(LIBSSH2_SESSION *session,
|
||||
int compress,
|
||||
unsigned char **dest,
|
||||
unsigned long *dest_len,
|
||||
unsigned long payload_limit,
|
||||
int *free_dest,
|
||||
const unsigned char *src,
|
||||
unsigned long src_len,
|
||||
void **abstract)
|
||||
{
|
||||
(void)session;
|
||||
(void)compress;
|
||||
(void)payload_limit;
|
||||
(void)abstract;
|
||||
*dest = (unsigned char *)src;
|
||||
*dest_len = src_len;
|
||||
|
||||
@@ -59,7 +69,7 @@ static int libssh2_comp_method_none_comp(LIBSSH2_SESSION *session, int compress,
|
||||
/* }}} */
|
||||
|
||||
static LIBSSH2_COMP_METHOD libssh2_comp_method_none = {
|
||||
"none",
|
||||
(char *)"none",
|
||||
NULL,
|
||||
libssh2_comp_method_none_comp,
|
||||
NULL
|
||||
@@ -129,28 +139,36 @@ static int libssh2_comp_method_zlib_init(LIBSSH2_SESSION *session, int compress,
|
||||
/* {{{ libssh2_comp_method_zlib_comp
|
||||
* zlib, a compression standard for all occasions
|
||||
*/
|
||||
static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
|
||||
unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
|
||||
const unsigned char *src, unsigned long src_len, void **abstract)
|
||||
static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session,
|
||||
int compress,
|
||||
unsigned char **dest,
|
||||
unsigned long *dest_len,
|
||||
unsigned long payload_limit,
|
||||
int *free_dest,
|
||||
const unsigned char *src,
|
||||
unsigned long src_len,
|
||||
void **abstract)
|
||||
{
|
||||
z_stream *strm = *abstract;
|
||||
/* A short-term alloc of a full data chunk is better than a series of reallocs */
|
||||
/* A short-term alloc of a full data chunk is better than a series of
|
||||
reallocs */
|
||||
char *out;
|
||||
int out_maxlen = compress ? src_len : (2 * src_len);
|
||||
int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
|
||||
int limiter = 0;
|
||||
|
||||
/* In practice they never come smaller than this */
|
||||
if (out_maxlen < 21) {
|
||||
out_maxlen = 21;
|
||||
if (out_maxlen < 25) {
|
||||
out_maxlen = 25;
|
||||
}
|
||||
|
||||
if (out_maxlen > payload_limit) {
|
||||
if (out_maxlen > (int)payload_limit) {
|
||||
out_maxlen = payload_limit;
|
||||
}
|
||||
|
||||
strm->next_in = (char *)src;
|
||||
strm->next_in = (unsigned char *)src;
|
||||
strm->avail_in = src_len;
|
||||
out = strm->next_out = LIBSSH2_ALLOC(session, out_maxlen);
|
||||
strm->next_out = (unsigned char *)LIBSSH2_ALLOC(session, out_maxlen);
|
||||
out = (char *)strm->next_out;
|
||||
strm->avail_out = out_maxlen;
|
||||
if (!strm->next_out) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate compression/decompression buffer", 0);
|
||||
@@ -166,17 +184,19 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
|
||||
}
|
||||
if (status != Z_OK) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
|
||||
LIBSSH2_FREE(session, strm->next_out);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
if (strm->avail_in) {
|
||||
unsigned long out_ofs = out_maxlen - strm->avail_out;
|
||||
|
||||
out_maxlen += compress ? strm->avail_in : (2 * strm->avail_in);
|
||||
out_maxlen += compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
|
||||
|
||||
if ((out_maxlen > payload_limit) && !compress && limiter++) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
|
||||
LIBSSH2_FREE(session, strm->next_out);
|
||||
if ((out_maxlen > (int)payload_limit) &&
|
||||
!compress && limiter++) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"Excessive growth in decompression phase", 0);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -185,12 +205,49 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to expand compress/decompression buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
strm->next_out = out + out_ofs;
|
||||
strm->avail_out += compress ? strm->avail_in : (2 * strm->avail_in);
|
||||
strm->next_out = (unsigned char *)out + out_ofs;
|
||||
strm->avail_out += compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
|
||||
} else while (!strm->avail_out) {
|
||||
/* Done with input, might be a byte or two in internal buffer during compress
|
||||
* Or potentially many bytes if it's a decompress
|
||||
*/
|
||||
int grow_size = compress ? 8 : 1024;
|
||||
|
||||
if (out_maxlen >= (int)payload_limit) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (grow_size > (int)(payload_limit - out_maxlen)) {
|
||||
grow_size = payload_limit - out_maxlen;
|
||||
}
|
||||
|
||||
out_maxlen += grow_size;
|
||||
strm->avail_out = grow_size;
|
||||
|
||||
out = LIBSSH2_REALLOC(session, out, out_maxlen);
|
||||
if (!out) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to expand final compress/decompress buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
strm->next_out = (unsigned char *)out + out_maxlen -
|
||||
grow_size;
|
||||
|
||||
if (compress) {
|
||||
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||
} else {
|
||||
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||
}
|
||||
if (status != Z_OK) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*dest = out;
|
||||
*dest = (unsigned char *)out;
|
||||
*dest_len = out_maxlen - strm->avail_out;
|
||||
*free_dest = 1;
|
||||
|
||||
@@ -224,7 +281,7 @@ static int libssh2_comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compress,
|
||||
/* }}} */
|
||||
|
||||
static LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
|
||||
"zlib",
|
||||
(char *)"zlib",
|
||||
libssh2_comp_method_zlib_init,
|
||||
libssh2_comp_method_zlib_comp,
|
||||
libssh2_comp_method_zlib_dtor,
|
||||
@@ -236,10 +293,10 @@ static LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
|
||||
*********************** */
|
||||
|
||||
static LIBSSH2_COMP_METHOD *_libssh2_comp_methods[] = {
|
||||
&libssh2_comp_method_none,
|
||||
#ifdef LIBSSH2_HAVE_ZLIB
|
||||
&libssh2_comp_method_zlib,
|
||||
#endif /* LIBSSH2_HAVE_ZLIB */
|
||||
&libssh2_comp_method_none,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
191
src/crypt.c
191
src/crypt.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,9 +36,8 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#ifdef LIBSSH2_CRYPT_NONE
|
||||
#if LIBSSH2_CRYPT_NONE
|
||||
/* {{{ libssh2_crypt_none_crypt
|
||||
* Minimalist cipher: VERY secure *wink*
|
||||
*/
|
||||
@@ -59,29 +58,67 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = {
|
||||
libssh2_crypt_none_crypt,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
#endif /* LIBSSH2_CRYPT_NONE */
|
||||
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
|
||||
"3des-cbc",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
24, /* secret length */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_des_ede3_cbc,
|
||||
NULL,
|
||||
struct crypt_ctx {
|
||||
int encrypt;
|
||||
_libssh2_cipher_type(algo);
|
||||
_libssh2_cipher_ctx h;
|
||||
};
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
|
||||
static int init (LIBSSH2_SESSION *session,
|
||||
LIBSSH2_CRYPT_METHOD *method,
|
||||
unsigned char *iv, int *free_iv,
|
||||
unsigned char *secret, int *free_secret,
|
||||
int encrypt, void **abstract)
|
||||
{
|
||||
struct crypt_ctx *ctx = LIBSSH2_ALLOC(session,
|
||||
sizeof(struct crypt_ctx));
|
||||
if (!ctx) {
|
||||
return -1;
|
||||
}
|
||||
ctx->encrypt = encrypt;
|
||||
ctx->algo = method->algo;
|
||||
if (_libssh2_cipher_init (&ctx->h, ctx->algo, iv, secret, encrypt))
|
||||
{
|
||||
LIBSSH2_FREE (session, ctx);
|
||||
return -1;
|
||||
}
|
||||
*abstract = ctx;
|
||||
*free_iv = 1;
|
||||
*free_secret = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypt(LIBSSH2_SESSION *session, unsigned char *block, void **abstract)
|
||||
{
|
||||
struct crypt_ctx *cctx = *(struct crypt_ctx **)abstract;
|
||||
return _libssh2_cipher_crypt(&cctx->h, cctx->algo,
|
||||
cctx->encrypt, block);
|
||||
}
|
||||
|
||||
static int dtor(LIBSSH2_SESSION *session, void **abstract)
|
||||
{
|
||||
struct crypt_ctx **cctx = (struct crypt_ctx **)abstract;
|
||||
if (cctx && *cctx) {
|
||||
_libssh2_cipher_dtor(&(*cctx)->h);
|
||||
LIBSSH2_FREE(session, *cctx);
|
||||
*abstract = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LIBSSH2_AES
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = {
|
||||
"aes128-cbc",
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
16, /* secret length -- 16*8 == 128bit */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_aes_128_cbc,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_aes128
|
||||
};
|
||||
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
|
||||
@@ -89,10 +126,11 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
24, /* secret length -- 24*8 == 192bit */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_aes_192_cbc,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_aes192
|
||||
};
|
||||
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
|
||||
@@ -100,10 +138,11 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
32, /* secret length -- 32*8 == 256bit */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_aes_256_cbc,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_aes256
|
||||
};
|
||||
|
||||
/* rijndael-cbc@lysator.liu.se == aes256-cbc */
|
||||
@@ -112,72 +151,90 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_rijndael_cbc_lysator_liu_se = {
|
||||
16, /* blocksize */
|
||||
16, /* initial value length */
|
||||
32, /* secret length -- 32*8 == 256bit */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_aes_256_cbc,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_aes256
|
||||
};
|
||||
#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)*/
|
||||
#endif /* LIBSSH2_AES */
|
||||
|
||||
#ifndef OPENSSL_NO_BLOWFISH
|
||||
#if LIBSSH2_BLOWFISH
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = {
|
||||
"blowfish-cbc",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
16, /* secret length */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_bf_cbc,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_blowfish
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_BLOWFISH */
|
||||
#endif /* LIBSSH2_BLOWFISH */
|
||||
|
||||
#ifndef OPENSSL_NO_CAST
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
|
||||
"cast128-cbc",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
16, /* secret length */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_cast5_cbc,
|
||||
NULL,
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_CAST */
|
||||
|
||||
#ifndef OPENSSL_NO_RC4
|
||||
#if LIBSSH2_RC4
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = {
|
||||
"arcfour",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
16, /* secret length */
|
||||
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
|
||||
NULL,
|
||||
(void*)EVP_rc4,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_arcfour
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_RC4 */
|
||||
#endif /* LIBSSH2_RC4 */
|
||||
|
||||
#if LIBSSH2_CAST
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
|
||||
"cast128-cbc",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
16, /* secret length */
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_cast5
|
||||
};
|
||||
#endif /* LIBSSH2_CAST */
|
||||
|
||||
#if LIBSSH2_3DES
|
||||
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
|
||||
"3des-cbc",
|
||||
8, /* blocksize */
|
||||
8, /* initial value length */
|
||||
24, /* secret length */
|
||||
0, /* flags */
|
||||
&init,
|
||||
&crypt,
|
||||
&dtor,
|
||||
_libssh2_cipher_3des
|
||||
};
|
||||
#endif
|
||||
|
||||
static LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
|
||||
#if LIBSSH2_AES
|
||||
&libssh2_crypt_method_aes256_cbc,
|
||||
&libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */
|
||||
&libssh2_crypt_method_aes192_cbc,
|
||||
&libssh2_crypt_method_aes128_cbc,
|
||||
#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES) */
|
||||
#ifndef OPENSSL_NO_BLOWFISH
|
||||
#endif /* LIBSSH2_AES */
|
||||
#if LIBSSH2_BLOWFISH
|
||||
&libssh2_crypt_method_blowfish_cbc,
|
||||
#endif /* ! OPENSSL_NO_BLOWFISH */
|
||||
#ifndef OPENSSL_NO_RC4
|
||||
#endif /* LIBSSH2_BLOWFISH */
|
||||
#if LIBSSH2_RC4
|
||||
&libssh2_crypt_method_arcfour,
|
||||
#endif /* ! OPENSSL_NO_RC4 */
|
||||
#ifndef OPENSSL_NO_CAST
|
||||
#endif /* LIBSSH2_RC4 */
|
||||
#if LIBSSH2_CAST
|
||||
&libssh2_crypt_method_cast128_cbc,
|
||||
#endif /* ! OPENSSL_NO_CAST */
|
||||
#ifndef OPENSSL_NO_DES
|
||||
#endif /* LIBSSH2_CAST */
|
||||
#if LIBSSH2_3DES
|
||||
&libssh2_crypt_method_3des_cbc,
|
||||
#endif /* ! OPENSSL_NO_DES */
|
||||
#ifdef LIBSSH2_CRYPT_NONE
|
||||
#endif /* LIBSSH2_DES */
|
||||
#if LIBSSH2_CRYPT_NONE
|
||||
&libssh2_crypt_method_none,
|
||||
#endif
|
||||
NULL
|
||||
|
348
src/hostkey.c
348
src/hostkey.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,11 +36,13 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#ifndef OPENSSL_NO_RSA
|
||||
/* Needed for struct iovec on some platforms */
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if LIBSSH2_RSA
|
||||
/* ***********
|
||||
* ssh-rsa *
|
||||
*********** */
|
||||
@@ -50,33 +52,42 @@ static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION *session, void **
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_init
|
||||
* Initialize the server hostkey working area with e/n pair
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract)
|
||||
static int
|
||||
libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session,
|
||||
unsigned char *hostkey_data,
|
||||
unsigned long hostkey_data_len,
|
||||
void **abstract)
|
||||
{
|
||||
RSA *rsactx;
|
||||
libssh2_rsa_ctx *rsactx;
|
||||
unsigned char *s, *e, *n;
|
||||
unsigned long len, e_len, n_len;
|
||||
|
||||
(void)hostkey_data_len;
|
||||
|
||||
if (*abstract) {
|
||||
libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
|
||||
*abstract = NULL;
|
||||
}
|
||||
|
||||
s = hostkey_data;
|
||||
len = libssh2_ntohu32(s); s += 4;
|
||||
if (len != 7 || strncmp(s, "ssh-rsa", 7) != 0) {
|
||||
return -1;
|
||||
} s += 7;
|
||||
len = libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
|
||||
if (len != 7 || strncmp((char *)s, "ssh-rsa", 7) != 0) {
|
||||
return -1;
|
||||
}
|
||||
s += 7;
|
||||
|
||||
e_len = libssh2_ntohu32(s);
|
||||
s += 4;
|
||||
|
||||
e_len = libssh2_ntohu32(s); s += 4;
|
||||
e = s; s += e_len;
|
||||
n_len = libssh2_ntohu32(s); s += 4;
|
||||
n = s; s += n_len;
|
||||
|
||||
rsactx = RSA_new();
|
||||
rsactx->e = BN_new();
|
||||
BN_bin2bn(e, e_len, rsactx->e);
|
||||
rsactx->n = BN_new();
|
||||
BN_bin2bn(n, n_len, rsactx->n);
|
||||
if (_libssh2_rsa_new (&rsactx, e, e_len, n, n_len, NULL, 0,
|
||||
NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0))
|
||||
return -1;
|
||||
|
||||
*abstract = rsactx;
|
||||
|
||||
@@ -84,30 +95,15 @@ static int libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session, unsigne
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_passphrase_cb
|
||||
* TODO: Optionally call a passphrase callback specified by the calling program
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsadsa_passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
|
||||
{
|
||||
int passphrase_len = strlen(passphrase);
|
||||
|
||||
if (passphrase_len > (size - 1)) {
|
||||
passphrase_len = size - 1;
|
||||
}
|
||||
memcpy(buf, passphrase, passphrase_len);
|
||||
buf[passphrase_len] = '\0';
|
||||
|
||||
return passphrase_len;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_initPEM
|
||||
* Load a Private Key from a PEM file
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session,
|
||||
const char *privkeyfile, unsigned const char *passphrase, void **abstract)
|
||||
{
|
||||
RSA *rsactx;
|
||||
libssh2_rsa_ctx *rsactx;
|
||||
FILE *fp;
|
||||
int ret;
|
||||
|
||||
if (*abstract) {
|
||||
libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
|
||||
@@ -119,19 +115,11 @@ static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsi
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none are.
|
||||
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
|
||||
* Someone buy me an OpenSSL manual and I'll read up on it.
|
||||
*/
|
||||
OPENSSL_add_all_algorithms_noconf();
|
||||
}
|
||||
rsactx = PEM_read_RSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase);
|
||||
if (!rsactx) {
|
||||
ret = _libssh2_rsa_new_private (&rsactx, session, fp, passphrase);
|
||||
fclose(fp);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
*abstract = rsactx;
|
||||
|
||||
@@ -142,56 +130,19 @@ static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsi
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_sign
|
||||
* Verify signature created by remote
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION *session,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len,
|
||||
void **abstract)
|
||||
{
|
||||
RSA *rsactx = (RSA*)(*abstract);
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
int ret;
|
||||
libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx*)(*abstract);
|
||||
(void)session;
|
||||
|
||||
/* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
|
||||
sig += 15; sig_len -= 15;
|
||||
SHA1(m, m_len, hash);
|
||||
ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, (char *)sig, sig_len, rsactx);
|
||||
|
||||
return (ret == 1) ? 0 : -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_sign
|
||||
* Sign data to send to remote
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_sign(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
|
||||
const unsigned char *buf, unsigned long buf_len, void **abstract)
|
||||
{
|
||||
RSA *rsactx = (RSA*)(*abstract);
|
||||
int ret;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx;
|
||||
char *sig;
|
||||
int sig_len;
|
||||
|
||||
sig_len = RSA_size(rsactx);
|
||||
sig = LIBSSH2_ALLOC(session, sig_len);
|
||||
|
||||
if (!sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, buf, buf_len);
|
||||
SHA1_Final(hash, &ctx);
|
||||
|
||||
ret = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, rsactx);
|
||||
if (!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*signature = sig;
|
||||
*signature_len = sig_len;
|
||||
|
||||
return 0;
|
||||
return _libssh2_rsa_sha1_verify (rsactx, sig, sig_len, m, m_len);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -201,36 +152,24 @@ static int libssh2_hostkey_method_ssh_rsa_sign(LIBSSH2_SESSION *session, unsigne
|
||||
static int libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
|
||||
unsigned long veccount, const struct iovec datavec[], void **abstract)
|
||||
{
|
||||
RSA *rsactx = (RSA*)(*abstract);
|
||||
int ret, i;
|
||||
libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx*)(*abstract);
|
||||
int ret;
|
||||
unsigned int i;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx;
|
||||
char *sig;
|
||||
int sig_len;
|
||||
libssh2_sha1_ctx ctx;
|
||||
|
||||
sig_len = RSA_size(rsactx);
|
||||
sig = LIBSSH2_ALLOC(session, sig_len);
|
||||
|
||||
if (!sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
libssh2_sha1_init(&ctx);
|
||||
for(i = 0; i < veccount; i++) {
|
||||
SHA1_Update(&ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
}
|
||||
SHA1_Final(hash, &ctx);
|
||||
libssh2_sha1_final(ctx, hash);
|
||||
|
||||
ret = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, rsactx);
|
||||
|
||||
if (!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH,
|
||||
signature, signature_len);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*signature = sig;
|
||||
*signature_len = sig_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -238,11 +177,13 @@ static int libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION *session, unsign
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_dtor
|
||||
* Shutdown the hostkey
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION *session, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION *session,
|
||||
void **abstract)
|
||||
{
|
||||
RSA *rsactx = (RSA*)(*abstract);
|
||||
libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx*)(*abstract);
|
||||
(void)session;
|
||||
|
||||
RSA_free(rsactx);
|
||||
_libssh2_rsa_free(rsactx);
|
||||
|
||||
*abstract = NULL;
|
||||
|
||||
@@ -256,14 +197,13 @@ static LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_rsa = {
|
||||
libssh2_hostkey_method_ssh_rsa_init,
|
||||
libssh2_hostkey_method_ssh_rsa_initPEM,
|
||||
libssh2_hostkey_method_ssh_rsa_sig_verify,
|
||||
libssh2_hostkey_method_ssh_rsa_sign,
|
||||
libssh2_hostkey_method_ssh_rsa_signv,
|
||||
NULL, /* encrypt */
|
||||
libssh2_hostkey_method_ssh_rsa_dtor,
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_RSA */
|
||||
#endif /* LIBSSH2_RSA */
|
||||
|
||||
#ifndef OPENSSL_NO_DSA
|
||||
#if LIBSSH2_DSA
|
||||
/* ***********
|
||||
* ssh-dss *
|
||||
*********** */
|
||||
@@ -273,11 +213,16 @@ static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION *session, void **
|
||||
/* {{{ libssh2_hostkey_method_ssh_dss_init
|
||||
* Initialize the server hostkey working area with p/q/g/y set
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract)
|
||||
static int
|
||||
libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session,
|
||||
unsigned char *hostkey_data,
|
||||
unsigned long hostkey_data_len,
|
||||
void **abstract)
|
||||
{
|
||||
DSA *dsactx;
|
||||
libssh2_dsa_ctx *dsactx;
|
||||
unsigned char *p, *q, *g, *y, *s;
|
||||
unsigned long p_len, q_len, g_len, y_len, len;
|
||||
(void)hostkey_data_len;
|
||||
|
||||
if (*abstract) {
|
||||
libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
|
||||
@@ -286,7 +231,7 @@ static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigne
|
||||
|
||||
s = hostkey_data;
|
||||
len = libssh2_ntohu32(s); s += 4;
|
||||
if (len != 7 || strncmp(s, "ssh-dss", 7) != 0) {
|
||||
if (len != 7 || strncmp((char *)s, "ssh-dss", 7) != 0) {
|
||||
return -1;
|
||||
} s += 7;
|
||||
|
||||
@@ -299,15 +244,8 @@ static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigne
|
||||
y_len = libssh2_ntohu32(s); s += 4;
|
||||
y = s; s += y_len;
|
||||
|
||||
dsactx = DSA_new();
|
||||
dsactx->p = BN_new();
|
||||
BN_bin2bn(p, p_len, dsactx->p);
|
||||
dsactx->q = BN_new();
|
||||
BN_bin2bn(q, q_len, dsactx->q);
|
||||
dsactx->g = BN_new();
|
||||
BN_bin2bn(g, g_len, dsactx->g);
|
||||
dsactx->pub_key = BN_new();
|
||||
BN_bin2bn(y, y_len, dsactx->pub_key);
|
||||
_libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len,
|
||||
y, y_len, NULL, 0);
|
||||
|
||||
*abstract = dsactx;
|
||||
|
||||
@@ -318,10 +256,14 @@ static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigne
|
||||
/* {{{ libssh2_hostkey_method_ssh_dss_initPEM
|
||||
* Load a Private Key from a PEM file
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session,
|
||||
const char *privkeyfile,
|
||||
unsigned const char *passphrase,
|
||||
void **abstract)
|
||||
{
|
||||
DSA *dsactx;
|
||||
libssh2_dsa_ctx *dsactx;
|
||||
FILE *fp;
|
||||
int ret;
|
||||
|
||||
if (*abstract) {
|
||||
libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
|
||||
@@ -333,19 +275,11 @@ static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsi
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none are.
|
||||
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
|
||||
* Someone buy me an OpenSSL manual and I'll read up on it.
|
||||
*/
|
||||
OPENSSL_add_all_algorithms_noconf();
|
||||
}
|
||||
dsactx = PEM_read_DSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase);
|
||||
if (!dsactx) {
|
||||
ret = _libssh2_dsa_new_private (&dsactx, session, fp, passphrase);
|
||||
fclose(fp);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
*abstract = dsactx;
|
||||
|
||||
@@ -359,10 +293,7 @@ static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsi
|
||||
static int libssh2_hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len, void **abstract)
|
||||
{
|
||||
DSA *dsactx = (DSA*)(*abstract);
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
DSA_SIG dsasig;
|
||||
int ret;
|
||||
libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx*)(*abstract);
|
||||
|
||||
/* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
|
||||
sig += 15; sig_len -= 15;
|
||||
@@ -370,63 +301,7 @@ static int libssh2_hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION *session, c
|
||||
libssh2_error(session, LIBSSH2_ERROR_PROTO, "Invalid DSS signature length", 0);
|
||||
return -1;
|
||||
}
|
||||
dsasig.r = BN_new();
|
||||
BN_bin2bn(sig, 20, dsasig.r);
|
||||
dsasig.s = BN_new();
|
||||
BN_bin2bn(sig + 20, 20, dsasig.s);
|
||||
|
||||
SHA1(m, m_len, hash);
|
||||
ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx);
|
||||
|
||||
return (ret == 1) ? 0 : -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_hostkey_method_ssh_dss_sign
|
||||
* Sign data to send to remote
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_dss_sign(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
|
||||
const unsigned char *buf, unsigned long buf_len, void **abstract)
|
||||
{
|
||||
DSA *dsactx = (DSA*)(*abstract);
|
||||
DSA_SIG *sig;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx;
|
||||
int r_len, s_len, rs_pad;
|
||||
|
||||
*signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
|
||||
*signature_len = 2 * SHA_DIGEST_LENGTH;
|
||||
memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
|
||||
|
||||
if (!(*signature)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, buf, buf_len);
|
||||
SHA1_Final(hash, &ctx);
|
||||
|
||||
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
|
||||
if (!sig) {
|
||||
LIBSSH2_FREE(session, *signature);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r_len = BN_num_bytes(sig->r);
|
||||
s_len = BN_num_bytes(sig->s);
|
||||
rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
|
||||
if (rs_pad < 0) {
|
||||
DSA_SIG_free(sig);
|
||||
LIBSSH2_FREE(session, *signature);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BN_bn2bin(sig->r, *signature + rs_pad);
|
||||
BN_bn2bin(sig->s, *signature + rs_pad + r_len);
|
||||
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
return 0;
|
||||
return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -436,11 +311,10 @@ static int libssh2_hostkey_method_ssh_dss_sign(LIBSSH2_SESSION *session, unsigne
|
||||
static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
|
||||
unsigned long veccount, const struct iovec datavec[], void **abstract)
|
||||
{
|
||||
DSA *dsactx = (DSA*)(*abstract);
|
||||
DSA_SIG *sig;
|
||||
libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx*)(*abstract);
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx;
|
||||
int r_len, s_len, rs_pad, i;
|
||||
libssh2_sha1_ctx ctx;
|
||||
unsigned int i;
|
||||
|
||||
*signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
|
||||
*signature_len = 2 * SHA_DIGEST_LENGTH;
|
||||
@@ -450,32 +324,19 @@ static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsign
|
||||
return -1;
|
||||
}
|
||||
|
||||
SHA1_Init(&ctx);
|
||||
libssh2_sha1_init(&ctx);
|
||||
for(i = 0; i < veccount; i++) {
|
||||
SHA1_Update(&ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
|
||||
}
|
||||
SHA1_Final(hash, &ctx);
|
||||
libssh2_sha1_final(ctx, hash);
|
||||
|
||||
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
|
||||
if (!sig) {
|
||||
if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH,
|
||||
*signature))
|
||||
{
|
||||
LIBSSH2_FREE(session, *signature);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r_len = BN_num_bytes(sig->r);
|
||||
s_len = BN_num_bytes(sig->s);
|
||||
rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
|
||||
if (rs_pad < 0) {
|
||||
DSA_SIG_free(sig);
|
||||
LIBSSH2_FREE(session, *signature);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BN_bn2bin(sig->r, *signature + rs_pad);
|
||||
BN_bn2bin(sig->s, *signature + rs_pad + r_len);
|
||||
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -483,11 +344,13 @@ static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsign
|
||||
/* {{{ libssh2_hostkey_method_ssh_dss_dtor
|
||||
* Shutdown the hostkey method
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION *session, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION *session,
|
||||
void **abstract)
|
||||
{
|
||||
DSA *dsactx = (DSA*)(*abstract);
|
||||
libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx*)(*abstract);
|
||||
(void)session;
|
||||
|
||||
DSA_free(dsactx);
|
||||
_libssh2_dsa_free(dsactx);
|
||||
|
||||
*abstract = NULL;
|
||||
|
||||
@@ -501,20 +364,19 @@ static LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_dss = {
|
||||
libssh2_hostkey_method_ssh_dss_init,
|
||||
libssh2_hostkey_method_ssh_dss_initPEM,
|
||||
libssh2_hostkey_method_ssh_dss_sig_verify,
|
||||
libssh2_hostkey_method_ssh_dss_sign,
|
||||
libssh2_hostkey_method_ssh_dss_signv,
|
||||
NULL, /* encrypt */
|
||||
libssh2_hostkey_method_ssh_dss_dtor,
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_DSA */
|
||||
#endif /* LIBSSH2_DSA */
|
||||
|
||||
static LIBSSH2_HOSTKEY_METHOD *_libssh2_hostkey_methods[] = {
|
||||
#ifndef OPENSSL_NO_RSA
|
||||
#if LIBSSH2_RSA
|
||||
&libssh2_hostkey_method_ssh_rsa,
|
||||
#endif /* ! OPENSSL_NO_RSA */
|
||||
#ifndef OPENSSL_NO_DSA
|
||||
#endif /* LIBSSH2_RSA */
|
||||
#if LIBSSH2_DSA
|
||||
&libssh2_hostkey_method_ssh_dss,
|
||||
#endif /* ! OPENSSL_NO_DSA */
|
||||
#endif /* LIBSSH2_DSA */
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -529,19 +391,17 @@ LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void)
|
||||
* Length of buffer is determined by hash type
|
||||
* i.e. MD5 == 16, SHA1 == 20
|
||||
*/
|
||||
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type)
|
||||
LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type)
|
||||
{
|
||||
switch (hash_type) {
|
||||
#ifndef OPENSSL_NO_MD5
|
||||
#if LIBSSH2_MD5
|
||||
case LIBSSH2_HOSTKEY_HASH_MD5:
|
||||
return session->server_hostkey_md5;
|
||||
return (char *)session->server_hostkey_md5;
|
||||
break;
|
||||
#endif /* ! OPENSSL_NO_MD5 */
|
||||
#ifndef OPENSSL_NO_SHA
|
||||
#endif /* LIBSSH2_MD5 */
|
||||
case LIBSSH2_HOSTKEY_HASH_SHA1:
|
||||
return session->server_hostkey_sha1;
|
||||
return (char *)session->server_hostkey_sha1;
|
||||
break;
|
||||
#endif /* ! OPENSSL_NO_SHA */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
433
src/kex.c
433
src/kex.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,31 +36,27 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
/* TODO: Switch this to an inline and handle alloc() failures */
|
||||
/* Helper macro called from libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange */
|
||||
#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \
|
||||
{ \
|
||||
SHA_CTX hash; \
|
||||
libssh2_sha1_ctx hash; \
|
||||
unsigned long len = 0; \
|
||||
if (!(value)) { \
|
||||
value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH); \
|
||||
} \
|
||||
while (len < reqlen) { \
|
||||
SHA1_Init(&hash); \
|
||||
SHA1_Update(&hash, k_value, k_value_len); \
|
||||
SHA1_Update(&hash, h_sig_comp, SHA_DIGEST_LENGTH); \
|
||||
libssh2_sha1_init(&hash); \
|
||||
libssh2_sha1_update(hash, k_value, k_value_len); \
|
||||
libssh2_sha1_update(hash, h_sig_comp, SHA_DIGEST_LENGTH); \
|
||||
if (len > 0) { \
|
||||
SHA1_Update(&hash, value, len); \
|
||||
libssh2_sha1_update(hash, value, len); \
|
||||
} else { \
|
||||
SHA1_Update(&hash, (version), 1); \
|
||||
SHA1_Update(&hash, session->session_id, session->session_id_len); \
|
||||
libssh2_sha1_update(hash, (version), 1); \
|
||||
libssh2_sha1_update(hash, session->session_id, session->session_id_len); \
|
||||
} \
|
||||
SHA1_Final((value) + len, &hash); \
|
||||
libssh2_sha1_final(hash, (value) + len); \
|
||||
len += SHA_DIGEST_LENGTH; \
|
||||
} \
|
||||
}
|
||||
@@ -68,29 +64,29 @@
|
||||
/* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
|
||||
* Diffie Hellman Key Exchange, Group Agnostic
|
||||
*/
|
||||
static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session, BIGNUM *g, BIGNUM *p,
|
||||
static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session, _libssh2_bn *g, _libssh2_bn *p, int group_order,
|
||||
unsigned char packet_type_init, unsigned char packet_type_reply,
|
||||
unsigned char *midhash, unsigned long midhash_len)
|
||||
{
|
||||
unsigned char *e_packet = NULL, *s_packet = NULL, *tmp, h_sig_comp[SHA_DIGEST_LENGTH], c;
|
||||
unsigned long e_packet_len, s_packet_len, tmp_len;
|
||||
int ret = 0;
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BIGNUM *x = BN_new(); /* Random from client */
|
||||
BIGNUM *e = BN_new(); /* g^x mod p */
|
||||
BIGNUM *f = BN_new(); /* g^(Random from server) mod p */
|
||||
BIGNUM *k = BN_new(); /* The shared secret: f^x mod p */
|
||||
_libssh2_bn_ctx *ctx = _libssh2_bn_ctx_new();
|
||||
_libssh2_bn *x = _libssh2_bn_init(); /* Random from client */
|
||||
_libssh2_bn *e = _libssh2_bn_init(); /* g^x mod p */
|
||||
_libssh2_bn *f = _libssh2_bn_init(); /* g^(Random from server) mod p */
|
||||
_libssh2_bn *k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
|
||||
unsigned char *s, *f_value, *k_value = NULL, *h_sig;
|
||||
unsigned long f_value_len, k_value_len, h_sig_len;
|
||||
SHA_CTX exchange_hash;
|
||||
libssh2_sha1_ctx exchange_hash;
|
||||
|
||||
/* Generate x and e */
|
||||
BN_rand(x, 128, 0, -1);
|
||||
BN_mod_exp(e, g, x, p, ctx);
|
||||
_libssh2_bn_rand(x, group_order, 0, -1);
|
||||
_libssh2_bn_mod_exp(e, g, x, p, ctx);
|
||||
|
||||
/* Send KEX init */
|
||||
e_packet_len = BN_num_bytes(e) + 6; /* packet_type(1) + String Length(4) + leading 0(1) */
|
||||
if (BN_num_bits(e) % 8) {
|
||||
e_packet_len = _libssh2_bn_bytes(e) + 6; /* packet_type(1) + String Length(4) + leading 0(1) */
|
||||
if (_libssh2_bn_bits(e) % 8) {
|
||||
/* Leading 00 not needed */
|
||||
e_packet_len--;
|
||||
}
|
||||
@@ -102,19 +98,42 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
}
|
||||
e_packet[0] = packet_type_init;
|
||||
libssh2_htonu32(e_packet + 1, e_packet_len - 5);
|
||||
if (BN_num_bits(e) % 8) {
|
||||
BN_bn2bin(e, e_packet + 5);
|
||||
if (_libssh2_bn_bits(e) % 8) {
|
||||
_libssh2_bn_to_bin(e, e_packet + 5);
|
||||
} else {
|
||||
e_packet[5] = 0;
|
||||
BN_bn2bin(e, e_packet + 6);
|
||||
_libssh2_bn_to_bin(e, e_packet + 6);
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d", (int)packet_type_init);
|
||||
#endif
|
||||
if (libssh2_packet_write(session, e_packet, e_packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEX init message", 0);
|
||||
ret = -11;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (session->burn_optimistic_kexinit) {
|
||||
/* The first KEX packet to come along will be the guess initially sent by the server
|
||||
* That guess turned out to be wrong so we need to silently ignore it */
|
||||
int burn_type;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Waiting for badly guessed KEX packet (to be ignored)");
|
||||
#endif
|
||||
burn_type = libssh2_packet_burn(session);
|
||||
if (burn_type <= 0) {
|
||||
/* Failed to receive a packet */
|
||||
ret = -1;
|
||||
goto clean_exit;
|
||||
}
|
||||
session->burn_optimistic_kexinit = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Burnt packet of type: %02x", (unsigned int)burn_type);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Wait for KEX reply */
|
||||
if (libssh2_packet_require(session, packet_type_reply, &s_packet, &s_packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for KEX reply", 0);
|
||||
@@ -135,25 +154,45 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
memcpy(session->server_hostkey, s, session->server_hostkey_len);
|
||||
s += session->server_hostkey_len;
|
||||
|
||||
#ifndef OPENSSL_NO_MD5
|
||||
#if LIBSSH2_MD5
|
||||
{
|
||||
MD5_CTX fingerprint_ctx;
|
||||
libssh2_md5_ctx fingerprint_ctx;
|
||||
|
||||
MD5_Init(&fingerprint_ctx);
|
||||
MD5_Update(&fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
|
||||
MD5_Final(session->server_hostkey_md5, &fingerprint_ctx);
|
||||
libssh2_md5_init(&fingerprint_ctx);
|
||||
libssh2_md5_update(fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
|
||||
libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_SHA
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
{
|
||||
SHA_CTX fingerprint_ctx;
|
||||
|
||||
SHA1_Init(&fingerprint_ctx);
|
||||
SHA1_Update(&fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
|
||||
SHA1_Final(session->server_hostkey_sha1, &fingerprint_ctx);
|
||||
char fingerprint[50], *fprint = fingerprint;
|
||||
int i;
|
||||
for(i = 0; i < 16; i++, fprint += 3) {
|
||||
snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
|
||||
}
|
||||
*(--fprint) = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's MD5 Fingerprint: %s", fingerprint);
|
||||
}
|
||||
#endif
|
||||
#endif /* LIBSSH2_DEBUG_KEX */
|
||||
#endif /* ! LIBSSH2_MD5 */
|
||||
|
||||
{
|
||||
libssh2_sha1_ctx fingerprint_ctx;
|
||||
|
||||
libssh2_sha1_init(&fingerprint_ctx);
|
||||
libssh2_sha1_update (fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
|
||||
libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1);
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
{
|
||||
char fingerprint[64], *fprint = fingerprint;
|
||||
int i;
|
||||
for(i = 0; i < 20; i++, fprint += 3) {
|
||||
snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
|
||||
}
|
||||
*(--fprint) = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's SHA1 Fingerprint: %s", fingerprint);
|
||||
}
|
||||
#endif /* LIBSSH2_DEBUG_KEX */
|
||||
|
||||
if (session->hostkey->init(session, session->server_hostkey, session->server_hostkey_len, &session->server_hostkey_abstract)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, "Unable to initialize hostkey importer", 0);
|
||||
@@ -161,18 +200,17 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
|
||||
f_value_len = libssh2_ntohu32(s); s += 4;
|
||||
f_value = s; s += f_value_len;
|
||||
BN_bin2bn(f_value, f_value_len, f);
|
||||
_libssh2_bn_from_bin(f, f_value_len, f_value);
|
||||
|
||||
h_sig_len = libssh2_ntohu32(s); s += 4;
|
||||
h_sig = s;
|
||||
|
||||
/* Compute the shared secret */
|
||||
BN_mod_exp(k, f, x, p, ctx);
|
||||
k_value_len = BN_num_bytes(k) + 5;
|
||||
if (BN_num_bits(k) % 8) {
|
||||
_libssh2_bn_mod_exp(k, f, x, p, ctx);
|
||||
k_value_len = _libssh2_bn_bytes(k) + 5;
|
||||
if (_libssh2_bn_bits(k) % 8) {
|
||||
/* don't need leading 00 */
|
||||
k_value_len--;
|
||||
}
|
||||
@@ -183,39 +221,43 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
libssh2_htonu32(k_value, k_value_len - 4);
|
||||
if (BN_num_bits(k) % 8) {
|
||||
BN_bn2bin(k, k_value + 4);
|
||||
if (_libssh2_bn_bits(k) % 8) {
|
||||
_libssh2_bn_to_bin(k, k_value + 4);
|
||||
} else {
|
||||
k_value[4] = 0;
|
||||
BN_bn2bin(k, k_value + 5);
|
||||
_libssh2_bn_to_bin(k, k_value + 5);
|
||||
}
|
||||
|
||||
SHA1_Init(&exchange_hash);
|
||||
libssh2_sha1_init(&exchange_hash);
|
||||
if (session->local.banner) {
|
||||
libssh2_htonu32(h_sig_comp, strlen(session->local.banner) - 2);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, session->local.banner, strlen(session->local.banner) - 2);
|
||||
libssh2_htonu32(h_sig_comp,
|
||||
strlen((char *)session->local.banner) - 2);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, (char *)session->local.banner,
|
||||
strlen((char *)session->local.banner) - 2);
|
||||
} else {
|
||||
libssh2_htonu32(h_sig_comp, sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, LIBSSH2_SSH_DEFAULT_BANNER, sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, LIBSSH2_SSH_DEFAULT_BANNER,
|
||||
sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
|
||||
}
|
||||
|
||||
libssh2_htonu32(h_sig_comp, strlen(session->remote.banner));
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, session->remote.banner, strlen(session->remote.banner));
|
||||
libssh2_htonu32(h_sig_comp, strlen((char *)session->remote.banner));
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, session->remote.banner,
|
||||
strlen((char *)session->remote.banner));
|
||||
|
||||
libssh2_htonu32(h_sig_comp, session->local.kexinit_len);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, session->local.kexinit, session->local.kexinit_len);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, session->local.kexinit, session->local.kexinit_len);
|
||||
|
||||
libssh2_htonu32(h_sig_comp, session->remote.kexinit_len);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, session->remote.kexinit, session->remote.kexinit_len);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, session->remote.kexinit, session->remote.kexinit_len);
|
||||
|
||||
libssh2_htonu32(h_sig_comp, session->server_hostkey_len);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, session->server_hostkey, session->server_hostkey_len);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, session->server_hostkey, session->server_hostkey_len);
|
||||
|
||||
if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
|
||||
/* diffie-hellman-group-exchange hashes additional fields */
|
||||
@@ -223,26 +265,26 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
libssh2_htonu32(h_sig_comp, LIBSSH2_DH_GEX_MINGROUP);
|
||||
libssh2_htonu32(h_sig_comp + 4, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
libssh2_htonu32(h_sig_comp + 8, LIBSSH2_DH_GEX_MAXGROUP);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 12);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 12);
|
||||
#else
|
||||
libssh2_htonu32(h_sig_comp, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (midhash) {
|
||||
SHA1_Update(&exchange_hash, midhash, midhash_len);
|
||||
libssh2_sha1_update(exchange_hash, midhash, midhash_len);
|
||||
}
|
||||
|
||||
SHA1_Update(&exchange_hash, e_packet + 1, e_packet_len - 1);
|
||||
libssh2_sha1_update(exchange_hash, e_packet + 1, e_packet_len - 1);
|
||||
|
||||
libssh2_htonu32(h_sig_comp, f_value_len);
|
||||
SHA1_Update(&exchange_hash, h_sig_comp, 4);
|
||||
SHA1_Update(&exchange_hash, f_value, f_value_len);
|
||||
libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
|
||||
libssh2_sha1_update(exchange_hash, f_value, f_value_len);
|
||||
|
||||
SHA1_Update(&exchange_hash, k_value, k_value_len);
|
||||
libssh2_sha1_update(exchange_hash, k_value, k_value_len);
|
||||
|
||||
SHA1_Final(h_sig_comp, &exchange_hash);
|
||||
libssh2_sha1_final(exchange_hash, h_sig_comp);
|
||||
|
||||
if (session->hostkey->sig_verify(session, h_sig, h_sig_len, h_sig_comp, 20, &session->server_hostkey_abstract)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, "Unable to verify hostkey signature", 0);
|
||||
@@ -250,6 +292,9 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
|
||||
#endif
|
||||
c = SSH_MSG_NEWKEYS;
|
||||
if (libssh2_packet_write(session, &c, 1)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send NEWKEYS message", 0);
|
||||
@@ -263,7 +308,10 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
/* The first key exchange has been performed, switch to active crypt/comp/mac mode */
|
||||
session->newkeys = 1;
|
||||
session->state |= LIBSSH2_STATE_NEWKEYS;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
|
||||
#endif
|
||||
|
||||
/* This will actually end up being just packet_type(1) for this packet type anyway */
|
||||
LIBSSH2_FREE(session, tmp);
|
||||
@@ -276,46 +324,29 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
}
|
||||
memcpy(session->session_id, h_sig_comp, SHA_DIGEST_LENGTH);
|
||||
session->session_id_len = SHA_DIGEST_LENGTH;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Cleanup any existing cipher */
|
||||
if (session->local.crypt->dtor) {
|
||||
session->local.crypt->dtor(session, &session->local.crypt_abstract);
|
||||
}
|
||||
|
||||
/* Calculate IV/Secret/Key for each direction */
|
||||
if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
if (session->local.crypt_abstract) {
|
||||
LIBSSH2_FREE(session, session->local.crypt_abstract);
|
||||
session->local.crypt_abstract = NULL;
|
||||
}
|
||||
} else {
|
||||
if (session->local.crypt->dtor) {
|
||||
/* Cleanup any existing cipher */
|
||||
session->local.crypt->dtor(session, &session->local.crypt_abstract);
|
||||
}
|
||||
}
|
||||
|
||||
if (session->local.crypt->init || (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP)) {
|
||||
if (session->local.crypt->init) {
|
||||
unsigned char *iv = NULL, *secret = NULL;
|
||||
int free_iv = 0, free_secret = 0;
|
||||
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->local.crypt->iv_len, "A");
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->local.crypt->secret_len, "C");
|
||||
if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
EVP_CIPHER *(*get_cipher)(void) = (void*)session->local.crypt->crypt;
|
||||
EVP_CIPHER *cipher = get_cipher();
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
ctx = LIBSSH2_ALLOC(session, sizeof(EVP_CIPHER_CTX));
|
||||
if (!ctx) {
|
||||
if (session->local.crypt->init(session, session->local.crypt, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract)) {
|
||||
LIBSSH2_FREE(session, iv);
|
||||
LIBSSH2_FREE(session, secret);
|
||||
ret = -1;
|
||||
goto clean_exit;
|
||||
}
|
||||
EVP_CipherInit(ctx, cipher, secret, iv, 1);
|
||||
session->local.crypt_abstract = ctx;
|
||||
free_iv = 1;
|
||||
free_secret = 1;
|
||||
} else {
|
||||
session->local.crypt->init(session, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract);
|
||||
}
|
||||
|
||||
if (free_iv) {
|
||||
memset(iv, 0, session->local.crypt->iv_len);
|
||||
@@ -327,44 +358,27 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
LIBSSH2_FREE(session, secret);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server IV and Key calculated");
|
||||
#endif
|
||||
|
||||
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
if (session->remote.crypt_abstract) {
|
||||
LIBSSH2_FREE(session, session->remote.crypt_abstract);
|
||||
session->remote.crypt_abstract = NULL;
|
||||
}
|
||||
} else {
|
||||
if (session->remote.crypt->dtor) {
|
||||
/* Cleanup any existing cipher */
|
||||
session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
|
||||
}
|
||||
}
|
||||
|
||||
if (session->remote.crypt->init || (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP)) {
|
||||
if (session->remote.crypt->init) {
|
||||
unsigned char *iv = NULL, *secret = NULL;
|
||||
int free_iv = 0, free_secret = 0;
|
||||
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->remote.crypt->iv_len, "B");
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->remote.crypt->secret_len, "D");
|
||||
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
EVP_CIPHER *(*get_cipher)(void) = (void*)session->remote.crypt->crypt;
|
||||
EVP_CIPHER *cipher = get_cipher();
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
ctx = LIBSSH2_ALLOC(session, sizeof(EVP_CIPHER_CTX));
|
||||
if (!ctx) {
|
||||
if (session->remote.crypt->init(session, session->remote.crypt, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract)) {
|
||||
LIBSSH2_FREE(session, iv);
|
||||
LIBSSH2_FREE(session, secret);
|
||||
ret = -1;
|
||||
goto clean_exit;
|
||||
}
|
||||
EVP_CipherInit(ctx, cipher, secret, iv, 0);
|
||||
session->remote.crypt_abstract = ctx;
|
||||
free_iv = 1;
|
||||
free_secret = 1;
|
||||
} else {
|
||||
session->remote.crypt->init(session, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract);
|
||||
}
|
||||
|
||||
if (free_iv) {
|
||||
memset(iv, 0, session->remote.crypt->iv_len);
|
||||
@@ -376,6 +390,9 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
LIBSSH2_FREE(session, secret);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client IV and Key calculated");
|
||||
#endif
|
||||
|
||||
if (session->local.mac->dtor) {
|
||||
session->local.mac->dtor(session, &session->local.mac_abstract);
|
||||
@@ -393,6 +410,9 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
LIBSSH2_FREE(session, key);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server HMAC Key calculated");
|
||||
#endif
|
||||
|
||||
if (session->remote.mac->dtor) {
|
||||
session->remote.mac->dtor(session, &session->remote.mac_abstract);
|
||||
@@ -410,13 +430,16 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
LIBSSH2_FREE(session, key);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client HMAC Key calculated");
|
||||
#endif
|
||||
|
||||
clean_exit:
|
||||
BN_clear_free(x);
|
||||
BN_clear_free(e);
|
||||
BN_clear_free(f);
|
||||
BN_clear_free(k);
|
||||
BN_CTX_free(ctx);
|
||||
_libssh2_bn_free(x);
|
||||
_libssh2_bn_free(e);
|
||||
_libssh2_bn_free(f);
|
||||
_libssh2_bn_free(k);
|
||||
_libssh2_bn_ctx_free(ctx);
|
||||
|
||||
if (e_packet) {
|
||||
LIBSSH2_FREE(session, e_packet);
|
||||
@@ -462,18 +485,21 @@ static int libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SE
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
/* g == 2 */
|
||||
BIGNUM *p = BN_new(); /* SSH2 defined value (p_value) */
|
||||
BIGNUM *g = BN_new(); /* SSH2 defined value (2) */
|
||||
_libssh2_bn *p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */
|
||||
_libssh2_bn *g = _libssh2_bn_init(); /* SSH2 defined value (2) */
|
||||
int ret;
|
||||
|
||||
/* Initialize P and G */
|
||||
BN_set_word(g, 2);
|
||||
BN_bin2bn(p_value, 128, p);
|
||||
_libssh2_bn_set_word(g, 2);
|
||||
_libssh2_bn_from_bin(p, 128, p_value);
|
||||
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group1 Key Exchange");
|
||||
#endif
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, 128, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
|
||||
|
||||
BN_clear_free(p);
|
||||
BN_clear_free(g);
|
||||
_libssh2_bn_free(p);
|
||||
_libssh2_bn_free(g);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -518,18 +544,21 @@ static int libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_S
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
/* g == 2 */
|
||||
BIGNUM *p = BN_new(); /* SSH2 defined value (p_value) */
|
||||
BIGNUM *g = BN_new(); /* SSH2 defined value (2) */
|
||||
_libssh2_bn *p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */
|
||||
_libssh2_bn *g = _libssh2_bn_init(); /* SSH2 defined value (2) */
|
||||
int ret;
|
||||
|
||||
/* Initialize P and G */
|
||||
BN_set_word(g, 2);
|
||||
BN_bin2bn(p_value, 256, p);
|
||||
_libssh2_bn_set_word(g, 2);
|
||||
_libssh2_bn_from_bin(p, 256, p_value);
|
||||
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group14 Key Exchange");
|
||||
#endif
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, 256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
|
||||
|
||||
BN_clear_free(p);
|
||||
BN_clear_free(g);
|
||||
_libssh2_bn_free(p);
|
||||
_libssh2_bn_free(g);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -542,9 +571,9 @@ static int libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_S
|
||||
static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LIBSSH2_SESSION *session)
|
||||
{
|
||||
unsigned char request[13], *s, *data;
|
||||
unsigned long data_len, len, request_len;
|
||||
BIGNUM *p = BN_new();
|
||||
BIGNUM *g = BN_new();
|
||||
unsigned long data_len, p_len, g_len, request_len;
|
||||
_libssh2_bn *p = _libssh2_bn_init ();
|
||||
_libssh2_bn *g = _libssh2_bn_init ();
|
||||
int ret;
|
||||
|
||||
/* Ask for a P and G pair */
|
||||
@@ -554,10 +583,16 @@ static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LI
|
||||
libssh2_htonu32(request + 5, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
libssh2_htonu32(request + 9, LIBSSH2_DH_GEX_MAXGROUP);
|
||||
request_len = 13;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group-Exchange (New Method)");
|
||||
#endif
|
||||
#else
|
||||
request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD;
|
||||
libssh2_htonu32(request + 1, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
request_len = 5;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group-Exchange (Old Method)");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (libssh2_packet_write(session, request, request_len)) {
|
||||
@@ -573,19 +608,19 @@ static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LI
|
||||
}
|
||||
|
||||
s = data + 1;
|
||||
len = libssh2_ntohu32(s); s += 4;
|
||||
BN_bin2bn(s, len, p); s += len;
|
||||
p_len = libssh2_ntohu32(s); s += 4;
|
||||
_libssh2_bn_from_bin(p, p_len, s); s += p_len;
|
||||
|
||||
len = libssh2_ntohu32(s); s += 4;
|
||||
BN_bin2bn(s, len, g); s += len;
|
||||
g_len = libssh2_ntohu32(s); s += 4;
|
||||
_libssh2_bn_from_bin(g, g_len, s); s += g_len;
|
||||
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY, data + 1, data_len - 1);
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, p_len, SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY, data + 1, data_len - 1);
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
dh_gex_clean_exit:
|
||||
BN_clear_free(g);
|
||||
BN_clear_free(p);
|
||||
_libssh2_bn_free(g);
|
||||
_libssh2_bn_free(p);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -718,7 +753,7 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
||||
|
||||
*(s++) = SSH_MSG_KEXINIT;
|
||||
|
||||
RAND_bytes(s, 16);
|
||||
libssh2_random(s, 16);
|
||||
s += 16;
|
||||
|
||||
/* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */
|
||||
@@ -746,6 +781,23 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
||||
*(s++) = 0;
|
||||
*(s++) = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
{
|
||||
/* Funnily enough, they'll all "appear" to be '\0' terminated */
|
||||
char *p = data + 21; /* type(1) + cookie(16) + len(4) */
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent KEX: %s", p); p += kex_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent HOSTKEY: %s", p); p += hostkey_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_CS: %s", p); p += crypt_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_SC: %s", p); p += crypt_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_CS: %s", p); p += mac_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_SC: %s", p); p += mac_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_CS: %s", p); p += comp_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_SC: %s", p); p += comp_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_CS: %s", p); p += lang_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_SC: %s", p); p += lang_sc_len + 4;
|
||||
}
|
||||
#endif /* LIBSSH2_DEBUG_KEX */
|
||||
if (libssh2_packet_write(session, data, data_len)) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEXINIT packet to remote host", 0);
|
||||
@@ -854,7 +906,7 @@ static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((*hostkeyp)->name) {
|
||||
while (hostkeyp && (*hostkeyp)->name) {
|
||||
s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*hostkeyp)->name));
|
||||
if (s) {
|
||||
/* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
|
||||
@@ -889,9 +941,9 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
|
||||
s = session->kex_prefs;
|
||||
|
||||
while (s && *s) {
|
||||
unsigned char *p = strchr(s, ',');
|
||||
unsigned char *q, *p = strchr(s, ',');
|
||||
int method_len = (p ? (p - s) : strlen(s));
|
||||
if (libssh2_kex_agree_instr(kex, kex_len, s, method_len)) {
|
||||
if ((q = 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) {
|
||||
@@ -904,6 +956,12 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
|
||||
*/
|
||||
if (libssh2_kex_agree_hostkey(session, method->flags, hostkey, hostkey_len) == 0) {
|
||||
session->kex = method;
|
||||
if (session->burn_optimistic_kexinit && (kex == q)) {
|
||||
/* Server sent an optimistic packet,
|
||||
* and client agrees with preference
|
||||
* cancel burning the first KEX_INIT packet that comes in */
|
||||
session->burn_optimistic_kexinit = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -921,6 +979,12 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
|
||||
*/
|
||||
if (libssh2_kex_agree_hostkey(session, (*kexp)->flags, hostkey, hostkey_len) == 0) {
|
||||
session->kex = *kexp;
|
||||
if (session->burn_optimistic_kexinit && (kex == s)) {
|
||||
/* Server sent an optimistic packet,
|
||||
* and client agrees with preference
|
||||
* cancel burning the first KEX_INIT packet that comes in */
|
||||
session->burn_optimistic_kexinit = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -933,7 +997,10 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
|
||||
/* {{{ libssh2_kex_agree_crypt
|
||||
* Agree on a cipher algo
|
||||
*/
|
||||
static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *crypt, unsigned long crypt_len)
|
||||
static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session,
|
||||
libssh2_endpoint_data *endpoint,
|
||||
unsigned char *crypt,
|
||||
unsigned long crypt_len)
|
||||
{
|
||||
LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
|
||||
unsigned char *s;
|
||||
@@ -946,7 +1013,8 @@ static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_da
|
||||
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);
|
||||
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 */
|
||||
@@ -962,7 +1030,7 @@ static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_da
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((*cryptp)->name) {
|
||||
while (*cryptp && (*cryptp)->name) {
|
||||
s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name));
|
||||
if (s) {
|
||||
endpoint->crypt = *cryptp;
|
||||
@@ -1007,7 +1075,7 @@ static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((*macp)->name) {
|
||||
while (*macp && (*macp)->name) {
|
||||
s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name));
|
||||
if (s) {
|
||||
endpoint->mac = *macp;
|
||||
@@ -1052,7 +1120,7 @@ static int libssh2_kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_dat
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((*compp)->name) {
|
||||
while (*compp && (*compp)->name) {
|
||||
s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name));
|
||||
if (s) {
|
||||
endpoint->comp = *compp;
|
||||
@@ -1096,6 +1164,12 @@ static int libssh2_kex_agree_methods(LIBSSH2_SESSION *session, unsigned char *da
|
||||
lang_cs_len = libssh2_ntohu32(s); lang_cs = s + 4; s += 4 + lang_cs_len;
|
||||
lang_sc_len = libssh2_ntohu32(s); lang_sc = s + 4; s += 4 + lang_sc_len;
|
||||
|
||||
/* If the server sent an optimistic packet, assume that it guessed wrong.
|
||||
* If the guess is determined to be right (by libssh2_kex_agree_kex_hostkey)
|
||||
* This flag will be reset to zero so that it's not ignored */
|
||||
session->burn_optimistic_kexinit = *(s++);
|
||||
/* Next uint32 in packet is all zeros (reserved) */
|
||||
|
||||
if (libssh2_kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1120,6 +1194,19 @@ static int libssh2_kex_agree_methods(LIBSSH2_SESSION *session, unsigned char *da
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on KEX method: %s", session->kex->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on HOSTKEY method: %s", session->hostkey->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_CS method: %s", session->local.crypt->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_SC method: %s", session->remote.crypt->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_CS method: %s", session->local.mac->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_SC method: %s", session->remote.mac->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_CS method: %s", session->local.comp->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_SC method: %s", session->remote.comp->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_CS method:"); /* None yet */
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_SC method:"); /* None yet */
|
||||
#endif
|
||||
|
||||
/* Initialize compression layer */
|
||||
if (session->local.comp && session->local.comp->init &&
|
||||
session->local.comp->init(session, 1, &session->local.comp_abstract)) {
|
||||
@@ -1145,7 +1232,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
unsigned long data_len;
|
||||
|
||||
/* Prevent loop in packet_add() */
|
||||
session->exchanging_keys = 1;
|
||||
session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
|
||||
|
||||
if (reexchange) {
|
||||
session->kex = NULL;
|
||||
@@ -1157,7 +1244,23 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
}
|
||||
|
||||
if (!session->kex || !session->hostkey) {
|
||||
/* Preserve in case of failure */
|
||||
unsigned char *oldlocal = session->local.kexinit;
|
||||
unsigned long oldlocal_len = session->local.kexinit_len;
|
||||
|
||||
session->local.kexinit = NULL;
|
||||
if (libssh2_kexinit(session)) {
|
||||
session->local.kexinit = oldlocal;
|
||||
session->local.kexinit_len = oldlocal_len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_require(session, SSH_MSG_KEXINIT, &data, &data_len)) {
|
||||
if (session->local.kexinit) {
|
||||
LIBSSH2_FREE(session, session->local.kexinit);
|
||||
}
|
||||
session->local.kexinit = oldlocal;
|
||||
session->local.kexinit_len = oldlocal_len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1167,10 +1270,6 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
session->remote.kexinit = data;
|
||||
session->remote.kexinit_len = data_len;
|
||||
|
||||
if (libssh2_kexinit(session)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_kex_agree_methods(session, data, data_len)) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1191,7 +1290,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
session->remote.kexinit = NULL;
|
||||
}
|
||||
|
||||
session->exchanging_keys = 0;
|
||||
session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1200,7 +1299,7 @@ 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)
|
||||
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs)
|
||||
{
|
||||
char **prefvar, *s, *newprefs;
|
||||
int prefs_len = strlen(prefs);
|
||||
|
567
src/libgcrypt.c
Normal file
567
src/libgcrypt.c
Normal file
@@ -0,0 +1,567 @@
|
||||
/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <string.h>
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx **rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata,
|
||||
unsigned long coefflen)
|
||||
{
|
||||
int rc;
|
||||
(void)e1data;
|
||||
(void)e1len;
|
||||
(void)e2data;
|
||||
(void)e2len;
|
||||
|
||||
if (ddata) {
|
||||
rc = gcry_sexp_build
|
||||
(rsa, NULL,
|
||||
"(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))",
|
||||
nlen, ndata, elen, edata, dlen, ddata, plen, pdata,
|
||||
qlen, qdata, coefflen, coeffdata);
|
||||
} else {
|
||||
rc = gcry_sexp_build (rsa, NULL, "(public-key(rsa(n%b)(e%b)))",
|
||||
nlen, ndata, elen, edata);
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
*rsa = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len)
|
||||
{
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
gcry_sexp_t s_sig, s_hash;
|
||||
int rc = -1;
|
||||
|
||||
libssh2_sha1(m, m_len, hash);
|
||||
|
||||
rc = gcry_sexp_build (&s_hash, NULL,
|
||||
"(data (flags pkcs1) (hash sha1 %b))",
|
||||
SHA_DIGEST_LENGTH, hash);
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s %b)))",
|
||||
sig_len, sig);
|
||||
if (rc != 0) {
|
||||
gcry_sexp_release (s_hash);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = gcry_pk_verify (s_sig, s_hash, rsa);
|
||||
gcry_sexp_release (s_sig);
|
||||
gcry_sexp_release (s_hash);
|
||||
|
||||
return (rc == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx **dsactx,
|
||||
const unsigned char *p,
|
||||
unsigned long p_len,
|
||||
const unsigned char *q,
|
||||
unsigned long q_len,
|
||||
const unsigned char *g,
|
||||
unsigned long g_len,
|
||||
const unsigned char *y,
|
||||
unsigned long y_len,
|
||||
const unsigned char *x,
|
||||
unsigned long x_len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (x_len) {
|
||||
rc = gcry_sexp_build
|
||||
(dsactx, NULL,
|
||||
"(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))",
|
||||
p_len, p, q_len, q, g_len, g, y_len, y, x_len, x);
|
||||
} else {
|
||||
rc = gcry_sexp_build (dsactx, NULL,
|
||||
"(public-key(dsa(p%b)(q%b)(g%b)(y%b)))",
|
||||
p_len, p, q_len, q, g_len, g, y_len, y);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
*dsactx = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase)
|
||||
{
|
||||
char *data, *save_data;
|
||||
unsigned int datalen;
|
||||
int ret;
|
||||
char *n, *e, *d, *p, *q, *e1, *e2, *coeff;
|
||||
unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen;
|
||||
|
||||
(void)passphrase;
|
||||
|
||||
ret = _libssh2_pem_parse (session,
|
||||
"-----BEGIN RSA PRIVATE KEY-----",
|
||||
"-----END RSA PRIVATE KEY-----",
|
||||
fp, &data, &datalen);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
save_data = data;
|
||||
|
||||
if (_libssh2_pem_decode_sequence (&data, &datalen)) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
/* First read Version field (should be 0). */
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &n, &nlen);
|
||||
if (ret != 0 || (nlen != 1 && *n != '\0')) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &n, &nlen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &e, &elen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &d, &dlen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &p, &plen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &q, &qlen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &e1, &e1len);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &e2, &e2len);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &coeff, &coefflen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (_libssh2_rsa_new (rsa, e, elen, n, nlen, d, dlen, p, plen,
|
||||
q, qlen, e1, e1len, e2, e2len,
|
||||
coeff, coefflen)) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
fail:
|
||||
LIBSSH2_FREE (session, save_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase)
|
||||
{
|
||||
char *data, *save_data;
|
||||
unsigned int datalen;
|
||||
int ret;
|
||||
char *p, *q, *g, *y, *x;
|
||||
unsigned int plen, qlen, glen, ylen, xlen;
|
||||
|
||||
(void)passphrase;
|
||||
|
||||
ret = _libssh2_pem_parse (session,
|
||||
"-----BEGIN DSA PRIVATE KEY-----",
|
||||
"-----END DSA PRIVATE KEY-----",
|
||||
fp, &data, &datalen);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
save_data = data;
|
||||
|
||||
if (_libssh2_pem_decode_sequence (&data, &datalen)) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* First read Version field (should be 0). */
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &p, &plen);
|
||||
if (ret != 0 || (plen != 1 && *p != '\0')) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &p, &plen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &q, &qlen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &g, &glen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &y, &ylen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = _libssh2_pem_decode_integer (&data, &datalen, &x, &xlen);
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (datalen != 0) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (_libssh2_dsa_new (dsa, p, plen, q, qlen,
|
||||
g, glen, y, ylen, x, xlen)) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
fail:
|
||||
LIBSSH2_FREE (session, save_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session,
|
||||
libssh2_dsa_ctx *rsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char **signature,
|
||||
unsigned long *signature_len)
|
||||
{
|
||||
gcry_sexp_t sig_sexp;
|
||||
gcry_sexp_t data;
|
||||
int rc;
|
||||
const char *tmp;
|
||||
size_t size;
|
||||
|
||||
if (hash_len != SHA_DIGEST_LENGTH) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gcry_sexp_build (&data, NULL,
|
||||
"(data (flags pkcs1) (hash sha1 %b))",
|
||||
hash_len, hash)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = gcry_pk_sign (&sig_sexp, data, rsactx);
|
||||
|
||||
gcry_sexp_release (data);
|
||||
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = gcry_sexp_find_token(sig_sexp, "s", 0);
|
||||
if (!data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = gcry_sexp_nth_data(data, 1, &size);
|
||||
if (!tmp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tmp[0] == '\0') {
|
||||
tmp++;
|
||||
size--;
|
||||
}
|
||||
|
||||
*signature = LIBSSH2_ALLOC(session, size);
|
||||
memcpy (*signature, tmp, size);
|
||||
*signature_len = size;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char *sig)
|
||||
{
|
||||
unsigned char zhash[SHA_DIGEST_LENGTH+1];
|
||||
gcry_sexp_t sig_sexp;
|
||||
gcry_sexp_t data;
|
||||
int ret;
|
||||
const char *tmp;
|
||||
size_t size;
|
||||
|
||||
if (hash_len != SHA_DIGEST_LENGTH) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy (zhash + 1, hash, hash_len);
|
||||
zhash[0] = 0;
|
||||
|
||||
if (gcry_sexp_build (&data, NULL, "(data (value %b))",
|
||||
hash_len + 1, zhash)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = gcry_pk_sign (&sig_sexp, data, dsactx);
|
||||
|
||||
gcry_sexp_release (data);
|
||||
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Extract R. */
|
||||
|
||||
data = gcry_sexp_find_token(sig_sexp, "r", 0);
|
||||
if (!data) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = gcry_sexp_nth_data(data, 1, &size);
|
||||
if (!tmp) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tmp[0] == '\0') {
|
||||
tmp++;
|
||||
size--;
|
||||
}
|
||||
|
||||
if (size != 20) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy (sig, tmp, 20);
|
||||
|
||||
gcry_sexp_release (data);
|
||||
|
||||
/* Extract S. */
|
||||
|
||||
data = gcry_sexp_find_token(sig_sexp, "s",0);
|
||||
if (!data) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = gcry_sexp_nth_data(data, 1, &size);
|
||||
if (!tmp) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tmp[0] == '\0') {
|
||||
tmp++;
|
||||
size--;
|
||||
}
|
||||
|
||||
if (size != 20) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy (sig + 20, tmp, 20);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (sig_sexp) {
|
||||
gcry_sexp_release (sig_sexp);
|
||||
}
|
||||
if (data) {
|
||||
gcry_sexp_release (data);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len)
|
||||
{
|
||||
unsigned char hash[SHA_DIGEST_LENGTH+1];
|
||||
gcry_sexp_t s_sig, s_hash;
|
||||
int rc = -1;
|
||||
|
||||
libssh2_sha1(m, m_len, hash+1);
|
||||
hash[0] = 0;
|
||||
|
||||
if (gcry_sexp_build (&s_hash, NULL, "(data(flags raw)(value %b))",
|
||||
SHA_DIGEST_LENGTH+1, hash)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gcry_sexp_build (&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))",
|
||||
20, sig, 20, sig + 20)) {
|
||||
gcry_sexp_release (s_hash);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = gcry_pk_verify (s_sig, s_hash, dsactx);
|
||||
gcry_sexp_release (s_sig);
|
||||
gcry_sexp_release (s_hash);
|
||||
|
||||
return (rc == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
int _libssh2_cipher_init (_libssh2_cipher_ctx *h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret,
|
||||
int encrypt)
|
||||
{
|
||||
int mode = 0, ret;
|
||||
int keylen = gcry_cipher_get_algo_keylen (algo);
|
||||
|
||||
(void)encrypt;
|
||||
|
||||
if (algo != GCRY_CIPHER_ARCFOUR) {
|
||||
mode = GCRY_CIPHER_MODE_CBC;
|
||||
}
|
||||
|
||||
ret = gcry_cipher_open (h, algo, mode, 0);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = gcry_cipher_setkey (*h, secret, keylen);
|
||||
if (ret) {
|
||||
gcry_cipher_close (*h);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (algo != GCRY_CIPHER_ARCFOUR) {
|
||||
int blklen = gcry_cipher_get_algo_blklen (algo);
|
||||
ret = gcry_cipher_setiv (*h, iv, blklen);
|
||||
if (ret) {
|
||||
gcry_cipher_close (*h);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt,
|
||||
unsigned char *block)
|
||||
{
|
||||
size_t blklen = gcry_cipher_get_algo_blklen (algo);
|
||||
int ret;
|
||||
if (blklen == 1) {
|
||||
/* Hack for arcfour. */
|
||||
blklen = 8;
|
||||
}
|
||||
|
||||
if (encrypt) {
|
||||
ret = gcry_cipher_encrypt (*ctx, block, blklen,
|
||||
block, blklen);
|
||||
} else {
|
||||
ret = gcry_cipher_decrypt (*ctx, block, blklen,
|
||||
block, blklen);
|
||||
}
|
||||
return ret;
|
||||
}
|
195
src/libgcrypt.h
Normal file
195
src/libgcrypt.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#define LIBSSH2_MD5 1
|
||||
|
||||
#define LIBSSH2_HMAC_RIPEMD 1
|
||||
|
||||
#define LIBSSH2_AES 1
|
||||
#define LIBSSH2_BLOWFISH 1
|
||||
#define LIBSSH2_RC4 1
|
||||
#define LIBSSH2_CAST 1
|
||||
#define LIBSSH2_3DES 1
|
||||
|
||||
#define LIBSSH2_RSA 1
|
||||
#define LIBSSH2_DSA 1
|
||||
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
#define SHA_DIGEST_LENGTH 20
|
||||
|
||||
#define libssh2_random(buf, len) \
|
||||
(gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
|
||||
|
||||
#define libssh2_sha1_ctx gcry_md_hd_t
|
||||
#define libssh2_sha1_init(ctx) gcry_md_open (ctx, GCRY_MD_SHA1, 0);
|
||||
#define libssh2_sha1_update(ctx, data, len) gcry_md_write (ctx, data, len)
|
||||
#define libssh2_sha1_final(ctx, out) \
|
||||
memcpy (out, gcry_md_read (ctx, 0), 20), gcry_md_close (ctx)
|
||||
#define libssh2_sha1(message, len, out) \
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, out, message, len)
|
||||
|
||||
#define libssh2_md5_ctx gcry_md_hd_t
|
||||
#define libssh2_md5_init(ctx) gcry_md_open (ctx, GCRY_MD_MD5, 0);
|
||||
#define libssh2_md5_update(ctx, data, len) gcry_md_write (ctx, data, len)
|
||||
#define libssh2_md5_final(ctx, out) \
|
||||
memcpy (out, gcry_md_read (ctx, 0), 20), gcry_md_close (ctx)
|
||||
#define libssh2_md5(message, len, out) \
|
||||
gcry_md_hash_buffer (GCRY_MD_MD5, out, message, len)
|
||||
|
||||
#define libssh2_hmac_ctx gcry_md_hd_t
|
||||
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
|
||||
gcry_md_open (ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \
|
||||
gcry_md_setkey (*ctx, key, keylen)
|
||||
#define libssh2_hmac_md5_init(ctx, key, keylen) \
|
||||
gcry_md_open (ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \
|
||||
gcry_md_setkey (*ctx, key, keylen)
|
||||
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
|
||||
gcry_md_open (ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \
|
||||
gcry_md_setkey (*ctx, key, keylen)
|
||||
#define libssh2_hmac_update(ctx, data, datalen) \
|
||||
gcry_md_write (ctx, data, datalen)
|
||||
#define libssh2_hmac_final(ctx, data) \
|
||||
memcpy (data, gcry_md_read (ctx, 0), \
|
||||
gcry_md_get_algo_dlen (gcry_md_get_algo (ctx)))
|
||||
#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx);
|
||||
|
||||
#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM)
|
||||
|
||||
#define libssh2_rsa_ctx struct gcry_sexp
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx **rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata,
|
||||
unsigned long coefflen);
|
||||
int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len);
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session,
|
||||
libssh2_rsa_ctx *rsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char **signature,
|
||||
unsigned long *signature_len);
|
||||
|
||||
#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx)
|
||||
|
||||
#define libssh2_dsa_ctx struct gcry_sexp
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx **dsa,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *gdata,
|
||||
unsigned long glen,
|
||||
const unsigned char *ydata,
|
||||
unsigned long ylen,
|
||||
const unsigned char *x,
|
||||
unsigned long x_len);
|
||||
int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsa,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len);
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char *sig);
|
||||
|
||||
#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx)
|
||||
|
||||
#define _libssh2_cipher_type(name) int name
|
||||
#define _libssh2_cipher_ctx gcry_cipher_hd_t
|
||||
|
||||
#define _libssh2_cipher_aes256 GCRY_CIPHER_AES256
|
||||
#define _libssh2_cipher_aes192 GCRY_CIPHER_AES192
|
||||
#define _libssh2_cipher_aes128 GCRY_CIPHER_AES128
|
||||
#define _libssh2_cipher_blowfish GCRY_CIPHER_BLOWFISH
|
||||
#define _libssh2_cipher_arcfour GCRY_CIPHER_ARCFOUR
|
||||
#define _libssh2_cipher_cast5 GCRY_CIPHER_CAST5
|
||||
#define _libssh2_cipher_3des GCRY_CIPHER_3DES
|
||||
|
||||
int _libssh2_cipher_init (_libssh2_cipher_ctx *h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret,
|
||||
int encrypt);
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt,
|
||||
unsigned char *block);
|
||||
|
||||
#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx))
|
||||
|
||||
#define _libssh2_bn struct gcry_mpi
|
||||
#define _libssh2_bn_ctx int
|
||||
#define _libssh2_bn_ctx_new() 0
|
||||
#define _libssh2_bn_ctx_free(bnctx) 0
|
||||
#define _libssh2_bn_init() gcry_mpi_new(0)
|
||||
#define _libssh2_bn_rand(bn, bits, top, bottom) gcry_mpi_randomize (bn, bits, GCRY_WEAK_RANDOM)
|
||||
#define _libssh2_bn_mod_exp(r, a, p, m, ctx) gcry_mpi_powm (r, a, p, m)
|
||||
#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val)
|
||||
#define _libssh2_bn_from_bin(bn, len, val) gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL)
|
||||
#define _libssh2_bn_to_bin(bn, val) gcry_mpi_print (GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn)
|
||||
#define _libssh2_bn_bytes(bn) (gcry_mpi_get_nbits (bn) / 8 + ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1))
|
||||
#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
|
||||
#define _libssh2_bn_free(bn) gcry_mpi_release(bn)
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -42,13 +42,20 @@
|
||||
#include "libssh2_config.h"
|
||||
#include "libssh2.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#ifdef LIBSSH2_LIBGCRYPT
|
||||
#include "libgcrypt.h"
|
||||
#else
|
||||
#include "openssl.h"
|
||||
#endif
|
||||
|
||||
#define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract)
|
||||
#define LIBSSH2_REALLOC(session, ptr, count) session->realloc((ptr), (count), &(session)->abstract)
|
||||
#define LIBSSH2_REALLOC(session, ptr, count) ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : session->alloc((count), &(session)->abstract))
|
||||
#define LIBSSH2_FREE(session, ptr) session->free((ptr), &(session)->abstract)
|
||||
|
||||
#define LIBSSH2_IGNORE(session, data, datalen) session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract)
|
||||
@@ -112,7 +119,11 @@ struct _LIBSSH2_CHANNEL {
|
||||
|
||||
int blocking;
|
||||
|
||||
/* channel's program exit status */
|
||||
int exit_status;
|
||||
|
||||
libssh2_channel_data local, remote;
|
||||
unsigned long adjust_queue; /* Amount of bytes to be refunded to receive window (but not yet sent) */
|
||||
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
@@ -180,12 +191,12 @@ struct _LIBSSH2_SESSION {
|
||||
char *kex_prefs;
|
||||
char *hostkey_prefs;
|
||||
|
||||
int exchanging_keys;
|
||||
int newkeys;
|
||||
int authenticated;
|
||||
int state;
|
||||
int flags;
|
||||
|
||||
/* Agreed Key Exchange Method */
|
||||
LIBSSH2_KEX_METHOD *kex;
|
||||
int burn_optimistic_kexinit:1;
|
||||
|
||||
unsigned char *session_id;
|
||||
unsigned long session_id_len;
|
||||
@@ -199,12 +210,10 @@ struct _LIBSSH2_SESSION {
|
||||
*/
|
||||
unsigned char *server_hostkey;
|
||||
unsigned long server_hostkey_len;
|
||||
#ifndef OPENSSL_NO_MD5
|
||||
#if LIBSSH2_MD5
|
||||
unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH];
|
||||
#endif /* ! OPENSSL_NO_MD5 */
|
||||
#ifndef OPENSSL_NO_SHA
|
||||
#endif /* ! LIBSSH2_MD5 */
|
||||
unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH];
|
||||
#endif
|
||||
|
||||
/* (remote as source of data -- packet_read ) */
|
||||
libssh2_endpoint_data remote;
|
||||
@@ -233,10 +242,25 @@ struct _LIBSSH2_SESSION {
|
||||
int err_code;
|
||||
};
|
||||
|
||||
/* session.state bits */
|
||||
#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001
|
||||
#define LIBSSH2_STATE_NEWKEYS 0x00000002
|
||||
#define LIBSSH2_STATE_AUTHENTICATED 0x00000004
|
||||
|
||||
/* session.flag helpers */
|
||||
#ifdef MSG_NOSIGNAL
|
||||
#define LIBSSH2_SOCKET_SEND_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
|
||||
#define LIBSSH2_SOCKET_RECV_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
|
||||
#else
|
||||
/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */
|
||||
#define LIBSSH2_SOCKET_SEND_FLAGS(session) 0
|
||||
#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0
|
||||
#endif
|
||||
|
||||
/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
|
||||
|
||||
struct _LIBSSH2_KEX_METHOD {
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
/* Key exchange, populates session->* and returns 0 on success, non-0 on error */
|
||||
int (*exchange_keys)(LIBSSH2_SESSION *session);
|
||||
@@ -245,26 +269,19 @@ struct _LIBSSH2_KEX_METHOD {
|
||||
};
|
||||
|
||||
struct _LIBSSH2_HOSTKEY_METHOD {
|
||||
char *name;
|
||||
const char *name;
|
||||
unsigned long hash_len;
|
||||
|
||||
int (*init)(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract);
|
||||
int (*initPEM)(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract);
|
||||
int (*initPEM)(LIBSSH2_SESSION *session, const char *privkeyfile, unsigned const char *passphrase, void **abstract);
|
||||
int (*sig_verify)(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len, const unsigned char *m, unsigned long m_len, void **abstract);
|
||||
int (*sign)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, const unsigned char *data, unsigned long data_len, void **abstract);
|
||||
int (*signv)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, unsigned long veccount, const struct iovec datavec[], void **abstract);
|
||||
int (*encrypt)(LIBSSH2_SESSION *session, unsigned char **dst, unsigned long *dst_len, const unsigned char *src, unsigned long src_len, void **abstract);
|
||||
int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
|
||||
};
|
||||
|
||||
/* When FLAG_EVP is set, crypt contains a pointer to an EVP_CIPHER generator and init and dtor are ignored
|
||||
* Yes, I know it's a hack.
|
||||
*/
|
||||
|
||||
#define LIBSSH2_CRYPT_METHOD_FLAG_EVP 0x0001
|
||||
|
||||
struct _LIBSSH2_CRYPT_METHOD {
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
int blocksize;
|
||||
|
||||
@@ -274,13 +291,15 @@ struct _LIBSSH2_CRYPT_METHOD {
|
||||
|
||||
long flags;
|
||||
|
||||
int (*init)(LIBSSH2_SESSION *session, unsigned char *iv, int *free_iv, unsigned char *secret, int *free_secret, int encrypt, void **abstract);
|
||||
int (*init)(LIBSSH2_SESSION *session, LIBSSH2_CRYPT_METHOD *method, unsigned char *iv, int *free_iv, unsigned char *secret, int *free_secret, int encrypt, void **abstract);
|
||||
int (*crypt)(LIBSSH2_SESSION *session, unsigned char *block, void **abstract);
|
||||
int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
|
||||
|
||||
_libssh2_cipher_type(algo);
|
||||
};
|
||||
|
||||
struct _LIBSSH2_COMP_METHOD {
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
int (*init)(LIBSSH2_SESSION *session, int compress, void **abstract);
|
||||
int (*comp)(LIBSSH2_SESSION *session, int compress, unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
|
||||
@@ -289,7 +308,7 @@ struct _LIBSSH2_COMP_METHOD {
|
||||
};
|
||||
|
||||
struct _LIBSSH2_MAC_METHOD {
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
/* The length of a given MAC packet */
|
||||
int mac_len;
|
||||
@@ -303,6 +322,38 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
|
||||
};
|
||||
|
||||
#if defined(LIBSSH2_DEBUG_TRANSPORT) || defined(LIBSSH2_DEBUG_KEX) || defined(LIBSSH2_DEBUG_USERAUTH) || defined(LIBSSH2_DEBUG_CONNECTION) || defined(LIBSSH2_DEBUG_SCP) || defined(LIBSSH2_DEBUG_SFTP) || defined(LIBSSH2_DEBUG_ERRORS)
|
||||
#define LIBSSH2_DEBUG_ENABLED
|
||||
|
||||
/* Internal debugging contexts -- Used with --enable-debug-* */
|
||||
#define LIBSSH2_DBG_TRANS 1
|
||||
#define LIBSSH2_DBG_KEX 2
|
||||
#define LIBSSH2_DBG_AUTH 3
|
||||
#define LIBSSH2_DBG_CONN 4
|
||||
#define LIBSSH2_DBG_SCP 5
|
||||
#define LIBSSH2_DBG_SFTP 6
|
||||
#define LIBSSH2_DBG_ERROR 7
|
||||
#define LIBSSH2_DBG_PUBLICKEY 8
|
||||
|
||||
void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, ...);
|
||||
|
||||
#endif /* LIBSSH2_DEBUG_ENABLED */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_ERRORS
|
||||
#define libssh2_error(session, errcode, errmsg, should_free) \
|
||||
{ \
|
||||
if (session->err_msg && session->err_should_free) { \
|
||||
LIBSSH2_FREE(session, session->err_msg); \
|
||||
} \
|
||||
session->err_msg = errmsg; \
|
||||
session->err_msglen = strlen(errmsg); \
|
||||
session->err_should_free = should_free; \
|
||||
session->err_code = errcode; \
|
||||
_libssh2_debug(session, LIBSSH2_DBG_ERROR, "%d - %s", session->err_code, session->err_msg); \
|
||||
}
|
||||
|
||||
#else /* ! LIBSSH2_DEBUG_ERRORS */
|
||||
|
||||
#define libssh2_error(session, errcode, errmsg, should_free) \
|
||||
{ \
|
||||
if (session->err_msg && session->err_should_free) { \
|
||||
@@ -314,6 +365,9 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
session->err_code = errcode; \
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_DEBUG_ENABLED */
|
||||
|
||||
|
||||
#define LIBSSH2_SOCKET_UNKNOWN 1
|
||||
#define LIBSSH2_SOCKET_CONNECTED 0
|
||||
#define LIBSSH2_SOCKET_DISCONNECTED -1
|
||||
@@ -358,6 +412,9 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
#define SSH_MSG_USERAUTH_PK_OK 60
|
||||
/* "password" method */
|
||||
#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60
|
||||
/* "keyboard-interactive" method */
|
||||
#define SSH_MSG_USERAUTH_INFO_REQUEST 60
|
||||
#define SSH_MSG_USERAUTH_INFO_RESPONSE 61
|
||||
|
||||
/* Channels */
|
||||
#define SSH_MSG_GLOBAL_REQUEST 80
|
||||
@@ -387,9 +444,16 @@ 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);
|
||||
#define libssh2_packet_ask(session, packet_type, data, data_len, poll_socket) \
|
||||
libssh2_packet_ask_ex((session), (packet_type), (data), (data_len), 0, NULL, 0, (poll_socket))
|
||||
int libssh2_packet_askv_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket);
|
||||
#define libssh2_packet_askv(session, packet_types, data, data_len, poll_socket) \
|
||||
libssh2_packet_askv_ex((session), (packet_types), (data), (data_len), 0, NULL, 0, (poll_socket))
|
||||
int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
|
||||
#define libssh2_packet_require(session, packet_type, data, data_len) \
|
||||
libssh2_packet_require_ex((session), (packet_type), (data), (data_len), 0, NULL, 0)
|
||||
int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
|
||||
#define libssh2_packet_requirev(session, packet_types, data, data_len) \
|
||||
libssh2_packet_requirev_ex((session), (packet_types), (data), (data_len), 0, NULL, 0)
|
||||
int libssh2_packet_burn(LIBSSH2_SESSION *session);
|
||||
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len);
|
||||
int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange);
|
||||
unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session);
|
||||
@@ -404,4 +468,14 @@ LIBSSH2_MAC_METHOD **libssh2_mac_methods(void);
|
||||
/* Language API doesn't exist yet. Just act like we've agreed on a language */
|
||||
#define libssh2_kex_agree_lang(session, endpoint, str, str_len) 0
|
||||
|
||||
/* pem.c */
|
||||
int _libssh2_pem_parse (LIBSSH2_SESSION *session,
|
||||
const char *headerbegin,
|
||||
const char *headerend,
|
||||
FILE *fp,
|
||||
char **data, unsigned int *datalen);
|
||||
int _libssh2_pem_decode_sequence (unsigned char **data, unsigned int *datalen);
|
||||
int _libssh2_pem_decode_integer (unsigned char **data, unsigned int *datalen,
|
||||
unsigned char **i, unsigned int *ilen);
|
||||
|
||||
#endif /* LIBSSH2_H */
|
65
src/mac.c
65
src/mac.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,7 +36,6 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#ifdef LIBSSH2_MAC_NONE
|
||||
/* {{{ libssh2_mac_none_MAC
|
||||
@@ -68,6 +67,7 @@ static int libssh2_mac_method_common_init(LIBSSH2_SESSION *session, unsigned cha
|
||||
{
|
||||
*abstract = key;
|
||||
*free_key = 0;
|
||||
(void)session;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -94,19 +94,20 @@ static int libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION *session, unsigned
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
HMAC_CTX ctx;
|
||||
libssh2_hmac_ctx ctx;
|
||||
unsigned char seqno_buf[4];
|
||||
(void)session;
|
||||
|
||||
libssh2_htonu32(seqno_buf, seqno);
|
||||
|
||||
HMAC_Init(&ctx, *abstract, 20, EVP_sha1());
|
||||
HMAC_Update(&ctx, seqno_buf, 4);
|
||||
HMAC_Update(&ctx, packet, packet_len);
|
||||
libssh2_hmac_sha1_init(&ctx, *abstract, 20);
|
||||
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||
libssh2_hmac_update(ctx, packet, packet_len);
|
||||
if (addtl && addtl_len) {
|
||||
HMAC_Update(&ctx, addtl, addtl_len);
|
||||
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||
}
|
||||
HMAC_Final(&ctx, buf, NULL);
|
||||
HMAC_cleanup(&ctx);
|
||||
libssh2_hmac_final(ctx, buf);
|
||||
libssh2_hmac_cleanup(&ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -128,10 +129,10 @@ static int libssh2_mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION *session, unsign
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
char temp[SHA_DIGEST_LENGTH];
|
||||
unsigned char temp[SHA_DIGEST_LENGTH];
|
||||
|
||||
libssh2_mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len, addtl, addtl_len, abstract);
|
||||
memcpy(buf, temp, 96 / 8);
|
||||
memcpy(buf, (char *)temp, 96 / 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -153,19 +154,20 @@ static int libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION *session, unsigned c
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
HMAC_CTX ctx;
|
||||
libssh2_hmac_ctx ctx;
|
||||
unsigned char seqno_buf[4];
|
||||
(void)session;
|
||||
|
||||
libssh2_htonu32(seqno_buf, seqno);
|
||||
|
||||
HMAC_Init(&ctx, *abstract, 16, EVP_md5());
|
||||
HMAC_Update(&ctx, seqno_buf, 4);
|
||||
HMAC_Update(&ctx, packet, packet_len);
|
||||
libssh2_hmac_md5_init(&ctx, *abstract, 16);
|
||||
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||
libssh2_hmac_update(ctx, packet, packet_len);
|
||||
if (addtl && addtl_len) {
|
||||
HMAC_Update(&ctx, addtl, addtl_len);
|
||||
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||
}
|
||||
HMAC_Final(&ctx, buf, NULL);
|
||||
HMAC_cleanup(&ctx);
|
||||
libssh2_hmac_final(ctx, buf);
|
||||
libssh2_hmac_cleanup(&ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -187,10 +189,10 @@ static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigne
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
char temp[MD5_DIGEST_LENGTH];
|
||||
unsigned char temp[MD5_DIGEST_LENGTH];
|
||||
|
||||
libssh2_mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len, addtl, addtl_len, abstract);
|
||||
memcpy(buf, temp, 96 / 8);
|
||||
memcpy(buf, (char *)temp, 96 / 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -205,7 +207,7 @@ static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5_96 = {
|
||||
libssh2_mac_method_common_dtor,
|
||||
};
|
||||
|
||||
#ifndef OPENSSL_NO_RIPEMD
|
||||
#if LIBSSH2_HMAC_RIPEMD
|
||||
/* {{{ libssh2_mac_method_hmac_ripemd160_hash
|
||||
* Calculate hash using ripemd160 value
|
||||
*/
|
||||
@@ -213,19 +215,20 @@ static int libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION *session, unsi
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
HMAC_CTX ctx;
|
||||
libssh2_hmac_ctx ctx;
|
||||
unsigned char seqno_buf[4];
|
||||
(void)session;
|
||||
|
||||
libssh2_htonu32(seqno_buf, seqno);
|
||||
|
||||
HMAC_Init(&ctx, *abstract, 20, EVP_ripemd160());
|
||||
HMAC_Update(&ctx, seqno_buf, 4);
|
||||
HMAC_Update(&ctx, packet, packet_len);
|
||||
libssh2_hmac_ripemd160_init(&ctx, *abstract, 20);
|
||||
libssh2_hmac_update(ctx, seqno_buf, 4);
|
||||
libssh2_hmac_update(ctx, packet, packet_len);
|
||||
if (addtl && addtl_len) {
|
||||
HMAC_Update(&ctx, addtl, addtl_len);
|
||||
libssh2_hmac_update(ctx, addtl, addtl_len);
|
||||
}
|
||||
HMAC_Final(&ctx, buf, NULL);
|
||||
HMAC_cleanup(&ctx);
|
||||
libssh2_hmac_final(ctx, buf);
|
||||
libssh2_hmac_cleanup(&ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -248,17 +251,17 @@ static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
|
||||
libssh2_mac_method_hmac_ripemd160_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
};
|
||||
#endif /* ! OPENSSL_NO_RIPEMD */
|
||||
#endif /* LIBSSH2_HMAC_RIPEMD */
|
||||
|
||||
static LIBSSH2_MAC_METHOD *_libssh2_mac_methods[] = {
|
||||
&libssh2_mac_method_hmac_sha1,
|
||||
&libssh2_mac_method_hmac_sha1_96,
|
||||
&libssh2_mac_method_hmac_md5,
|
||||
&libssh2_mac_method_hmac_md5_96,
|
||||
#ifndef OPENSSL_NO_RIPEMD
|
||||
#ifdef LIBSSH2_HMAC_RIPEMD
|
||||
&libssh2_mac_method_hmac_ripemd160,
|
||||
&libssh2_mac_method_hmac_ripemd160_openssh_com,
|
||||
#endif /* ! OPENSSL_NO_RIPEMD */
|
||||
#endif /* LIBSSH2_HMAC_RIPEMD */
|
||||
#ifdef LIBSSH2_MAC_NONE
|
||||
&libssh2_mac_method_none,
|
||||
#endif /* LIBSSH2_MAC_NONE */
|
||||
|
50
src/misc.c
50
src/misc.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -49,7 +49,7 @@ unsigned long libssh2_ntohu32(const unsigned char *buf)
|
||||
* 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)
|
||||
libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf)
|
||||
{
|
||||
unsigned long msl, lsl;
|
||||
|
||||
@@ -73,7 +73,7 @@ void libssh2_htonu32(unsigned char *buf, unsigned long value)
|
||||
|
||||
/* {{{ libssh2_htonu64
|
||||
*/
|
||||
void libssh2_htonu64(unsigned char *buf, unsigned long long value)
|
||||
void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t value)
|
||||
{
|
||||
unsigned long msl = (value / 65536) / 65536;
|
||||
|
||||
@@ -126,19 +126,20 @@ static const short libssh2_base64_reverse_table[256] = {
|
||||
/* {{{ libssh2_base64_decode
|
||||
* Decode a base64 chunk and store it into a newly alloc'd buffer
|
||||
*/
|
||||
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, int *datalen,
|
||||
char *src, int src_len)
|
||||
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, unsigned int *datalen,
|
||||
char *src, unsigned int src_len)
|
||||
{
|
||||
unsigned char *s, *d;
|
||||
short v;
|
||||
int i = 0, len = 0;
|
||||
|
||||
*data = d = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
|
||||
*data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
|
||||
d = (unsigned char *)*data;
|
||||
if (!d) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(s = src; ((char*)s) < (src + src_len); s++) {
|
||||
for(s = (unsigned char *)src; ((char*)s) < (src + src_len); s++) {
|
||||
if ((v = libssh2_base64_reverse_table[*s]) < 0) continue;
|
||||
switch (i % 4) {
|
||||
case 0:
|
||||
@@ -169,3 +170,38 @@ LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, int
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_ENABLED
|
||||
/* {{{ _libssh2_debug
|
||||
* Internal debug logging facility
|
||||
* Just writes to stderr until a good reason comes up to support anything else
|
||||
*/
|
||||
void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, ...)
|
||||
{
|
||||
char buffer[1536];
|
||||
int len;
|
||||
va_list vargs;
|
||||
char *contexts[9] = { "Unknown",
|
||||
"Transport",
|
||||
"Key Exhange",
|
||||
"Userauth",
|
||||
"Connection",
|
||||
"scp",
|
||||
"SFTP Subsystem",
|
||||
"Failure Event",
|
||||
"Publickey Subsystem",
|
||||
};
|
||||
|
||||
if (context < 1 || context > 8) {
|
||||
context = 0;
|
||||
}
|
||||
|
||||
len = snprintf(buffer, 1535, "[libssh2] %s: ", contexts[context]);
|
||||
|
||||
va_start(vargs, format);
|
||||
len += vsnprintf(buffer + len, 1535 - len, format, vargs);
|
||||
buffer[len] = '\n';
|
||||
va_end(vargs);
|
||||
write(2, buffer, len + 1);
|
||||
}
|
||||
/* }}} */
|
||||
#endif
|
||||
|
313
src/openssl.c
Normal file
313
src/openssl.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <string.h>
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx **rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata,
|
||||
unsigned long coefflen)
|
||||
{
|
||||
*rsa = RSA_new();
|
||||
|
||||
(*rsa)->e = BN_new();
|
||||
BN_bin2bn(edata, elen, (*rsa)->e);
|
||||
|
||||
(*rsa)->n = BN_new();
|
||||
BN_bin2bn(ndata, nlen, (*rsa)->n);
|
||||
|
||||
if (ddata)
|
||||
{
|
||||
(*rsa)->d = BN_new();
|
||||
BN_bin2bn(ddata, dlen, (*rsa)->d);
|
||||
|
||||
(*rsa)->p = BN_new();
|
||||
BN_bin2bn(pdata, plen, (*rsa)->p);
|
||||
|
||||
(*rsa)->q = BN_new();
|
||||
BN_bin2bn(qdata, qlen, (*rsa)->q);
|
||||
|
||||
(*rsa)->dmp1 = BN_new();
|
||||
BN_bin2bn(e1data, e1len, (*rsa)->dmp1);
|
||||
|
||||
(*rsa)->dmq1 = BN_new();
|
||||
BN_bin2bn(e2data, e2len, (*rsa)->dmq1);
|
||||
|
||||
(*rsa)->iqmp = BN_new();
|
||||
BN_bin2bn(coeffdata, coefflen, (*rsa)->iqmp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsactx,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len)
|
||||
{
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
int ret;
|
||||
|
||||
SHA1(m, m_len, hash);
|
||||
ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
|
||||
(unsigned char *)sig, sig_len, rsactx);
|
||||
return (ret == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx **dsactx,
|
||||
const unsigned char *p,
|
||||
unsigned long p_len,
|
||||
const unsigned char *q,
|
||||
unsigned long q_len,
|
||||
const unsigned char *g,
|
||||
unsigned long g_len,
|
||||
const unsigned char *y,
|
||||
unsigned long y_len,
|
||||
const unsigned char *x,
|
||||
unsigned long x_len)
|
||||
{
|
||||
*dsactx = DSA_new();
|
||||
|
||||
(*dsactx)->p = BN_new();
|
||||
BN_bin2bn(p, p_len, (*dsactx)->p);
|
||||
|
||||
(*dsactx)->q = BN_new();
|
||||
BN_bin2bn(q, q_len, (*dsactx)->q);
|
||||
|
||||
(*dsactx)->g = BN_new();
|
||||
BN_bin2bn(g, g_len, (*dsactx)->g);
|
||||
|
||||
(*dsactx)->pub_key = BN_new();
|
||||
BN_bin2bn(y, y_len, (*dsactx)->pub_key);
|
||||
|
||||
if (x_len) {
|
||||
(*dsactx)->priv_key = BN_new();
|
||||
BN_bin2bn(x, x_len, (*dsactx)->priv_key);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len)
|
||||
{
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
DSA_SIG dsasig;
|
||||
int ret;
|
||||
|
||||
dsasig.r = BN_new();
|
||||
BN_bin2bn(sig, 20, dsasig.r);
|
||||
dsasig.s = BN_new();
|
||||
BN_bin2bn(sig + 20, 20, dsasig.s);
|
||||
|
||||
libssh2_sha1(m, m_len, hash);
|
||||
ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx);
|
||||
|
||||
return (ret == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
int _libssh2_cipher_init (_libssh2_cipher_ctx *h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret,
|
||||
int encrypt)
|
||||
{
|
||||
EVP_CIPHER_CTX_init(h);
|
||||
EVP_CipherInit(h, algo(), secret, iv, encrypt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt,
|
||||
unsigned char *block)
|
||||
{
|
||||
int blocksize = ctx->cipher->block_size;
|
||||
unsigned char buf[EVP_MAX_BLOCK_LENGTH];
|
||||
int ret;
|
||||
(void)algo;
|
||||
(void)encrypt;
|
||||
|
||||
if (blocksize == 1) {
|
||||
/* Hack for arcfour. */
|
||||
blocksize = 8;
|
||||
}
|
||||
ret = EVP_Cipher(ctx, buf, block, blocksize);
|
||||
if (ret == 1) {
|
||||
memcpy(block, buf, blocksize);
|
||||
}
|
||||
return ret == 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
/* TODO: Optionally call a passphrase callback specified by the
|
||||
* calling program
|
||||
*/
|
||||
static int
|
||||
passphrase_cb(char *buf, int size,
|
||||
int rwflag, char *passphrase)
|
||||
{
|
||||
int passphrase_len = strlen(passphrase);
|
||||
(void)rwflag;
|
||||
|
||||
if (passphrase_len > (size - 1)) {
|
||||
passphrase_len = size - 1;
|
||||
}
|
||||
memcpy(buf, passphrase, passphrase_len);
|
||||
buf[passphrase_len] = '\0';
|
||||
|
||||
return passphrase_len;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase)
|
||||
{
|
||||
(void)session;
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none are.
|
||||
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
|
||||
* Someone buy me an OpenSSL manual and I'll read up on it.
|
||||
*/
|
||||
OpenSSL_add_all_ciphers();
|
||||
}
|
||||
*rsa = PEM_read_RSAPrivateKey(fp, NULL, (void*)passphrase_cb,
|
||||
(void*)passphrase);
|
||||
if (!*rsa) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase)
|
||||
{
|
||||
(void)session;
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none are.
|
||||
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
|
||||
* Someone buy me an OpenSSL manual and I'll read up on it.
|
||||
*/
|
||||
OpenSSL_add_all_ciphers();
|
||||
}
|
||||
*dsa = PEM_read_DSAPrivateKey(fp, NULL, (void*)passphrase_cb,
|
||||
(void*)passphrase);
|
||||
if (!*dsa) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session,
|
||||
libssh2_rsa_ctx *rsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char **signature,
|
||||
unsigned long *signature_len)
|
||||
{
|
||||
int ret;
|
||||
unsigned char *sig;
|
||||
unsigned int sig_len;
|
||||
|
||||
sig_len = RSA_size(rsactx);
|
||||
sig = LIBSSH2_ALLOC(session, sig_len);
|
||||
|
||||
if (!sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx);
|
||||
|
||||
if (!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*signature = sig;
|
||||
*signature_len = sig_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char *signature)
|
||||
{
|
||||
DSA_SIG *sig;
|
||||
int r_len, s_len, rs_pad;
|
||||
(void)hash_len;
|
||||
|
||||
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
|
||||
if (!sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
r_len = BN_num_bytes(sig->r);
|
||||
s_len = BN_num_bytes(sig->s);
|
||||
rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
|
||||
if (rs_pad < 0) {
|
||||
DSA_SIG_free(sig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BN_bn2bin(sig->r, signature + rs_pad);
|
||||
BN_bn2bin(sig->s, signature + rs_pad + r_len);
|
||||
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
return 0;
|
||||
}
|
233
src/openssl.h
Normal file
233
src/openssl.h
Normal file
@@ -0,0 +1,233 @@
|
||||
/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/sha.h>
|
||||
#ifndef OPENSSL_NO_MD5
|
||||
#include <openssl/md5.h>
|
||||
#endif
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#ifdef OPENSSL_NO_RSA
|
||||
# define LIBSSH2_RSA 0
|
||||
#else
|
||||
# define LIBSSH2_RSA 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_DSA
|
||||
# define LIBSSH2_DSA 0
|
||||
#else
|
||||
# define LIBSSH2_DSA 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_MD5
|
||||
# define LIBSSH2_MD5 0
|
||||
#else
|
||||
# define LIBSSH2_MD5 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_RIPEMD
|
||||
# define LIBSSH2_HMAC_RIPEMD 0
|
||||
#else
|
||||
# define LIBSSH2_HMAC_RIPEMD 1
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
|
||||
# define LIBSSH2_AES 1
|
||||
#else
|
||||
# define LIBSSH2_AES 0
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_BLOWFISH
|
||||
# define LIBSSH2_BLOWFISH 0
|
||||
#else
|
||||
# define LIBSSH2_BLOWFISH 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_RC4
|
||||
# define LIBSSH2_RC4 0
|
||||
#else
|
||||
# define LIBSSH2_RC4 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_CAST
|
||||
# define LIBSSH2_CAST 0
|
||||
#else
|
||||
# define LIBSSH2_CAST 1
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_NO_DES
|
||||
# define LIBSSH2_3DES 0
|
||||
#else
|
||||
# define LIBSSH2_3DES 1
|
||||
#endif
|
||||
|
||||
#define libssh2_random(buf, len) \
|
||||
RAND_bytes ((buf), (len))
|
||||
|
||||
#define libssh2_sha1_ctx SHA_CTX
|
||||
#define libssh2_sha1_init(ctx) SHA1_Init(ctx)
|
||||
#define libssh2_sha1_update(ctx, data, len) SHA1_Update(&(ctx), data, len)
|
||||
#define libssh2_sha1_final(ctx, out) SHA1_Final(out, &(ctx))
|
||||
#define libssh2_sha1(message, len, out) SHA1(message, len, out)
|
||||
|
||||
#define libssh2_md5_ctx MD5_CTX
|
||||
#define libssh2_md5_init(ctx) MD5_Init(ctx)
|
||||
#define libssh2_md5_update(ctx, data, len) MD5_Update(&(ctx), data, len)
|
||||
#define libssh2_md5_final(ctx, out) MD5_Final(out, &(ctx))
|
||||
#define libssh2_md5(message, len, out) MD5(message, len, out)
|
||||
|
||||
#define libssh2_hmac_ctx HMAC_CTX
|
||||
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
|
||||
HMAC_Init(ctx, key, keylen, EVP_sha1())
|
||||
#define libssh2_hmac_md5_init(ctx, key, keylen) \
|
||||
HMAC_Init(ctx, key, keylen, EVP_md5())
|
||||
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
|
||||
HMAC_Init(ctx, key, keylen, EVP_ripemd160())
|
||||
#define libssh2_hmac_update(ctx, data, datalen) \
|
||||
HMAC_Update(&(ctx), data, datalen)
|
||||
#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL)
|
||||
#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx)
|
||||
|
||||
#define libssh2_crypto_init()
|
||||
|
||||
#define libssh2_rsa_ctx RSA
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx **rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata,
|
||||
unsigned long coefflen);
|
||||
int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len);
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session,
|
||||
libssh2_rsa_ctx *rsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char **signature,
|
||||
unsigned long *signature_len);
|
||||
|
||||
#define _libssh2_rsa_free(rsactx) RSA_free(rsactx)
|
||||
|
||||
#define libssh2_dsa_ctx DSA
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx **dsa,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *gdata,
|
||||
unsigned long glen,
|
||||
const unsigned char *ydata,
|
||||
unsigned long ylen,
|
||||
const unsigned char *x,
|
||||
unsigned long x_len);
|
||||
int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa,
|
||||
LIBSSH2_SESSION *session,
|
||||
FILE *fp,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m,
|
||||
unsigned long m_len);
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len,
|
||||
unsigned char *sig);
|
||||
|
||||
#define _libssh2_dsa_free(dsactx) DSA_free(dsactx)
|
||||
|
||||
#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
|
||||
#define _libssh2_cipher_ctx EVP_CIPHER_CTX
|
||||
|
||||
#define _libssh2_cipher_aes256 EVP_aes_256_cbc
|
||||
#define _libssh2_cipher_aes192 EVP_aes_192_cbc
|
||||
#define _libssh2_cipher_aes128 EVP_aes_128_cbc
|
||||
#define _libssh2_cipher_blowfish EVP_bf_cbc
|
||||
#define _libssh2_cipher_arcfour EVP_rc4
|
||||
#define _libssh2_cipher_cast5 EVP_cast5_cbc
|
||||
#define _libssh2_cipher_3des EVP_des_ede3_cbc
|
||||
|
||||
int _libssh2_cipher_init (_libssh2_cipher_ctx *h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret,
|
||||
int encrypt);
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt,
|
||||
unsigned char *block);
|
||||
|
||||
#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx)
|
||||
|
||||
#define _libssh2_bn BIGNUM
|
||||
#define _libssh2_bn_ctx BN_CTX
|
||||
#define _libssh2_bn_ctx_new() BN_CTX_new()
|
||||
#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx)
|
||||
#define _libssh2_bn_init() BN_new()
|
||||
#define _libssh2_bn_rand(bn, bits, top, bottom) BN_rand(bn, bits, top, bottom)
|
||||
#define _libssh2_bn_mod_exp(r, a, p, m, ctx) BN_mod_exp(r, a, p, m, ctx)
|
||||
#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val)
|
||||
#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn)
|
||||
#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val)
|
||||
#define _libssh2_bn_bytes(bn) BN_num_bytes(bn)
|
||||
#define _libssh2_bn_bits(bn) BN_num_bits(bn)
|
||||
#define _libssh2_bn_free(bn) BN_clear_free(bn)
|
497
src/packet.c
497
src/packet.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -41,9 +41,38 @@
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
/* Needed for struct iovec on some platforms */
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
# include <sys/poll.h>
|
||||
#else
|
||||
# ifdef HAVE_SELECT
|
||||
# ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
# else
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* RFC4253 section 6.1 Maximum Packet Length says:
|
||||
*
|
||||
* "All implementations MUST be able to process packets with
|
||||
* uncompressed payload length of 32768 bytes or less and
|
||||
* total packet size of 35000 bytes or less (including length,
|
||||
* padding length, payload, padding, and MAC.)."
|
||||
*/
|
||||
#define MAX_SSH_PACKET_LEN 35000
|
||||
|
||||
inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen);
|
||||
inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen);
|
||||
|
||||
/* {{{ libssh2_packet_queue_listener
|
||||
* Queue a connection request for a listener
|
||||
@@ -52,14 +81,14 @@ inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char
|
||||
{
|
||||
/* Look for a matching listener */
|
||||
unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5;
|
||||
/* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
|
||||
unsigned long packet_len = 17 + (sizeof("Forward not requested") - 1);
|
||||
unsigned char *p, packet[17 + (sizeof("Forward not requested") - 1)];
|
||||
/* packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
|
||||
LIBSSH2_LISTENER *l = session->listeners;
|
||||
char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
|
||||
unsigned long sender_channel, initial_window_size, packet_size;
|
||||
uint32_t sender_channel, initial_window_size, packet_size;
|
||||
unsigned char *host, *shost;
|
||||
unsigned long port, sport, host_len, shost_len;
|
||||
uint32_t port, sport, host_len, shost_len;
|
||||
|
||||
sender_channel = libssh2_ntohu32(s); s += 4;
|
||||
|
||||
@@ -74,6 +103,9 @@ inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char
|
||||
shost = s; s += shost_len;
|
||||
sport = libssh2_ntohu32(s); s += 4;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Remote received connection from %s:%ld to %s:%ld", shost, sport, host, port);
|
||||
#endif
|
||||
while (l) {
|
||||
if ((l->port == port) &&
|
||||
(strlen(l->host) == host_len) &&
|
||||
@@ -85,6 +117,9 @@ inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char
|
||||
(l->queue_maxsize <= l->queue_size)) {
|
||||
/* Queue is full */
|
||||
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Listener queue full, ignoring");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -117,6 +152,13 @@ inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char
|
||||
channel->local.window_size = initial_window_size;
|
||||
channel->local.packet_size = packet_size;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Connection queued: channel %lu/%lu win %lu/%lu packet %lu/%lu",
|
||||
channel->local.id, channel->remote.id,
|
||||
channel->local.window_size, channel->remote.window_size,
|
||||
channel->local.packet_size, channel->remote.packet_size);
|
||||
#endif
|
||||
|
||||
p = packet;
|
||||
*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
|
||||
libssh2_htonu32(p, channel->remote.id); p += 4;
|
||||
@@ -191,6 +233,9 @@ inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data
|
||||
shost = s; s += shost_len;
|
||||
sport = libssh2_ntohu32(s); s += 4;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection Received from %s:%ld on channel %lu", shost, sport, sender_channel);
|
||||
#endif
|
||||
if (session->x11) {
|
||||
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
|
||||
if (!channel) {
|
||||
@@ -221,6 +266,12 @@ inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data
|
||||
channel->local.window_size = initial_window_size;
|
||||
channel->local.packet_size = packet_size;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection established: channel %lu/%lu win %lu/%lu packet %lu/%lu",
|
||||
channel->local.id, channel->remote.id,
|
||||
channel->local.window_size, channel->remote.window_size,
|
||||
channel->local.packet_size, channel->remote.packet_size);
|
||||
#endif
|
||||
p = packet;
|
||||
*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
|
||||
libssh2_htonu32(p, channel->remote.id); p += 4;
|
||||
@@ -244,8 +295,11 @@ inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data
|
||||
channel->next = NULL;
|
||||
session->channels.tail = channel;
|
||||
|
||||
/* Pass control to the callback, they may turn right around and free the channel, or actually use it */
|
||||
LIBSSH2_X11_OPEN(channel, shost, sport);
|
||||
/*
|
||||
* Pass control to the callback, they may turn right around and
|
||||
* free the channel, or actually use it
|
||||
*/
|
||||
LIBSSH2_X11_OPEN(channel, (char *)shost, sport);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
@@ -277,9 +331,12 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
LIBSSH2_PACKET *packet;
|
||||
unsigned long data_head = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Packet type %d received, length=%d", (int)data[0], (int)datalen);
|
||||
#endif
|
||||
if (macstate == LIBSSH2_MAC_INVALID) {
|
||||
if (session->macerror) {
|
||||
if (LIBSSH2_MACERROR(session, data, datalen) == 0) {
|
||||
if (LIBSSH2_MACERROR(session, (char *)data, datalen) == 0) {
|
||||
/* Calling app has given the OK, Process it anyway */
|
||||
macstate = LIBSSH2_MAC_CONFIRMED;
|
||||
} else {
|
||||
@@ -307,7 +364,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
|
||||
reason = libssh2_ntohu32(data + 1);
|
||||
message_len = libssh2_ntohu32(data + 5);
|
||||
message = data + 9; /* packet_type(1) + reason(4) + message_len(4) */
|
||||
message = (char *)data + 9; /* packet_type(1) + reason(4) + message_len(4) */
|
||||
language_len = libssh2_ntohu32(data + 9 + message_len);
|
||||
/* This is where we hack on the data a little,
|
||||
* Use the MSB of language_len to to a terminating NULL (In all liklihood it is already)
|
||||
@@ -316,7 +373,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
* With the lengths passed this isn't *REALLY* necessary, but it's "kind"
|
||||
*/
|
||||
message[message_len] = '\0';
|
||||
language = data + 9 + message_len + 3;
|
||||
language = (char *)data + 9 + message_len + 3;
|
||||
if (language_len) {
|
||||
memcpy(language, language + 1, language_len);
|
||||
}
|
||||
@@ -325,6 +382,9 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
if (session->ssh_msg_disconnect) {
|
||||
LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len);
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnect(%d): %s(%s)", reason, message, language);
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
|
||||
return -1;
|
||||
@@ -335,9 +395,9 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
memcpy(data + 4, data + 5, datalen - 5);
|
||||
data[datalen] = '\0';
|
||||
if (session->ssh_msg_ignore) {
|
||||
LIBSSH2_IGNORE(session, data + 4, datalen - 5);
|
||||
LIBSSH2_IGNORE(session, (char *)data + 4, datalen - 5);
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, (char *)data);
|
||||
return 0;
|
||||
break;
|
||||
case SSH_MSG_DEBUG:
|
||||
@@ -347,7 +407,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
int message_len, language_len;
|
||||
|
||||
message_len = libssh2_ntohu32(data + 2);
|
||||
message = data + 6; /* packet_type(1) + display(1) + message_len(4) */
|
||||
message = (char *)data + 6; /* packet_type(1) + display(1) + message_len(4) */
|
||||
language_len = libssh2_ntohu32(data + 6 + message_len);
|
||||
/* This is where we hack on the data a little,
|
||||
* Use the MSB of language_len to to a terminating NULL (In all liklihood it is already)
|
||||
@@ -356,7 +416,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
* With the lengths passed this isn't *REALLY* necessary, but it's "kind"
|
||||
*/
|
||||
message[message_len] = '\0';
|
||||
language = data + 6 + message_len + 3;
|
||||
language = (char *)data + 6 + message_len + 3;
|
||||
if (language_len) {
|
||||
memcpy(language, language + 1, language_len);
|
||||
}
|
||||
@@ -365,6 +425,10 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
if (session->ssh_msg_debug) {
|
||||
LIBSSH2_DEBUG(session, always_display, message, message_len, language, language_len);
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
/* _libssh2_debug will actually truncate this for us so that it's not an inordinate about of data */
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Debug Packet: %s", message);
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
@@ -381,22 +445,27 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
{
|
||||
unsigned long stream_id = 0;
|
||||
|
||||
if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
|
||||
stream_id = libssh2_ntohu32(data + 5);
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "%d bytes received for channel %lu/%lu stream #%lu", (int)(datalen - data_head), channel->local.id, channel->remote.id, stream_id);
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
|
||||
if (channel->remote.window_size_initial) {
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Ignoring extended data and refunding %d bytes", (int)(datalen - 13));
|
||||
#endif
|
||||
/* Adjust the window based on the block we just freed */
|
||||
unsigned char adjust[9];
|
||||
libssh2_channel_receive_window_adjust(channel, datalen - 13, 0);
|
||||
|
||||
adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
|
||||
libssh2_htonu32(adjust + 1, channel->remote.id);
|
||||
libssh2_htonu32(adjust + 5, datalen - 13);
|
||||
|
||||
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 0;
|
||||
}
|
||||
|
||||
@@ -406,7 +475,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, "Packet contains more data than we offered to receive, truncating", 0);
|
||||
datalen = channel->remote.packet_size + data_head;
|
||||
}
|
||||
if (channel->remote.window_size_initial && (channel->remote.window_size <= 0)) {
|
||||
if (channel->remote.window_size <= 0) {
|
||||
/* Spec says we MAY ignore bytes sent beyond window_size */
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "The current receive window is full, data ignored", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
@@ -415,7 +484,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
/* Reset EOF status */
|
||||
channel->remote.eof = 0;
|
||||
|
||||
if (channel->remote.window_size_initial && ((datalen - data_head) > channel->remote.window_size)) {
|
||||
if ((datalen - data_head) > channel->remote.window_size) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "Remote sent more data than current window allows, truncating", 0);
|
||||
datalen = channel->remote.window_size + data_head;
|
||||
} else {
|
||||
@@ -434,12 +503,35 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "EOF received for channel %lu/%lu", channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
channel->remote.eof = 1;
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case SSH_MSG_CHANNEL_REQUEST:
|
||||
{
|
||||
if (libssh2_ntohu32(data+5) == sizeof("exit-status") - 1
|
||||
&& !memcmp("exit-status", data + 9, sizeof("exit-status") - 1)) {
|
||||
|
||||
/* we've got "exit-status" packet. Set the session value */
|
||||
LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data+1));
|
||||
|
||||
if (channel) {
|
||||
channel->exit_status = libssh2_ntohu32(data + 9 + sizeof("exit-status"));
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Exit status %lu received for channel %lu/%lu", channel->exit_status, channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH_MSG_CHANNEL_CLOSE:
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
|
||||
@@ -449,8 +541,12 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Close received for channel %lu/%lu", channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
|
||||
channel->remote.close = 1;
|
||||
channel->remote.eof = 1;
|
||||
/* TODO: Add a callback for this */
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
@@ -475,6 +571,22 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
return retval;
|
||||
}
|
||||
break;
|
||||
case SSH_MSG_CHANNEL_WINDOW_ADJUST:
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
|
||||
unsigned long bytestoadd = libssh2_ntohu32(data + 5);
|
||||
|
||||
if (channel && bytestoadd) {
|
||||
channel->local.window_size += bytestoadd;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu", channel->local.id, channel->remote.id, bytestoadd, channel->local.window_size);
|
||||
#endif
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
|
||||
@@ -497,11 +609,14 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
packet->prev = NULL;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_KEXINIT && !session->exchanging_keys) {
|
||||
if (data[0] == SSH_MSG_KEXINIT && !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) {
|
||||
/* Remote wants new keys
|
||||
* Well, it's already in the brigade,
|
||||
* let's just call back into ourselves
|
||||
*/
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
|
||||
#endif
|
||||
libssh2_kex_exchange(session, 1);
|
||||
/* If there was a key reexchange failure, let's just hope we didn't send NEWKEYS yet, otherwise remote will drop us like a rock */
|
||||
}
|
||||
@@ -513,36 +628,75 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
/* {{{ libssh2_blocking_read
|
||||
* Force a blocking read, regardless of socket settings
|
||||
*/
|
||||
static int libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, size_t count)
|
||||
static ssize_t libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, size_t count)
|
||||
{
|
||||
size_t bytes_read = 0;
|
||||
#if !defined(HAVE_POLL) && !defined(HAVE_SELECT)
|
||||
int polls = 0;
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
fcntl(session->socket_fd, F_SETFL, 0);
|
||||
#else
|
||||
{
|
||||
u_long block = FALSE;
|
||||
ioctlsocket(session->socket_fd, FIONBIO, &block);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking read: %d bytes", (int)count);
|
||||
#endif
|
||||
|
||||
while (bytes_read < count) {
|
||||
int ret;
|
||||
|
||||
ret = recv(session->socket_fd, buf + bytes_read, count - bytes_read, 0);
|
||||
ret = recv(session->socket_fd, buf + bytes_read, count - bytes_read, LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (ret < 0) {
|
||||
#ifdef WIN32
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAEWOULDBLOCK: errno = EAGAIN;
|
||||
case WSAEWOULDBLOCK: errno = EAGAIN; break;
|
||||
case WSAENOTSOCK: errno = EBADF; break;
|
||||
case WSAENOTCONN:
|
||||
case WSAENOTSOCK:
|
||||
case WSAECONNABORTED: errno = EBADF;
|
||||
case WSAEINTR: errno = EINTR;
|
||||
case WSAECONNABORTED: errno = ENOTCONN; break;
|
||||
case WSAEINTR: errno = EINTR; break;
|
||||
}
|
||||
#endif
|
||||
if (errno == EAGAIN) {
|
||||
#ifdef HAVE_POLL
|
||||
struct pollfd read_socket;
|
||||
|
||||
read_socket.fd = session->socket_fd;
|
||||
read_socket.events = POLLIN;
|
||||
|
||||
if (poll(&read_socket, 1, 30000) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
#elif defined(HAVE_SELECT)
|
||||
fd_set read_socket;
|
||||
struct timeval timeout;
|
||||
|
||||
FD_ZERO(&read_socket);
|
||||
FD_SET(session->socket_fd, &read_socket);
|
||||
|
||||
timeout.tv_sec = 30;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
if (select(session->socket_fd + 1, &read_socket, NULL, NULL, &timeout) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
|
||||
return -1;
|
||||
}
|
||||
usleep(LIBSSH2_SOCKET_POLL_UDELAY);
|
||||
#endif /* POLL/SELECT/SLEEP */
|
||||
continue;
|
||||
}
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if ((errno == EBADF) || (errno == EIO)) {
|
||||
if ((errno == EBADF) || (errno == EIO) || (errno == ENOTCONN)) {
|
||||
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
|
||||
}
|
||||
return -1;
|
||||
@@ -552,6 +706,10 @@ static int libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, s
|
||||
bytes_read += ret;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking read: %d bytes actually read", (int)bytes_read);
|
||||
#endif
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -578,48 +736,67 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
ioctlsocket(session->socket_fd, FIONBIO, &non_block);
|
||||
}
|
||||
#endif
|
||||
if (session->newkeys) {
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Checking for packet: will%s block", should_block ? "" : " not");
|
||||
#endif
|
||||
if (session->state & LIBSSH2_STATE_NEWKEYS) {
|
||||
/* 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 char block[2 * 32], *payload, *s, *p, tmp[6];
|
||||
ssize_t read_len;
|
||||
unsigned long blocksize = session->remote.crypt->blocksize;
|
||||
unsigned long packet_len, payload_len;
|
||||
int padding_len;
|
||||
int macstate;
|
||||
int free_payload = 1;
|
||||
/* Safely ignored in CUSTOM cipher mode */
|
||||
EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->remote.crypt_abstract;
|
||||
|
||||
/* 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+
|
||||
*/
|
||||
if (should_block) {
|
||||
read_len = libssh2_blocking_read(session, block, blocksize);
|
||||
if(read_len <= 0)
|
||||
return read_len;
|
||||
} else {
|
||||
read_len = recv(session->socket_fd, block, 1, 0);
|
||||
ssize_t nread;
|
||||
read_len = recv(session->socket_fd, block, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (read_len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
read_len += libssh2_blocking_read(session, block + read_len, blocksize - read_len);
|
||||
nread = libssh2_blocking_read(session, block + read_len, blocksize - read_len);
|
||||
if(nread <= 0)
|
||||
return nread;
|
||||
|
||||
read_len += nread;
|
||||
}
|
||||
if (read_len < blocksize) {
|
||||
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
|
||||
}
|
||||
|
||||
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
EVP_Cipher(ctx, block + blocksize, block, blocksize);
|
||||
memcpy(block, block + blocksize, blocksize);
|
||||
} else {
|
||||
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
packet_len = libssh2_ntohu32(block);
|
||||
|
||||
/* RFC4253 section 6.1 Maximum Packet Length says:
|
||||
*
|
||||
* "All implementations MUST be able to process packets with
|
||||
* uncompressed payload length of 32768 bytes or less and
|
||||
* total packet size of 35000 bytes or less (including length,
|
||||
* padding length, payload, padding, and MAC.)."
|
||||
*/
|
||||
if(packet_len > MAX_SSH_PACKET_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
padding_len = block[4];
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Processing packet %lu bytes long (with %lu bytes padding)", packet_len, padding_len);
|
||||
#endif
|
||||
memcpy(tmp, block, 5); /* Use this for MAC later */
|
||||
|
||||
payload_len = packet_len - 1; /* padding_len(1) */
|
||||
@@ -636,26 +813,31 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
memcpy(s, block + 5, blocksize - 5);
|
||||
s += blocksize - 5;
|
||||
|
||||
while ((s - payload) < payload_len) {
|
||||
read_len = libssh2_blocking_read(session, block, blocksize);
|
||||
if (read_len < blocksize) {
|
||||
p = s;
|
||||
while (p - payload < payload_len) {
|
||||
read_len = payload_len - (p - payload);
|
||||
if (read_len > 4096) read_len = 4096;
|
||||
|
||||
if (libssh2_blocking_read(session, p, read_len) < read_len) {
|
||||
LIBSSH2_FREE(session, payload);
|
||||
return -1;
|
||||
}
|
||||
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
EVP_Cipher(ctx, block + blocksize, block, blocksize);
|
||||
memcpy(s, block + blocksize, blocksize);
|
||||
} else {
|
||||
|
||||
p += read_len;
|
||||
|
||||
while (s < p) {
|
||||
memcpy(block, s, blocksize);
|
||||
|
||||
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, payload);
|
||||
return -1;
|
||||
}
|
||||
memcpy(s, block, blocksize);
|
||||
}
|
||||
|
||||
s += blocksize;
|
||||
}
|
||||
}
|
||||
|
||||
read_len = libssh2_blocking_read(session, block, session->remote.mac->mac_len);
|
||||
if (read_len < session->remote.mac->mac_len) {
|
||||
@@ -666,7 +848,7 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
/* Calculate MAC hash */
|
||||
session->remote.mac->hash(session, block + session->remote.mac->mac_len, session->remote.seqno, tmp, 5, payload, payload_len, &session->remote.mac_abstract);
|
||||
|
||||
macstate = (strncmp(block, block + session->remote.mac->mac_len, session->remote.mac->mac_len) == 0) ? LIBSSH2_MAC_CONFIRMED : LIBSSH2_MAC_INVALID;
|
||||
macstate = (strncmp((char *)block, (char *)block + session->remote.mac->mac_len, session->remote.mac->mac_len) == 0) ? LIBSSH2_MAC_CONFIRMED : LIBSSH2_MAC_INVALID;
|
||||
|
||||
session->remote.seqno++;
|
||||
|
||||
@@ -683,6 +865,9 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
LIBSSH2_FREE(session, payload);
|
||||
return -1;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Payload decompressed: %lu bytes(compressed) to %lu bytes(uncompressed)", data_len, payload_len);
|
||||
#endif
|
||||
if (free_payload) {
|
||||
LIBSSH2_FREE(session, payload);
|
||||
payload = data;
|
||||
@@ -710,34 +895,59 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
}
|
||||
}
|
||||
|
||||
packet_type = payload[0];
|
||||
libssh2_packet_add(session, payload, payload_len, macstate);
|
||||
|
||||
packet_type = payload[0];
|
||||
} else { /* No cipher active */
|
||||
unsigned char *payload;
|
||||
unsigned char buf[24];
|
||||
unsigned long buf_len, payload_len;
|
||||
unsigned long packet_length;
|
||||
ssize_t buf_len;
|
||||
unsigned long payload_len;
|
||||
uint32_t packet_length;
|
||||
unsigned long padding_length;
|
||||
|
||||
if (should_block) {
|
||||
buf_len = libssh2_blocking_read(session, buf, 5);
|
||||
} else {
|
||||
buf_len = recv(session->socket_fd, buf, 1, 0);
|
||||
ssize_t nread;
|
||||
buf_len = recv(session->socket_fd, buf, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (buf_len <= 0) {
|
||||
return 0;
|
||||
return buf_len;
|
||||
}
|
||||
buf_len += libssh2_blocking_read(session, buf, 5 - buf_len);
|
||||
nread = libssh2_blocking_read(session, buf, 5 - buf_len);
|
||||
if(nread <= 0)
|
||||
return -1;
|
||||
|
||||
buf_len += nread;
|
||||
}
|
||||
if (buf_len < 5) {
|
||||
/* Something bad happened */
|
||||
return -1;
|
||||
}
|
||||
packet_length = libssh2_ntohu32(buf);
|
||||
|
||||
/* RFC4253 section 6.1 Maximum Packet Length says:
|
||||
*
|
||||
* "All implementations MUST be able to process packets with
|
||||
* uncompressed payload length of 32768 bytes or less and
|
||||
* total packet size of 35000 bytes or less (including length,
|
||||
* padding length, payload, padding, and MAC.)."
|
||||
*/
|
||||
if(packet_length > MAX_SSH_PACKET_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
padding_length = buf[4];
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Processing plaintext packet %lu bytes long (with %lu bytes padding)", packet_length, padding_length);
|
||||
#endif
|
||||
|
||||
payload_len = packet_length - padding_length - 1; /* padding_length(1) */
|
||||
payload = LIBSSH2_ALLOC(session, payload_len);
|
||||
if (!payload) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of plaintext data", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_blocking_read(session, payload, payload_len) < payload_len) {
|
||||
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
|
||||
@@ -752,11 +962,11 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
break;
|
||||
}
|
||||
|
||||
packet_type = payload[0];
|
||||
|
||||
/* MACs don't exist in non-encrypted mode */
|
||||
libssh2_packet_add(session, payload, payload_len, LIBSSH2_MAC_CONFIRMED);
|
||||
session->remote.seqno++;
|
||||
|
||||
packet_type = payload[0];
|
||||
}
|
||||
return packet_type;
|
||||
}
|
||||
@@ -775,10 +985,13 @@ int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, u
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Looking for packet of type: %d", (int)packet_type);
|
||||
#endif
|
||||
while (packet) {
|
||||
if (packet->data[0] == packet_type &&
|
||||
(packet->data_len >= (match_ofs + match_len)) &&
|
||||
(!match_buf || (strncmp(packet->data + match_ofs, match_buf, match_len) == 0))) {
|
||||
(!match_buf || (memcmp(packet->data + match_ofs, match_buf, match_len) == 0))) {
|
||||
*data = packet->data;
|
||||
*data_len = packet->data_len;
|
||||
|
||||
@@ -804,9 +1017,32 @@ int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, u
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_askv
|
||||
* Scan for any of a list of packet types in the brigade, optionally poll the socket for a packet first
|
||||
*/
|
||||
int libssh2_packet_askv_ex(LIBSSH2_SESSION *session,
|
||||
unsigned char *packet_types,
|
||||
unsigned char **data,
|
||||
unsigned long *data_len,
|
||||
unsigned long match_ofs,
|
||||
const unsigned char *match_buf,
|
||||
unsigned long match_len, int poll_socket)
|
||||
{
|
||||
int i, packet_types_len = strlen((char *)packet_types);
|
||||
|
||||
for(i = 0; i < packet_types_len; i++) {
|
||||
if (0 == libssh2_packet_ask_ex(session, packet_types[i], data, data_len, match_ofs, match_buf, match_len, i ? 0 : poll_socket)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_require
|
||||
* Loops libssh2_packet_read() until the packet requested is available
|
||||
* SSH_DISCONNECT will cause a bailout though
|
||||
* SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
|
||||
*/
|
||||
int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len,
|
||||
unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len)
|
||||
@@ -816,6 +1052,9 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking until packet of type %d becomes available", (int)packet_type);
|
||||
#endif
|
||||
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
int ret = libssh2_packet_read(session, 1);
|
||||
if (ret < 0) {
|
||||
@@ -834,6 +1073,81 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_burn
|
||||
* Loops libssh2_packet_read() until any packet is available and promptly discards it
|
||||
* Used during KEX exchange to discard badly guessed KEX_INIT packets
|
||||
*/
|
||||
int libssh2_packet_burn(LIBSSH2_SESSION *session)
|
||||
{
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
unsigned char all_packets[255];
|
||||
int i;
|
||||
for(i = 1; i < 256; i++) all_packets[i - 1] = i;
|
||||
|
||||
if (libssh2_packet_askv_ex(session, all_packets, &data, &data_len, 0, NULL, 0, 0) == 0) {
|
||||
i = data[0];
|
||||
/* A packet was available in the packet brigade, burn it */
|
||||
LIBSSH2_FREE(session, data);
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking until packet becomes available to burn");
|
||||
#endif
|
||||
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
int ret = libssh2_packet_read(session, 1);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) continue;
|
||||
|
||||
/* Be lazy, let packet_ask pull it out of the brigade */
|
||||
if (0 == libssh2_packet_ask_ex(session, ret, &data, &data_len, 0, NULL, 0, 0)) {
|
||||
/* Smoke 'em if you got 'em */
|
||||
LIBSSH2_FREE(session, data);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only reached if the socket died */
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_requirev
|
||||
* Loops libssh2_packet_read() until one of a list of packet types requested is available
|
||||
* SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
|
||||
* packet_types is a null terminated list of packet_type numbers
|
||||
*/
|
||||
int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len,
|
||||
unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len)
|
||||
{
|
||||
if (libssh2_packet_askv_ex(session, packet_types, data, data_len, match_ofs, match_buf, match_len, 0) == 0) {
|
||||
/* One of the packets listed was available in the packet brigade */
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
int ret = libssh2_packet_read(session, 1);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strchr((char *)packet_types, ret)) {
|
||||
/* Be lazy, let packet_ask pull it out of the brigade */
|
||||
return libssh2_packet_askv_ex(session, packet_types, data, data_len, match_ofs, match_buf, match_len, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Only reached if the socket died */
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_write
|
||||
* Send a packet, encrypting it and adding a MAC code if necessary
|
||||
* Returns 0 on success, non-zero on failure
|
||||
@@ -841,19 +1155,31 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
|
||||
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len)
|
||||
{
|
||||
unsigned long packet_length = data_len + 1;
|
||||
unsigned long block_size = (session->newkeys) ? session->local.crypt->blocksize : 8;
|
||||
unsigned long block_size = (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->blocksize : 8;
|
||||
/* At this point packet_length doesn't include the packet_len field itself */
|
||||
unsigned long padding_length;
|
||||
int free_data = 0;
|
||||
unsigned char buf[246]; /* 6 byte header plus max padding size(240) */
|
||||
int i;
|
||||
|
||||
if (session->newkeys &&
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
{
|
||||
/* Show a hint of what's being sent */
|
||||
char excerpt[32];
|
||||
int ex_len = 0, db_ofs = 0;
|
||||
|
||||
for (; ex_len < 24 && db_ofs < data_len; ex_len += 3, db_ofs++) snprintf(excerpt + ex_len, 4, "%02X ", data[db_ofs]);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending packet type %d, length=%lu, %s", (int)data[0], data_len, excerpt);
|
||||
}
|
||||
#endif
|
||||
if ((session->state & LIBSSH2_STATE_NEWKEYS) &&
|
||||
strcmp(session->local.comp->name, "none")) {
|
||||
|
||||
if (session->local.comp->comp(session, 1, &data, &data_len, LIBSSH2_PACKET_MAXCOMP, &free_data, data, data_len, &session->local.comp_abstract)) {
|
||||
return -1;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Compressed payload to %lu bytes", data_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
@@ -875,19 +1201,14 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
|
||||
packet_length += padding_length;
|
||||
libssh2_htonu32(buf, packet_length);
|
||||
buf[4] = padding_length;
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending packet with total length %lu (%lu bytes padding)", packet_length, padding_length);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < padding_length; i++) {
|
||||
/* Make random */
|
||||
buf[5 + i] = '\0';
|
||||
}
|
||||
|
||||
if (session->newkeys) {
|
||||
if (session->state & LIBSSH2_STATE_NEWKEYS) {
|
||||
/* Encryption is in effect */
|
||||
unsigned char *encbuf, *s;
|
||||
int ret;
|
||||
|
||||
/* Safely ignored in CUSTOM cipher mode */
|
||||
EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->local.crypt_abstract;
|
||||
int ret, size, written = 0;
|
||||
|
||||
/* include packet_length(4) itself and room for the hash at the end */
|
||||
encbuf = LIBSSH2_ALLOC(session, 4 + packet_length + session->local.mac->mac_len);
|
||||
@@ -902,7 +1223,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
|
||||
/* Copy packet to encoding buffer */
|
||||
memcpy(encbuf, buf, 5);
|
||||
memcpy(encbuf + 5, data, data_len);
|
||||
RAND_bytes(encbuf + 5 + data_len, padding_length);
|
||||
libssh2_random(encbuf + 5 + data_len, padding_length);
|
||||
if (free_data) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
@@ -912,18 +1233,22 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
|
||||
|
||||
/* Encrypt data */
|
||||
for(s = encbuf; (s - encbuf) < (4 + packet_length) ; s += session->local.crypt->blocksize) {
|
||||
if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
EVP_Cipher(ctx, buf, s, session->local.crypt->blocksize);
|
||||
memcpy(s, buf, session->local.crypt->blocksize);
|
||||
} else {
|
||||
session->local.crypt->crypt(session, s, &session->local.crypt_abstract);
|
||||
}
|
||||
}
|
||||
|
||||
session->local.seqno++;
|
||||
|
||||
/* Send It */
|
||||
ret = ((4 + packet_length + session->local.mac->mac_len) == send(session->socket_fd, encbuf, 4 + packet_length + session->local.mac->mac_len, 0)) ? 0 : -1;
|
||||
size = 4 + packet_length + session->local.mac->mac_len;
|
||||
written = 0;
|
||||
|
||||
while(written < size) {
|
||||
ret = send(session->socket_fd, encbuf + written, size - written, LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
if(ret > 0) written += ret;
|
||||
else break;
|
||||
}
|
||||
|
||||
ret = written == size ? 0 : -1;
|
||||
|
||||
/* Cleanup environment */
|
||||
LIBSSH2_FREE(session, encbuf);
|
||||
|
229
src/pem.c
Normal file
229
src/pem.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/* Copyright (C) 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
static int readline (char *line, int line_size, FILE *fp)
|
||||
{
|
||||
if (!fgets(line, line_size, fp))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (*line && line[strlen(line) - 1] == '\r')
|
||||
{
|
||||
line[strlen(line) - 1] = '\0';
|
||||
}
|
||||
if (*line && line[strlen(line) - 1] == '\n')
|
||||
{
|
||||
line[strlen(line) - 1] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define LINE_SIZE 128
|
||||
|
||||
int _libssh2_pem_parse (LIBSSH2_SESSION *session,
|
||||
const char *headerbegin,
|
||||
const char *headerend,
|
||||
FILE *fp,
|
||||
char **data, unsigned int *datalen)
|
||||
{
|
||||
char line[LINE_SIZE];
|
||||
char *b64data = NULL;
|
||||
unsigned int b64datalen = 0;
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
if (readline(line, LINE_SIZE, fp))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
while (strcmp (line, headerbegin) != 0);
|
||||
|
||||
*line = '\0';
|
||||
|
||||
do
|
||||
{
|
||||
if (*line)
|
||||
{
|
||||
char *tmp;
|
||||
size_t linelen;
|
||||
|
||||
linelen = strlen (line);
|
||||
tmp = LIBSSH2_REALLOC (session, b64data,
|
||||
b64datalen + linelen);
|
||||
if (!tmp)
|
||||
{
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
memcpy (tmp + b64datalen, line, linelen);
|
||||
b64data = tmp;
|
||||
b64datalen += linelen;
|
||||
}
|
||||
|
||||
if (readline(line, LINE_SIZE, fp))
|
||||
{
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
} while (strcmp (line, headerend) != 0);
|
||||
|
||||
if (libssh2_base64_decode(session, data, datalen,
|
||||
b64data, b64datalen))
|
||||
{
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (b64data) {
|
||||
LIBSSH2_FREE (session, b64data);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_asn1_length (const unsigned char *data,
|
||||
unsigned int datalen,
|
||||
unsigned int *len)
|
||||
{
|
||||
unsigned int lenlen;
|
||||
int nextpos;
|
||||
|
||||
if (datalen < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
*len = data[0];
|
||||
|
||||
if (*len >= 0x80)
|
||||
{
|
||||
lenlen = *len & 0x7F;
|
||||
*len = data[1];
|
||||
if (1 + lenlen > datalen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (lenlen > 1)
|
||||
{
|
||||
*len <<= 8;
|
||||
*len |= data[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lenlen = 0;
|
||||
}
|
||||
|
||||
nextpos = 1 + lenlen;
|
||||
if (lenlen > 2 || 1 + lenlen + *len > datalen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nextpos;
|
||||
}
|
||||
|
||||
int _libssh2_pem_decode_sequence (unsigned char **data, unsigned int *datalen)
|
||||
{
|
||||
unsigned int len;
|
||||
int lenlen;
|
||||
|
||||
if (*datalen < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*data)[0] != '\x30')
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*data)++;
|
||||
(*datalen)--;
|
||||
|
||||
lenlen = read_asn1_length (*data, *datalen, &len);
|
||||
if (lenlen < 0 || lenlen + len != *datalen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*data += lenlen;
|
||||
*datalen -= lenlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _libssh2_pem_decode_integer (unsigned char **data, unsigned int *datalen,
|
||||
unsigned char **i, unsigned int *ilen)
|
||||
{
|
||||
unsigned int len;
|
||||
int lenlen;
|
||||
|
||||
if (*datalen < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*data)[0] != '\x02')
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*data)++;
|
||||
(*datalen)--;
|
||||
|
||||
lenlen = read_asn1_length (*data, *datalen, &len);
|
||||
if (lenlen < 0 || lenlen + len > *datalen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*data += lenlen;
|
||||
*datalen -= lenlen;
|
||||
|
||||
*i = *data;
|
||||
*ilen = len;
|
||||
|
||||
*data += len;
|
||||
*datalen -= len;
|
||||
|
||||
return 0;
|
||||
}
|
730
src/publickey.c
Normal file
730
src/publickey.c
Normal file
@@ -0,0 +1,730 @@
|
||||
/* Copyright (c) 2004-2006, 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.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include "libssh2_publickey.h"
|
||||
|
||||
struct _LIBSSH2_PUBLICKEY {
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
unsigned long version;
|
||||
};
|
||||
|
||||
#define LIBSSH2_PUBLICKEY_VERSION 2
|
||||
|
||||
/* Numericised response codes -- Not IETF standard, just a local representation */
|
||||
#define LIBSSH2_PUBLICKEY_RESPONSE_STATUS 0
|
||||
#define LIBSSH2_PUBLICKEY_RESPONSE_VERSION 1
|
||||
#define LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY 2
|
||||
|
||||
typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST {
|
||||
int code;
|
||||
char *name;
|
||||
int name_len;
|
||||
} LIBSSH2_PUBLICKEY_CODE_LIST;
|
||||
|
||||
static LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_response_codes[] = {
|
||||
{ LIBSSH2_PUBLICKEY_RESPONSE_STATUS, "status", sizeof("status") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_RESPONSE_VERSION, "version", sizeof("version") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY, "publickey", sizeof("publickey") - 1 },
|
||||
{ 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/* PUBLICKEY status codes -- IETF defined */
|
||||
#define LIBSSH2_PUBLICKEY_SUCCESS 0
|
||||
#define LIBSSH2_PUBLICKEY_ACCESS_DENIED 1
|
||||
#define LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED 2
|
||||
#define LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED 3
|
||||
#define LIBSSH2_PUBLICKEY_KEY_NOT_FOUND 4
|
||||
#define LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED 5
|
||||
#define LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT 6
|
||||
#define LIBSSH2_PUBLICKEY_GENERAL_FAILURE 7
|
||||
#define LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED 8
|
||||
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_CODE_MAX 8
|
||||
|
||||
static LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_status_codes[] = {
|
||||
{ LIBSSH2_PUBLICKEY_SUCCESS, "success", sizeof("success") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_ACCESS_DENIED, "access denied", sizeof("access denied") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED, "storage exceeded", sizeof("storage exceeded") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED, "version not supported", sizeof("version not supported") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_KEY_NOT_FOUND, "key not found", sizeof("key not found") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED, "key not supported", sizeof("key not supported") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT, "key already present", sizeof("key already present") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_GENERAL_FAILURE, "general failure", sizeof("general failure") - 1 },
|
||||
{ LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED, "request not supported", sizeof("request not supported") - 1 },
|
||||
{ 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/* {{{ libssh2_publickey_status_error
|
||||
* Format an error message from a status code
|
||||
*/
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_START "Publickey Subsystem Error: \""
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_MID "\" Server Resports: \""
|
||||
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_END "\""
|
||||
static void libssh2_publickey_status_error(LIBSSH2_PUBLICKEY *pkey, LIBSSH2_SESSION *session, int status, unsigned char *message, int message_len)
|
||||
{
|
||||
char *status_text;
|
||||
int status_text_len;
|
||||
char *m, *s;
|
||||
int m_len;
|
||||
|
||||
/* GENERAL_FAILURE got remapped between version 1 and 2 */
|
||||
if (status == 6 && pkey && pkey->version == 1) {
|
||||
status = 7;
|
||||
}
|
||||
|
||||
if (status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) {
|
||||
status_text = "unknown";
|
||||
status_text_len = sizeof("unknown") - 1;
|
||||
} else {
|
||||
status_text = libssh2_publickey_status_codes[status].name;
|
||||
status_text_len = libssh2_publickey_status_codes[status].name_len;
|
||||
}
|
||||
|
||||
m_len = (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1) + status_text_len +
|
||||
(sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1) + message_len +
|
||||
(sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
|
||||
m = LIBSSH2_ALLOC(session, m_len + 1);
|
||||
if (!m) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for status message", 0);
|
||||
return;
|
||||
}
|
||||
s = m;
|
||||
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_START, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1);
|
||||
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1;
|
||||
memcpy(s, status_text, status_text_len); s += status_text_len;
|
||||
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_MID, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1);
|
||||
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1;
|
||||
memcpy(s, message, message_len); s += message_len;
|
||||
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_END, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
|
||||
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, m, 1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_packet_receive
|
||||
* Read a packet from the subsystem
|
||||
*/
|
||||
static int libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY *pkey, unsigned char **data, unsigned long *data_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char buffer[4];
|
||||
unsigned long packet_len;
|
||||
unsigned char *packet;
|
||||
|
||||
if (libssh2_channel_read(channel, (char *)buffer, 4) != 4) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid response from publickey subsystem", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
packet_len = libssh2_ntohu32(buffer);
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate publickey response buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_channel_read(channel, (char *)packet, packet_len) != packet_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for publickey subsystem response packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*data = packet;
|
||||
*data_len = packet_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_response_id
|
||||
* Translate a string response name to a numeric code
|
||||
* Data will be incremented by 4 + response_len on success only
|
||||
*/
|
||||
static int libssh2_publickey_response_id(unsigned char **pdata, int data_len)
|
||||
{
|
||||
unsigned long response_len;
|
||||
unsigned char *data = *pdata;
|
||||
LIBSSH2_PUBLICKEY_CODE_LIST *codes = libssh2_publickey_response_codes;
|
||||
|
||||
if (data_len < 4) {
|
||||
/* Malformed response */
|
||||
return -1;
|
||||
}
|
||||
response_len = libssh2_ntohu32(data); data += 4; data_len -= 4;
|
||||
if (data_len < response_len) {
|
||||
/* Malformed response */
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (codes->name) {
|
||||
if (codes->name_len == response_len &&
|
||||
strncmp(codes->name, (char *)data, response_len) == 0) {
|
||||
*pdata = data + response_len;
|
||||
return codes->code;
|
||||
}
|
||||
codes++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_response_success
|
||||
* Generic helper routine to wait for success response and nothing else
|
||||
*/
|
||||
static int libssh2_publickey_response_success(LIBSSH2_PUBLICKEY *pkey)
|
||||
{
|
||||
LIBSSH2_SESSION *session = pkey->channel->session;
|
||||
unsigned char *data, *s;
|
||||
unsigned long data_len;
|
||||
int response;
|
||||
|
||||
while (1) {
|
||||
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = data;
|
||||
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (response) {
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
|
||||
/* Error, or processing complete */
|
||||
{
|
||||
unsigned long status, descr_len, lang_len;
|
||||
unsigned char *descr, *lang;
|
||||
|
||||
status = libssh2_ntohu32(s); s += 4;
|
||||
descr_len = libssh2_ntohu32(s); s += 4;
|
||||
descr = s; s += descr_len;
|
||||
lang_len = libssh2_ntohu32(s); s += 4;
|
||||
lang = s; s += lang_len;
|
||||
|
||||
if (s > data + data_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
default:
|
||||
/* Unknown/Unexpected */
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
/* never reached, but include `return` to silence compiler warnings */
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* *****************
|
||||
* Publickey API *
|
||||
***************** */
|
||||
|
||||
/* {{{ libssh2_publickey_init
|
||||
* Startup the publickey subsystem
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session)
|
||||
{
|
||||
LIBSSH2_PUBLICKEY *pkey = NULL;
|
||||
LIBSSH2_CHANNEL *channel = NULL;
|
||||
unsigned char buffer[19];
|
||||
/* packet_len(4) +
|
||||
version_len(4) +
|
||||
"version"(7) +
|
||||
version_num(4) */
|
||||
unsigned char *s, *data = NULL;
|
||||
unsigned long data_len;
|
||||
int response;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Initializing publickey subsystem");
|
||||
#endif
|
||||
|
||||
channel = libssh2_channel_open_session(session);
|
||||
if (!channel) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
if (libssh2_channel_subsystem(channel, "publickey")) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
|
||||
|
||||
pkey = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
|
||||
if (!pkey) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new publickey structure", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
pkey->channel = channel;
|
||||
pkey->version = 0;
|
||||
|
||||
s = buffer;
|
||||
libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("version") - 1); s += 4;
|
||||
memcpy(s, "version", sizeof("version") - 1); s += sizeof("version") - 1;
|
||||
libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION); s += 4;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey version packet advertising version %d support", (int)LIBSSH2_PUBLICKEY_VERSION);
|
||||
#endif
|
||||
if ((s - buffer) != libssh2_channel_write(channel, (char*)buffer, (s - buffer))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey version packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
s = data;
|
||||
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
switch (response) {
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
|
||||
/* Error */
|
||||
{
|
||||
unsigned long status, descr_len, lang_len;
|
||||
unsigned char *descr, *lang;
|
||||
|
||||
status = libssh2_ntohu32(s); s += 4;
|
||||
descr_len = libssh2_ntohu32(s); s += 4;
|
||||
descr = s; s += descr_len;
|
||||
lang_len = libssh2_ntohu32(s); s += 4;
|
||||
lang = s; s += lang_len;
|
||||
|
||||
if (s > data + data_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
libssh2_publickey_status_error(NULL, session, status, descr, descr_len);
|
||||
goto err_exit;
|
||||
}
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
|
||||
/* What we want */
|
||||
pkey->version = libssh2_ntohu32(s);
|
||||
if (pkey->version > LIBSSH2_PUBLICKEY_VERSION) {
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Truncating remote publickey version from %lu", pkey->version);
|
||||
#endif
|
||||
pkey->version = LIBSSH2_PUBLICKEY_VERSION;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Enabling publickey subsystem version %lu", pkey->version);
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
return pkey;
|
||||
default:
|
||||
/* Unknown/Unexpected */
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached except by direct goto */
|
||||
err_exit:
|
||||
if (channel) {
|
||||
libssh2_channel_close(channel);
|
||||
}
|
||||
if (pkey) {
|
||||
LIBSSH2_FREE(session, pkey);
|
||||
}
|
||||
if (data) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_add_ex
|
||||
* Add a new public key entry
|
||||
*/
|
||||
LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len, char overwrite,
|
||||
unsigned long num_attrs, libssh2_publickey_attribute attrs[])
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *packet = NULL, *s;
|
||||
unsigned long i, packet_len = 19 + name_len + blob_len;
|
||||
unsigned char *comment = NULL;
|
||||
unsigned long comment_len = 0;
|
||||
/* packet_len(4) +
|
||||
add_len(4) +
|
||||
"add"(3) +
|
||||
name_len(4) +
|
||||
{name}
|
||||
blob_len(4) +
|
||||
{blob} */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s pubickey", name);
|
||||
#endif
|
||||
|
||||
if (pkey->version == 1) {
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
/* Search for a comment attribute */
|
||||
if (attrs[i].name_len == (sizeof("comment") - 1) &&
|
||||
strncmp(attrs[i].name, "comment", sizeof("comment") - 1) == 0) {
|
||||
comment = (unsigned char *)attrs[i].value;
|
||||
comment_len = attrs[i].value_len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
packet_len += 4 + comment_len;
|
||||
} else {
|
||||
packet_len += 5; /* overwrite(1) + attribute_count(4) */
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
|
||||
/* name_len(4) + value_len(4) + mandatory(1) */
|
||||
}
|
||||
}
|
||||
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"add\" packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = packet;
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("add") - 1); s += 4;
|
||||
memcpy(s, "add", sizeof("add") - 1); s += sizeof("add") - 1;
|
||||
if (pkey->version == 1) {
|
||||
libssh2_htonu32(s, comment_len); s += 4;
|
||||
if (comment) {
|
||||
memcpy(s, comment, comment_len); s += comment_len;
|
||||
}
|
||||
|
||||
libssh2_htonu32(s, name_len); s += 4;
|
||||
memcpy(s, name, name_len); s += name_len;
|
||||
libssh2_htonu32(s, blob_len); s += 4;
|
||||
memcpy(s, blob, blob_len); s += blob_len;
|
||||
} else {
|
||||
/* Version == 2 */
|
||||
|
||||
libssh2_htonu32(s, name_len); s += 4;
|
||||
memcpy(s, name, name_len); s += name_len;
|
||||
libssh2_htonu32(s, blob_len); s += 4;
|
||||
memcpy(s, blob, blob_len); s += blob_len;
|
||||
*(s++) = overwrite ? 0xFF : 0;
|
||||
libssh2_htonu32(s, num_attrs); s += 4;
|
||||
for(i = 0; i < num_attrs; i++) {
|
||||
libssh2_htonu32(s, attrs[i].name_len); s += 4;
|
||||
memcpy(s, attrs[i].name, attrs[i].name_len); s += attrs[i].name_len;
|
||||
libssh2_htonu32(s, attrs[i].value_len); s += 4;
|
||||
memcpy(s, attrs[i].value, attrs[i].value_len); s += attrs[i].value_len;
|
||||
*(s++) = attrs[i].mandatory ? 0xFF : 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld", name, blob_len, num_attrs);
|
||||
#endif
|
||||
if ((s - packet) != libssh2_channel_write(channel, (char *)packet, (s - packet))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey add packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
packet = NULL;
|
||||
|
||||
return libssh2_publickey_response_success(pkey);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_remove_ex
|
||||
* Remove an existing publickey so that authentication can no longer be performed using it
|
||||
*/
|
||||
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
|
||||
const unsigned char *blob, unsigned long blob_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *s, *packet = NULL;
|
||||
unsigned long packet_len = 22 + name_len + blob_len;
|
||||
/* packet_len(4) +
|
||||
remove_len(4) +
|
||||
"remove"(6) +
|
||||
name_len(4) +
|
||||
{name}
|
||||
blob_len(4) +
|
||||
{blob} */
|
||||
|
||||
packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"remove\" packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = packet;
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("remove") - 1); s += 4;
|
||||
memcpy(s, "remove", sizeof("remove") - 1); s += sizeof("remove") - 1;
|
||||
libssh2_htonu32(s, name_len); s += 4;
|
||||
memcpy(s, name, name_len); s += name_len;
|
||||
libssh2_htonu32(s, blob_len); s += 4;
|
||||
memcpy(s, blob, blob_len); s += blob_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"remove\" packet: type=%s blob_len=%ld", name, blob_len);
|
||||
#endif
|
||||
if ((s - packet) != libssh2_channel_write(channel, (char *)packet, (s - packet))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey remove packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
packet = NULL;
|
||||
|
||||
return libssh2_publickey_response_success(pkey);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_list_fetch
|
||||
* Fetch a list of supported public key from a server
|
||||
*/
|
||||
LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = pkey->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
libssh2_publickey_list *list = NULL;
|
||||
unsigned char *s, buffer[12], *data = NULL;
|
||||
unsigned long buffer_len = 12, keys = 0, max_keys = 0, data_len, i;
|
||||
/* packet_len(4) +
|
||||
list_len(4) +
|
||||
"list"(4) */
|
||||
int response;
|
||||
|
||||
s = buffer;
|
||||
libssh2_htonu32(s, buffer_len - 4); s += 4;
|
||||
libssh2_htonu32(s, sizeof("list") - 1); s += 4;
|
||||
memcpy(s, "list", sizeof("list") - 1); s += sizeof("list") - 1;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_PUBLICKEY
|
||||
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"list\" packet");
|
||||
#endif
|
||||
if ((s - buffer) != libssh2_channel_write(channel, (char *)buffer, (s - buffer))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
s = data;
|
||||
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
switch (response) {
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
|
||||
/* Error, or processing complete */
|
||||
{
|
||||
unsigned long status, descr_len, lang_len;
|
||||
unsigned char *descr, *lang;
|
||||
|
||||
status = libssh2_ntohu32(s); s += 4;
|
||||
descr_len = libssh2_ntohu32(s); s += 4;
|
||||
descr = s; s += descr_len;
|
||||
lang_len = libssh2_ntohu32(s); s += 4;
|
||||
lang = s; s += lang_len;
|
||||
|
||||
if (s > data + data_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
*pkey_list = list;
|
||||
*num_keys = keys;
|
||||
return 0;
|
||||
}
|
||||
|
||||
libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
|
||||
goto err_exit;
|
||||
}
|
||||
case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
|
||||
/* What we want */
|
||||
if (keys >= max_keys) {
|
||||
/* Grow the key list if necessary */
|
||||
max_keys += 8;
|
||||
list = LIBSSH2_REALLOC(session, list, (max_keys + 1) * sizeof(libssh2_publickey_list));
|
||||
if (!list) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey list", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
if (pkey->version == 1) {
|
||||
unsigned long comment_len;
|
||||
|
||||
comment_len = libssh2_ntohu32(s); s += 4;
|
||||
if (comment_len) {
|
||||
list[keys].num_attrs = 1;
|
||||
list[keys].attrs = LIBSSH2_ALLOC(session, sizeof(libssh2_publickey_attribute));
|
||||
if (!list[keys].attrs) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
list[keys].attrs[0].name = "comment";
|
||||
list[keys].attrs[0].name_len = sizeof("comment") - 1;
|
||||
list[keys].attrs[0].value = (char *)s;
|
||||
list[keys].attrs[0].value_len = comment_len;
|
||||
list[keys].attrs[0].mandatory = 0;
|
||||
|
||||
s += comment_len;
|
||||
} else {
|
||||
list[keys].num_attrs = 0;
|
||||
list[keys].attrs = NULL;
|
||||
}
|
||||
list[keys].name_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].name = s; s += list[keys].name_len;
|
||||
list[keys].blob_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].blob = s; s += list[keys].blob_len;
|
||||
} else {
|
||||
/* Version == 2 */
|
||||
list[keys].name_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].name = s; s += list[keys].name_len;
|
||||
list[keys].blob_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].blob = s; s += list[keys].blob_len;
|
||||
list[keys].num_attrs = libssh2_ntohu32(s); s += 4;
|
||||
if (list[keys].num_attrs) {
|
||||
list[keys].attrs = LIBSSH2_ALLOC(session, list[keys].num_attrs * sizeof(libssh2_publickey_attribute));
|
||||
if (!list[keys].attrs) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
|
||||
goto err_exit;
|
||||
}
|
||||
for(i = 0; i < list[keys].num_attrs; i++) {
|
||||
list[keys].attrs[i].name_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].attrs[i].name = (char *)s; s += list[keys].attrs[i].name_len;
|
||||
list[keys].attrs[i].value_len = libssh2_ntohu32(s); s += 4;
|
||||
list[keys].attrs[i].value = (char *)s; s += list[keys].attrs[i].value_len;
|
||||
list[keys].attrs[i].mandatory = 0; /* actually an ignored value */
|
||||
}
|
||||
} else {
|
||||
list[keys].attrs = NULL;
|
||||
}
|
||||
}
|
||||
list[keys].packet = data; /* To be FREEd in libssh2_publickey_list_free() */
|
||||
keys++;
|
||||
|
||||
list[keys].packet = NULL; /* Terminate the list */
|
||||
data = NULL;
|
||||
break;
|
||||
default:
|
||||
/* Unknown/Unexpected */
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Only reached via explicit goto */
|
||||
err_exit:
|
||||
if (data) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
if (list) {
|
||||
libssh2_publickey_list_free(pkey, list);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_list_free
|
||||
* Free a previously fetched list of public keys
|
||||
*/
|
||||
LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, libssh2_publickey_list *pkey_list)
|
||||
{
|
||||
LIBSSH2_SESSION *session = pkey->channel->session;
|
||||
libssh2_publickey_list *p = pkey_list;
|
||||
|
||||
while (p->packet) {
|
||||
if (p->attrs) {
|
||||
LIBSSH2_FREE(session, p->attrs);
|
||||
}
|
||||
LIBSSH2_FREE(session, p->packet);
|
||||
p++;
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, pkey_list);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_publickey_shutdown
|
||||
* Shutdown the publickey subsystem
|
||||
*/
|
||||
LIBSSH2_API void libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey)
|
||||
{
|
||||
LIBSSH2_SESSION *session = pkey->channel->session;
|
||||
|
||||
libssh2_channel_free(pkey->channel);
|
||||
LIBSSH2_FREE(session, pkey);
|
||||
}
|
||||
/* }}} */
|
33
src/scp.c
33
src/scp.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -37,7 +37,6 @@
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LIBSSH2_SCP_RESPONSE_BUFLEN 256
|
||||
@@ -45,7 +44,7 @@
|
||||
/* {{{ libssh2_scp_recv
|
||||
* Open a channel and request a remote file via SCP
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *path, struct stat *sb)
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb)
|
||||
{
|
||||
int path_len = strlen(path);
|
||||
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
@@ -71,6 +70,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
}
|
||||
command[command_len - 1] = '\0';
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP receive");
|
||||
#endif
|
||||
/* Allocate a channel */
|
||||
if ((channel = libssh2_channel_open_session(session)) == NULL) {
|
||||
LIBSSH2_FREE(session, command);
|
||||
@@ -87,6 +89,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
}
|
||||
LIBSSH2_FREE(session, command);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
|
||||
#endif
|
||||
/* SCP ACK */
|
||||
response[0] = '\0';
|
||||
if (libssh2_channel_write(channel, response, 1) != 1) {
|
||||
@@ -198,6 +203,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mtime = %ld, atime = %ld", mtime, atime);
|
||||
#endif
|
||||
|
||||
/* We *should* check that atime.usec is valid, but why let that stop use? */
|
||||
break;
|
||||
@@ -296,6 +304,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mod = 0%lo size = %ld", mode, size);
|
||||
#endif
|
||||
|
||||
/* We *should* check that basename is valid, but why let that stop us? */
|
||||
break;
|
||||
@@ -319,11 +330,12 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
/* {{{ libssh2_scp_send_ex
|
||||
* Send a file using SCP
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char *path, int mode, size_t size, long mtime, long atime)
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime)
|
||||
{
|
||||
int path_len = strlen(path);
|
||||
unsigned char *command, *base, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned long response_len, command_len = path_len + sizeof("scp -t ");
|
||||
unsigned const char *base;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
|
||||
if (mtime || atime) {
|
||||
@@ -345,8 +357,12 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
}
|
||||
command[command_len - 1] = '\0';
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP send");
|
||||
#endif
|
||||
/* Allocate a channel */
|
||||
if ((channel = libssh2_channel_open_session(session)) == NULL) {
|
||||
/* previous call set libssh2_session_last_error(), pass it through */
|
||||
LIBSSH2_FREE(session, command);
|
||||
return NULL;
|
||||
}
|
||||
@@ -355,6 +371,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
|
||||
/* Request SCP for the desired file */
|
||||
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
||||
/* previous call set libssh2_session_last_error(), pass it through */
|
||||
LIBSSH2_FREE(session, command);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
@@ -371,6 +388,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
/* Send mtime and atime to be used for file */
|
||||
if (mtime || atime) {
|
||||
response_len = snprintf(response, LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime, atime);
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", response);
|
||||
#endif
|
||||
if (libssh2_channel_write(channel, response, response_len) != response_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send time data for SCP file", 0);
|
||||
libssh2_channel_free(channel);
|
||||
@@ -393,6 +413,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
}
|
||||
|
||||
response_len = snprintf(response, LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode, (unsigned long)size, base);
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", response);
|
||||
#endif
|
||||
if (libssh2_channel_write(channel, response, response_len) != response_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send core file data for SCP file", 0);
|
||||
libssh2_channel_free(channel);
|
||||
|
467
src/session.c
467
src/session.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -42,6 +42,26 @@
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
# include <sys/poll.h>
|
||||
#else
|
||||
# ifdef HAVE_SELECT
|
||||
# ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
# else
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* {{{ libssh2_default_alloc
|
||||
*/
|
||||
static LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
|
||||
@@ -81,12 +101,31 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
char c = '\0';
|
||||
int ret;
|
||||
|
||||
ret = recv(session->socket_fd, &c, 1, 0);
|
||||
ret = recv(session->socket_fd, &c, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
|
||||
if ((ret < 0) && (ret != EAGAIN)) {
|
||||
if (ret < 0) {
|
||||
#ifdef WIN32
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAEWOULDBLOCK:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case WSAENOTSOCK:
|
||||
errno = EBADF;
|
||||
break;
|
||||
case WSAENOTCONN:
|
||||
case WSAECONNABORTED:
|
||||
errno = ENOTCONN;
|
||||
break;
|
||||
case WSAEINTR:
|
||||
errno = EINTR;
|
||||
break;
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
if (errno != EAGAIN) {
|
||||
/* Some kinda error, but don't break for non-blocking issues */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret <= 0) continue;
|
||||
|
||||
@@ -108,6 +147,9 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
|
||||
memcpy(session->remote.banner, banner, banner_len);
|
||||
session->remote.banner[banner_len] = '\0';
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s", session->remote.banner);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -125,15 +167,31 @@ static int libssh2_banner_send(LIBSSH2_SESSION *session)
|
||||
banner_len = strlen(session->local.banner);
|
||||
banner = session->local.banner;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
{
|
||||
/* Hack and slash to avoid sending CRLF in debug output */
|
||||
char banner_dup[256];
|
||||
|
||||
return (send(session->socket_fd, banner, banner_len, 0) == banner_len) ? 0 : 1;
|
||||
if (banner_len < 256) {
|
||||
memcpy(banner_dup, banner, banner_len - 2);
|
||||
banner_dup[banner_len - 2] = '\0';
|
||||
} else {
|
||||
memcpy(banner_dup, banner, 255);
|
||||
banner[255] = '\0';
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s", banner_dup);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (send(session->socket_fd, banner, banner_len, LIBSSH2_SOCKET_SEND_FLAGS(session)) == banner_len) ? 0 : 1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_banner_set
|
||||
* Set the local banner
|
||||
*/
|
||||
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, char *banner)
|
||||
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner)
|
||||
{
|
||||
int banner_len = banner ? strlen(banner) : 0;
|
||||
|
||||
@@ -153,6 +211,10 @@ LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, char *banner)
|
||||
}
|
||||
|
||||
memcpy(session->local.banner, banner, banner_len);
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
session->local.banner[banner_len] = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s", session->local.banner);
|
||||
#endif
|
||||
session->local.banner[banner_len++] = '\r';
|
||||
session->local.banner[banner_len++] = '\n';
|
||||
session->local.banner[banner_len++] = '\0';
|
||||
@@ -188,6 +250,11 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
|
||||
session->free = local_free;
|
||||
session->realloc = local_realloc;
|
||||
session->abstract = abstract;
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "New session resource allocated");
|
||||
#endif
|
||||
|
||||
libssh2_crypto_init ();
|
||||
|
||||
return session;
|
||||
}
|
||||
@@ -228,6 +295,9 @@ LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbt
|
||||
return oldcb;
|
||||
break;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -246,31 +316,37 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
|
||||
unsigned char service[sizeof("ssh-userauth") + 5 - 1];
|
||||
unsigned long service_length;
|
||||
|
||||
if (socket <= 0) {
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "session_startup for socket %d", socket);
|
||||
#endif
|
||||
if (socket < 0) {
|
||||
/* Did we forget something? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE, "No socket provided", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE, "Bad socket provided", 0);
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
}
|
||||
session->socket_fd = socket;
|
||||
|
||||
/* TODO: Liveness check */
|
||||
if (libssh2_banner_receive(session)) {
|
||||
/* Unable to receive banner from remote */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE, "Timeout waiting for banner", 0);
|
||||
return LIBSSH2_ERROR_BANNER_NONE;
|
||||
}
|
||||
|
||||
if (libssh2_banner_send(session)) {
|
||||
/* Unable to send banner? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND, "Error sending banner to remote host", 0);
|
||||
return LIBSSH2_ERROR_BANNER_SEND;
|
||||
}
|
||||
|
||||
if (libssh2_banner_receive(session)) {
|
||||
/* Unable to receive banner from remote */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE, "Timeout waiting for banner", 0);
|
||||
return LIBSSH2_ERROR_BANNER_NONE;
|
||||
}
|
||||
|
||||
if (libssh2_kex_exchange(session, 0)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to exchange encryption keys", 0);
|
||||
return LIBSSH2_ERROR_KEX_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Requesting userauth service");
|
||||
#endif
|
||||
/* Request the userauth service */
|
||||
service[0] = SSH_MSG_SERVICE_REQUEST;
|
||||
libssh2_htonu32(service + 1, sizeof("ssh-userauth") - 1);
|
||||
@@ -303,6 +379,9 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
|
||||
*/
|
||||
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
{
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource", session->remote.banner);
|
||||
#endif
|
||||
while (session->channels.head) {
|
||||
LIBSSH2_CHANNEL *tmp = session->channels.head;
|
||||
|
||||
@@ -325,7 +404,7 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
libssh2_channel_forward_cancel(session->listeners);
|
||||
}
|
||||
|
||||
if (session->newkeys) {
|
||||
if (session->state & LIBSSH2_STATE_NEWKEYS) {
|
||||
/* hostkey */
|
||||
if (session->hostkey && session->hostkey->dtor) {
|
||||
session->hostkey->dtor(session, &session->server_hostkey_abstract);
|
||||
@@ -333,16 +412,9 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
|
||||
/* Client to Server */
|
||||
/* crypt */
|
||||
if (session->local.crypt) {
|
||||
if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
if (session->local.crypt_abstract) {
|
||||
LIBSSH2_FREE(session, session->local.crypt_abstract);
|
||||
session->local.crypt_abstract = NULL;
|
||||
}
|
||||
} else if (session->local.crypt->dtor) {
|
||||
if (session->local.crypt && session->local.crypt->dtor) {
|
||||
session->local.crypt->dtor(session, &session->local.crypt_abstract);
|
||||
}
|
||||
}
|
||||
/* comp */
|
||||
if (session->local.comp && session->local.comp->dtor) {
|
||||
session->local.comp->dtor(session, 1, &session->local.comp_abstract);
|
||||
@@ -354,16 +426,9 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
|
||||
/* Server to Client */
|
||||
/* crypt */
|
||||
if (session->remote.crypt) {
|
||||
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
if (session->remote.crypt_abstract) {
|
||||
LIBSSH2_FREE(session, session->remote.crypt_abstract);
|
||||
session->remote.crypt_abstract = NULL;
|
||||
}
|
||||
} else if (session->remote.crypt->dtor) {
|
||||
if (session->remote.crypt && session->remote.crypt->dtor) {
|
||||
session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
|
||||
}
|
||||
}
|
||||
/* comp */
|
||||
if (session->remote.comp && session->remote.comp->dtor) {
|
||||
session->remote.comp->dtor(session, 0, &session->remote.comp_abstract);
|
||||
@@ -439,11 +504,14 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
|
||||
/* {{{ libssh2_session_disconnect_ex
|
||||
*/
|
||||
LIBSSH2_API int 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, const char *description, const char *lang)
|
||||
{
|
||||
unsigned char *s, *data;
|
||||
unsigned long data_len, descr_len = 0, lang_len = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnecting: reason=%d, desc=%s, lang=%s", reason, description, lang);
|
||||
#endif
|
||||
if (description) {
|
||||
descr_len = strlen(description);
|
||||
}
|
||||
@@ -486,48 +554,54 @@ LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reas
|
||||
* NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
|
||||
* Strings should NOT be freed
|
||||
*/
|
||||
LIBSSH2_API char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type)
|
||||
LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type)
|
||||
{
|
||||
char *methodlist = NULL;
|
||||
/* All methods have char *name as their first element */
|
||||
LIBSSH2_KEX_METHOD *method = NULL;
|
||||
|
||||
switch(method_type) {
|
||||
case LIBSSH2_METHOD_KEX:
|
||||
methodlist = session->kex->name;
|
||||
method = session->kex;
|
||||
break;
|
||||
case LIBSSH2_METHOD_HOSTKEY:
|
||||
methodlist = session->hostkey->name;
|
||||
method = (LIBSSH2_KEX_METHOD*)session->hostkey;
|
||||
break;
|
||||
case LIBSSH2_METHOD_CRYPT_CS:
|
||||
methodlist = session->local.crypt->name;
|
||||
method = (LIBSSH2_KEX_METHOD*)session->local.crypt;
|
||||
break;
|
||||
case LIBSSH2_METHOD_CRYPT_SC:
|
||||
methodlist = session->remote.crypt->name;
|
||||
method = (LIBSSH2_KEX_METHOD*)session->remote.crypt;
|
||||
break;
|
||||
case LIBSSH2_METHOD_MAC_CS:
|
||||
methodlist = session->local.mac->name;
|
||||
method = (LIBSSH2_KEX_METHOD*)session->local.mac;
|
||||
break;
|
||||
case LIBSSH2_METHOD_MAC_SC:
|
||||
methodlist = session->remote.mac->name;
|
||||
method = (LIBSSH2_KEX_METHOD*)session->remote.mac;
|
||||
break;
|
||||
case LIBSSH2_METHOD_COMP_CS:
|
||||
methodlist = session->local.comp->name;
|
||||
method = (LIBSSH2_KEX_METHOD*)session->local.comp;
|
||||
break;
|
||||
case LIBSSH2_METHOD_COMP_SC:
|
||||
methodlist = session->remote.comp->name;
|
||||
method = (LIBSSH2_KEX_METHOD*)session->remote.comp;
|
||||
break;
|
||||
case LIBSSH2_METHOD_LANG_CS:
|
||||
methodlist = "";
|
||||
return "";
|
||||
break;
|
||||
case LIBSSH2_METHOD_LANG_SC:
|
||||
methodlist = "";
|
||||
return "";
|
||||
break;
|
||||
default:
|
||||
libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid parameter specified for method_type", 0);
|
||||
methodlist = NULL;
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return(methodlist);
|
||||
if (!method) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, "No method negotiated", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return method->name;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -594,3 +668,306 @@ LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errm
|
||||
return session->err_code;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_session_flag
|
||||
* Set/Get session flags
|
||||
* Passing flag==0 will avoid changing session->flags while still returning its current value
|
||||
*/
|
||||
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value)
|
||||
{
|
||||
if (value) {
|
||||
session->flags |= flag;
|
||||
} else {
|
||||
session->flags &= ~flag;
|
||||
}
|
||||
|
||||
return session->flags;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll_channel_read
|
||||
* Returns 0 if no data is waiting on channel,
|
||||
* non-0 if data is available
|
||||
*/
|
||||
LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
LIBSSH2_PACKET *packet = session->packets.head;
|
||||
|
||||
while (packet) {
|
||||
if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) && (extended == 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
|
||||
((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (extended != 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
|
||||
/* Found data waiting to be read */
|
||||
return 1;
|
||||
}
|
||||
packet = packet->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll_channel_write
|
||||
* Returns 0 if writing to channel would block,
|
||||
* non-0 if data can be written without blocking
|
||||
*/
|
||||
inline int libssh2_poll_channel_write(LIBSSH2_CHANNEL *channel)
|
||||
{
|
||||
return channel->local.window_size ? 1 : 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll_listener_queued
|
||||
* Returns 0 if no connections are waiting to be accepted
|
||||
* non-0 if one or more connections are available
|
||||
*/
|
||||
inline int libssh2_poll_listener_queued(LIBSSH2_LISTENER *listener)
|
||||
{
|
||||
return listener->queue ? 1 : 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll
|
||||
* Poll sockets, channels, and listeners for activity
|
||||
*/
|
||||
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
|
||||
{
|
||||
long timeout_remaining;
|
||||
int i, active_fds;
|
||||
#ifdef HAVE_POLL
|
||||
LIBSSH2_SESSION *session = NULL;
|
||||
struct pollfd sockets[nfds];
|
||||
|
||||
/* Setup sockets for polling */
|
||||
for(i = 0; i < nfds; i++) {
|
||||
fds[i].revents = 0;
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
sockets[i].fd = fds[i].fd.socket;
|
||||
sockets[i].events = fds[i].events;
|
||||
sockets[i].revents = 0;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
sockets[i].fd = fds[i].fd.channel->session->socket_fd;
|
||||
sockets[i].events = POLLIN;
|
||||
sockets[i].revents = 0;
|
||||
if (!session) session = fds[i].fd.channel->session;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
sockets[i].fd = fds[i].fd.listener->session->socket_fd;
|
||||
sockets[i].events = POLLIN;
|
||||
sockets[i].revents = 0;
|
||||
if (!session) session = fds[i].fd.listener->session;
|
||||
break;
|
||||
default:
|
||||
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_SELECT)
|
||||
LIBSSH2_SESSION *session = NULL;
|
||||
int maxfd = 0;
|
||||
fd_set rfds,wfds;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
for(i = 0; i < nfds; i++) {
|
||||
fds[i].revents = 0;
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
|
||||
FD_SET(fds[i].fd.socket, &rfds);
|
||||
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
|
||||
}
|
||||
if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
|
||||
FD_SET(fds[i].fd.socket, &wfds);
|
||||
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
|
||||
if (fds[i].fd.channel->session->socket_fd > maxfd) maxfd = fds[i].fd.channel->session->socket_fd;
|
||||
if (!session) session = fds[i].fd.channel->session;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
|
||||
if (fds[i].fd.listener->session->socket_fd > maxfd) maxfd = fds[i].fd.listener->session->socket_fd;
|
||||
if (!session) session = fds[i].fd.listener->session;
|
||||
break;
|
||||
default:
|
||||
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* No select() or poll()
|
||||
* no sockets sturcture to setup
|
||||
*/
|
||||
|
||||
timeout = 0;
|
||||
#endif /* HAVE_POLL or HAVE_SELECT */
|
||||
|
||||
timeout_remaining = timeout;
|
||||
do {
|
||||
#if defined(HAVE_POLL) || defined(HAVE_SELECT)
|
||||
int sysret;
|
||||
#endif
|
||||
|
||||
active_fds = 0;
|
||||
|
||||
for (i = 0; i < nfds; i++) {
|
||||
if (fds[i].events != fds[i].revents) {
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want to be ready for read */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* Not yet known to be ready for read */
|
||||
fds[i].revents |= libssh2_poll_channel_read(fds[i].fd.channel, 0) ? LIBSSH2_POLLFD_POLLIN : 0;
|
||||
}
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && /* Want to be ready for extended read */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { /* Not yet known to be ready for extended read */
|
||||
fds[i].revents |= libssh2_poll_channel_read(fds[i].fd.channel, 1) ? LIBSSH2_POLLFD_POLLEXT : 0;
|
||||
}
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && /* Want to be ready for write */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { /* Not yet known to be ready for write */
|
||||
fds[i].revents |= libssh2_poll_channel_write(fds[i].fd.channel) ? LIBSSH2_POLLFD_POLLOUT : 0;
|
||||
}
|
||||
if (fds[i].fd.channel->remote.close || fds[i].fd.channel->local.close) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
|
||||
}
|
||||
if (fds[i].fd.channel->session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want a connection */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* No connections known of yet */
|
||||
fds[i].revents |= libssh2_poll_listener_queued(fds[i].fd.listener) ? LIBSSH2_POLLFD_POLLIN : 0;
|
||||
}
|
||||
if (fds[i].fd.listener->session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_LISTENER_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fds[i].revents) {
|
||||
active_fds++;
|
||||
}
|
||||
}
|
||||
|
||||
if (active_fds) {
|
||||
/* Don't block on the sockets if we have channels/listeners which are ready */
|
||||
timeout_remaining = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
{
|
||||
struct timeval tv_begin, tv_end;
|
||||
|
||||
gettimeofday((struct timeval *)&tv_begin, NULL);
|
||||
sysret = poll(sockets, nfds, timeout_remaining);
|
||||
gettimeofday((struct timeval *)&tv_end, NULL);
|
||||
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
|
||||
timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
|
||||
}
|
||||
#else
|
||||
/* If the platform doesn't support gettimeofday,
|
||||
* then just make the call non-blocking and walk away
|
||||
*/
|
||||
sysret = poll(sockets, nfds, timeout_remaining);
|
||||
timeout_remaining = 0;
|
||||
#endif /* HAVE_GETTIMEOFDAY */
|
||||
|
||||
if (sysret > 0) {
|
||||
for (i = 0; i < nfds; i++) {
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
fds[i].revents = sockets[i].revents;
|
||||
sockets[i].revents = 0; /* In case we loop again, be nice */
|
||||
if (fds[i].revents) {
|
||||
active_fds++;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
if (sockets[i].events & POLLIN) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.channel->session, 0) > 0);
|
||||
}
|
||||
if (sockets[i].revents & POLLHUP) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
sockets[i].revents = 0;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if (sockets[i].events & POLLIN) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.listener->session, 0) > 0);
|
||||
}
|
||||
if (sockets[i].revents & POLLHUP) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_LISTENER_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
sockets[i].revents = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_SELECT)
|
||||
tv.tv_sec = timeout_remaining / 1000;
|
||||
tv.tv_usec = (timeout_remaining % 1000) * 1000;
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
{
|
||||
struct timeval tv_begin, tv_end;
|
||||
|
||||
gettimeofday((struct timeval *)&tv_begin, NULL);
|
||||
sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
|
||||
gettimeofday((struct timeval *)&tv_end, NULL);
|
||||
|
||||
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
|
||||
timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
|
||||
}
|
||||
#else
|
||||
/* If the platform doesn't support gettimeofday,
|
||||
* then just make the call non-blocking and walk away
|
||||
*/
|
||||
sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
|
||||
timeout_remaining = 0;
|
||||
#endif
|
||||
|
||||
if (sysret > 0) {
|
||||
for (i = 0; i < nfds; i++) {
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
if (FD_ISSET(fds[i].fd.socket, &rfds)) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
|
||||
}
|
||||
if (FD_ISSET(fds[i].fd.socket, &wfds)) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
|
||||
}
|
||||
if (fds[i].revents) {
|
||||
active_fds++;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.channel->session, 0) > 0);
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if (FD_ISSET(fds[i].fd.listener->session->socket_fd, &rfds)) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.listener->session, 0) > 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
|
||||
} while ((timeout_remaining > 0) && !active_fds);
|
||||
|
||||
return active_fds;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
198
src/sftp.c
198
src/sftp.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -89,6 +89,11 @@ struct _LIBSSH2_SFTP {
|
||||
#define LIBSSH2_SFTP_HANDLE_FILE 0
|
||||
#define LIBSSH2_SFTP_HANDLE_DIR 1
|
||||
|
||||
/* S_IFREG */
|
||||
#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE 0100000
|
||||
/* S_IFDIR */
|
||||
#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000
|
||||
|
||||
struct _LIBSSH2_SFTP_HANDLE {
|
||||
LIBSSH2_SFTP *sftp;
|
||||
LIBSSH2_SFTP_HANDLE *prev, *next;
|
||||
@@ -118,6 +123,9 @@ static int libssh2_sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, unsi
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
LIBSSH2_PACKET *packet;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Received packet %d", (int)data[0]);
|
||||
#endif
|
||||
packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate datablock for SFTP packet", 0);
|
||||
@@ -151,8 +159,11 @@ static int libssh2_sftp_packet_read(LIBSSH2_SFTP *sftp, int should_block)
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char buffer[4]; /* To store the packet length */
|
||||
unsigned char *packet;
|
||||
unsigned long packet_len;
|
||||
unsigned long packet_len, packet_received;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Waiting for packet: %s block", should_block ? "will" : "willnot");
|
||||
#endif
|
||||
if (should_block) {
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
if (4 != libssh2_channel_read(channel, buffer, 4)) {
|
||||
@@ -172,6 +183,9 @@ static int libssh2_sftp_packet_read(LIBSSH2_SFTP *sftp, int should_block)
|
||||
}
|
||||
}
|
||||
packet_len = libssh2_ntohu32(buffer);
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Data begin - Packet Length: %lu", packet_len);
|
||||
#endif
|
||||
if (packet_len > LIBSSH2_SFTP_PACKET_MAXLEN) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, "SFTP packet too large", 0);
|
||||
return -1;
|
||||
@@ -183,11 +197,17 @@ static int libssh2_sftp_packet_read(LIBSSH2_SFTP *sftp, int should_block)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (packet_len != libssh2_channel_read(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for SFTP packet", 0);
|
||||
packet_received = 0;
|
||||
while (packet_len > packet_received) {
|
||||
long bytes_received = libssh2_channel_read(channel, packet + packet_received, packet_len - packet_received);
|
||||
|
||||
if (bytes_received < 0) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Receive error waiting for SFTP packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
packet_received += bytes_received;
|
||||
}
|
||||
|
||||
if (libssh2_sftp_packet_add(sftp, packet, packet_len)) {
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@@ -206,7 +226,11 @@ static int libssh2_sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
LIBSSH2_PACKET *packet = sftp->packets.head;
|
||||
unsigned char match_buf[5];
|
||||
int match_len = 5;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Asking for %d packet", (int)packet_type);
|
||||
#endif
|
||||
if (poll_channel) {
|
||||
if (libssh2_sftp_packet_read(sftp, 0) < 0) {
|
||||
return -1;
|
||||
@@ -214,10 +238,15 @@ static int libssh2_sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type
|
||||
}
|
||||
|
||||
match_buf[0] = packet_type;
|
||||
if (packet_type == SSH_FXP_VERSION) {
|
||||
/* Special consideration when matching VERSION packet */
|
||||
match_len = 1;
|
||||
} else {
|
||||
libssh2_htonu32(match_buf + 1, request_id);
|
||||
}
|
||||
|
||||
while (packet) {
|
||||
if (strncmp(packet->data, match_buf, 5) == 0) {
|
||||
if (strncmp(packet->data, match_buf, match_len) == 0) {
|
||||
*data = packet->data;
|
||||
*data_len = packet->data_len;
|
||||
|
||||
@@ -250,6 +279,9 @@ static int libssh2_sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_
|
||||
{
|
||||
LIBSSH2_SESSION *session = sftp->channel->session;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Requiring %d packet", (int)packet_type);
|
||||
#endif
|
||||
if (libssh2_sftp_packet_ask(sftp, packet_type, request_id, data, data_len, 0) == 0) {
|
||||
/* A packet was available in the packet brigade */
|
||||
return 0;
|
||||
@@ -280,12 +312,21 @@ static int libssh2_sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_respon
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Flush */
|
||||
while (libssh2_sftp_packet_read(sftp, 0) > 0);
|
||||
|
||||
while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
int ret;
|
||||
for(i = 0; i < num_valid_responses; i++) {
|
||||
if (libssh2_sftp_packet_ask(sftp, valid_responses[i], request_id, data, data_len, !i) == 0) {
|
||||
if (libssh2_sftp_packet_ask(sftp, valid_responses[i], request_id, data, data_len, 0) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ret = libssh2_sftp_packet_read(sftp, 1);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) continue;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@@ -408,9 +449,12 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
|
||||
{
|
||||
LIBSSH2_SFTP *sftp;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
unsigned char *data, *s, buffer[13]; /* sftp_header(9) + version_id(4) */
|
||||
unsigned long data_len, request_id;
|
||||
unsigned char *data, *s, buffer[9]; /* sftp_header(5){excludes request_id} + version_id(4) */
|
||||
unsigned long data_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Initializing SFTP subsystem");
|
||||
#endif
|
||||
channel = libssh2_channel_open_session(session);
|
||||
if (!channel) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
|
||||
@@ -424,6 +468,8 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
|
||||
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
|
||||
libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
|
||||
|
||||
sftp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP));
|
||||
if (!sftp) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new SFTP structure", 0);
|
||||
@@ -432,21 +478,23 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
|
||||
}
|
||||
memset(sftp, 0, sizeof(LIBSSH2_SFTP));
|
||||
sftp->channel = channel;
|
||||
sftp->request_id = 0;
|
||||
|
||||
request_id = sftp->request_id++;
|
||||
libssh2_htonu32(buffer, 4 + 5);
|
||||
libssh2_htonu32(buffer, 5);
|
||||
buffer[4] = SSH_FXP_INIT;
|
||||
libssh2_htonu32(buffer + 5, request_id);
|
||||
libssh2_htonu32(buffer + 9, 6);
|
||||
libssh2_htonu32(buffer + 5, LIBSSH2_SFTP_VERSION);
|
||||
|
||||
if (13 != libssh2_channel_write(channel, buffer, 13)) {
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending FXP_INIT packet advertising version %d support", (int)LIBSSH2_SFTP_VERSION);
|
||||
#endif
|
||||
if (9 != libssh2_channel_write(channel, buffer, 9)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send SSH_FXP_INIT", 0);
|
||||
libssh2_channel_free(channel);
|
||||
LIBSSH2_FREE(session, sftp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (libssh2_sftp_packet_require(sftp, SSH_FXP_VERSION, request_id, &data, &data_len)) {
|
||||
if (libssh2_sftp_packet_require(sftp, SSH_FXP_VERSION, 0, &data, &data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from SFTP subsystem", 0);
|
||||
libssh2_channel_free(channel);
|
||||
LIBSSH2_FREE(session, sftp);
|
||||
@@ -462,8 +510,14 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
|
||||
s = data + 1;
|
||||
sftp->version = libssh2_ntohu32(s); s += 4;
|
||||
if (sftp->version > LIBSSH2_SFTP_VERSION) {
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Truncating remote SFTP version from %lu", sftp->version);
|
||||
#endif
|
||||
sftp->version = LIBSSH2_SFTP_VERSION;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Enabling SFTP version %lu compatability", sftp->version);
|
||||
#endif
|
||||
while (s < (data + data_len)) {
|
||||
char *extension_name, *extension_data;
|
||||
unsigned long extname_len, extdata_len;
|
||||
@@ -501,7 +555,7 @@ LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp) {
|
||||
/* {{{ libssh2_sftp_open_ex
|
||||
*
|
||||
*/
|
||||
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)
|
||||
LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *filename, unsigned int filename_len, unsigned long flags, long mode, int open_type)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -515,10 +569,11 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_REMOVE packet", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_OPEN or FXP_OPENDIR packet", 0);
|
||||
return NULL;
|
||||
}
|
||||
attrs.permissions = mode;
|
||||
/* Filetype in SFTP 3 and earlier */
|
||||
attrs.permissions = mode | ((open_type == LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_ATTR_PFILETYPE_FILE : LIBSSH2_SFTP_ATTR_PFILETYPE_DIR);
|
||||
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
*(s++) = (open_type == LIBSSH2_SFTP_OPENFILE) ? SSH_FXP_OPEN : SSH_FXP_OPENDIR;
|
||||
@@ -531,8 +586,11 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
|
||||
s += libssh2_sftp_attr2bin(s, &attrs);
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request", (open_type == LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
|
||||
#endif
|
||||
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return NULL;
|
||||
}
|
||||
@@ -583,6 +641,9 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
|
||||
|
||||
fp->u.file.offset = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Open command successful");
|
||||
#endif
|
||||
return fp;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -601,6 +662,9 @@ LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
unsigned char read_responses[2] = { SSH_FXP_DATA, SSH_FXP_STATUS };
|
||||
size_t bytes_read = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading %lu bytes from SFTP handle", (unsigned long)buffer_maxlen);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_CLOSE packet", 0);
|
||||
@@ -639,6 +703,9 @@ LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
if (bytes_read > (data_len - 9)) {
|
||||
return -1;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu bytes returned", (unsigned long)bytes_read);
|
||||
#endif
|
||||
memcpy(buffer, data + 9, bytes_read);
|
||||
handle->u.file.offset += bytes_read;
|
||||
LIBSSH2_FREE(session, data);
|
||||
@@ -674,6 +741,11 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
}
|
||||
memcpy(buffer, s, filename_len); s += real_filename_len;
|
||||
|
||||
/* The filename is not null terminated, make it so if possible */
|
||||
if (filename_len < buffer_maxlen) {
|
||||
buffer[filename_len] = '\0';
|
||||
}
|
||||
|
||||
/* Skip longname */
|
||||
s += 4 + libssh2_ntohu32(s);
|
||||
|
||||
@@ -705,6 +777,9 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
libssh2_htonu32(s, handle->handle_len); s += 4;
|
||||
memcpy(s, handle->handle, handle->handle_len); s += handle->handle_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading entries from directory handle");
|
||||
#endif
|
||||
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@@ -732,6 +807,9 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
}
|
||||
|
||||
num_names = libssh2_ntohu32(data + 5);
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned", num_names);
|
||||
#endif
|
||||
if (num_names <= 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return (num_names == 0) ? 0 : -1;
|
||||
@@ -746,6 +824,11 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
|
||||
}
|
||||
memcpy(buffer, data + 13, filename_len);
|
||||
|
||||
/* The filename is not null terminated, make it so if possible */
|
||||
if (filename_len < buffer_maxlen) {
|
||||
buffer[filename_len] = '\0';
|
||||
}
|
||||
|
||||
if (attrs) {
|
||||
memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
|
||||
libssh2_sftp_bin2attr(attrs, data + 13 + real_filename_len + (4 + libssh2_ntohu32(data + 13 + real_filename_len)));
|
||||
@@ -776,6 +859,9 @@ LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *b
|
||||
unsigned long packet_len = handle->handle_len + count + 25; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Writing %lu bytes", (unsigned long)count);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_WRITE packet", 0);
|
||||
@@ -832,6 +918,9 @@ LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_
|
||||
unsigned char *packet, *s, *data;
|
||||
unsigned char fstat_responses[2] = { SSH_FXP_ATTRS, SSH_FXP_STATUS };
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Issuing %s command", setstat ? "set-stat" : "stat");
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FSTAT/FSETSTAT packet", 0);
|
||||
@@ -912,6 +1001,9 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
unsigned long packet_len = handle->handle_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Closing handle");
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_CLOSE packet", 0);
|
||||
@@ -972,7 +1064,7 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
|
||||
/* {{{ libssh2_sftp_unlink_ex
|
||||
* Delete a file from the remote server
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len)
|
||||
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, unsigned int filename_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -980,6 +1072,9 @@ LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int f
|
||||
unsigned long packet_len = filename_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Unlinking %s", filename);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_REMOVE packet", 0);
|
||||
@@ -1021,17 +1116,26 @@ LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int f
|
||||
/* {{{ libssh2_sftp_rename_ex
|
||||
* Rename a file on the remote server
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filename, int source_filename_len,
|
||||
char *dest_filename, int dest_filename_len,
|
||||
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filename, unsigned int source_filename_len,
|
||||
char *dest_filename, unsigned int dest_filename_len,
|
||||
long flags)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned long data_len, retcode = -1, request_id;
|
||||
unsigned long packet_len = source_filename_len + dest_filename_len + 21; /* packet_len(4) + packet_type(1) + request_id(4) +
|
||||
source_filename_len(4) + dest_filename_len(4) + flags(4) */
|
||||
unsigned long packet_len = source_filename_len + dest_filename_len + 17 + (sftp->version >= 5 ? 4 : 0);
|
||||
/* packet_len(4) + packet_type(1) + request_id(4) +
|
||||
source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
if (sftp->version < 2) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Server does not support RENAME", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Renaming %s to %s", source_filename, dest_filename);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_RENAME packet", 0);
|
||||
@@ -1046,10 +1150,13 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filenam
|
||||
memcpy(s, source_filename, source_filename_len); s += source_filename_len;
|
||||
libssh2_htonu32(s, dest_filename_len); s += 4;
|
||||
memcpy(s, dest_filename, dest_filename_len); s += dest_filename_len;
|
||||
libssh2_htonu32(s, flags); s += 4;
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
|
||||
if (sftp->version >= 5) {
|
||||
libssh2_htonu32(s, flags); s += 4;
|
||||
}
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, packet, s - packet)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_RENAME command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
@@ -1090,7 +1197,7 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filenam
|
||||
/* {{{ libssh2_sftp_mkdir_ex
|
||||
* Create a directory
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, long mode)
|
||||
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned int path_len, long mode)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -1100,12 +1207,16 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
/* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Creating directory %s with mode 0%lo", path, mode);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_MKDIR packet", 0);
|
||||
return -1;
|
||||
}
|
||||
attrs.permissions = mode;
|
||||
/* Filetype in SFTP 3 and earlier */
|
||||
attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR;
|
||||
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
*(s++) = SSH_FXP_MKDIR;
|
||||
@@ -1116,7 +1227,7 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
s += libssh2_sftp_attr2bin(s, &attrs);
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
@@ -1143,7 +1254,7 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
/* {{{ libssh2_sftp_rmdir_ex
|
||||
* Remove a directory
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len)
|
||||
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned int path_len)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -1151,6 +1262,9 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
unsigned long packet_len = path_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
|
||||
unsigned char *packet, *s, *data;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Removing directory: %s", path);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_MKDIR packet", 0);
|
||||
@@ -1165,7 +1279,7 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
memcpy(s, path, path_len); s += path_len;
|
||||
|
||||
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
@@ -1192,7 +1306,7 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
|
||||
/* {{{ libssh2_sftp_stat_ex
|
||||
* Stat a file or symbolic link
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs)
|
||||
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, unsigned int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -1202,6 +1316,9 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_le
|
||||
unsigned char *packet, *s, *data;
|
||||
unsigned char stat_responses[2] = { SSH_FXP_ATTRS, SSH_FXP_STATUS };
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s", (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" : (stat_type == LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path);
|
||||
#endif
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_MKDIR packet", 0);
|
||||
@@ -1265,7 +1382,7 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_le
|
||||
/* {{{ libssh2_sftp_symlink_ex
|
||||
* Read or set a symlink
|
||||
*/
|
||||
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, int path_len, char *target, int target_len, int link_type)
|
||||
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)
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = sftp->channel;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
@@ -1275,12 +1392,22 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
|
||||
unsigned char *packet, *s, *data;
|
||||
unsigned char link_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS };
|
||||
|
||||
if ((sftp->version < 3) &&
|
||||
(link_type != LIBSSH2_SFTP_REALPATH)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Server does not support SYMLINK or READLINK", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for SYMLINK/READLINK/REALPATH packet", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SFTP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s on %s", (link_type == LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading",
|
||||
(link_type == LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path);
|
||||
#endif
|
||||
libssh2_htonu32(s, packet_len - 4); s += 4;
|
||||
switch (link_type) {
|
||||
case LIBSSH2_SFTP_REALPATH:
|
||||
@@ -1335,10 +1462,11 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
|
||||
}
|
||||
|
||||
link_len = libssh2_ntohu32(data + 9);
|
||||
if (link_len > target_len) {
|
||||
link_len = target_len;
|
||||
if (link_len >= target_len) {
|
||||
link_len = target_len - 1;
|
||||
}
|
||||
memcpy(target, data + 13, link_len);
|
||||
target[link_len] = 0;
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
return link_len;
|
||||
|
509
src/userauth.c
509
src/userauth.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,16 +36,25 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Needed for struct iovec on some platforms */
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* {{{ proto 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, char *username, int username_len)
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len)
|
||||
{
|
||||
unsigned char reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
||||
unsigned long data_len = username_len + 31; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
|
||||
method_len(4) + method(4)"none" */
|
||||
unsigned long methods_len;
|
||||
@@ -76,25 +85,23 @@ LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
while (1) {
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
/* Wow, who'dve thought... */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->authenticated = 1;
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
/* What we *actually* wanted to happen */
|
||||
break;
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
/* Wow, who'dve thought... */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
methods_len = libssh2_ntohu32(data + 1);
|
||||
memcpy(data, data + 5, methods_len);
|
||||
data[methods_len] = '\0';
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s", data);
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -105,18 +112,18 @@ LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session)
|
||||
{
|
||||
return session->authenticated;
|
||||
return session->state & LIBSSH2_STATE_AUTHENTICATED;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_password
|
||||
* Plain ol' login
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *username, int username_len,
|
||||
char *password, int password_len,
|
||||
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)))
|
||||
{
|
||||
unsigned char *data, *s;
|
||||
unsigned char *data, *s, reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 };
|
||||
unsigned long data_len = username_len + password_len + 40; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
|
||||
method_len(4) + method(8)"password" + chgpwdbool(1) + password_len(4) */
|
||||
|
||||
@@ -141,6 +148,9 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
|
||||
libssh2_htonu32(s, password_len); s += 4;
|
||||
memcpy(s, password, password_len); s += password_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting to login using password authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, data, data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password request", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
@@ -148,22 +158,27 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
while (1) {
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->authenticated = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
password_response:
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, &data, &data_len, 0) == 0) {
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password authentication successful");
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) {
|
||||
char *newpw = NULL;
|
||||
int newpw_len = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password change required");
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
if (passwd_change_cb) {
|
||||
passwd_change_cb(session, &newpw, &newpw_len, &session->abstract);
|
||||
@@ -203,16 +218,18 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, newpw);
|
||||
/* TODO: Reset timeout? */
|
||||
|
||||
/* Ugliest use of goto ever. Blame it on the askN => requirev migration. */
|
||||
goto password_response;
|
||||
} else {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password Expired, and no callback specified", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* FAILURE */
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -221,12 +238,16 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
|
||||
*/
|
||||
static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char **method, unsigned long *method_len,
|
||||
unsigned char **pubkeydata, unsigned long *pubkeydata_len,
|
||||
char *pubkeyfile)
|
||||
const char *pubkeyfile)
|
||||
{
|
||||
FILE *fd;
|
||||
char *pubkey = NULL, c, *sp1, *sp2, *tmp;
|
||||
int pubkey_len = 0, tmp_len;
|
||||
size_t pubkey_len = 0;
|
||||
unsigned int tmp_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s", pubkeyfile);
|
||||
#endif
|
||||
/* Read Public Key */
|
||||
fd = fopen(pubkeyfile, "r");
|
||||
if (!fd) {
|
||||
@@ -234,6 +255,10 @@ static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char *
|
||||
return -1;
|
||||
}
|
||||
while (!feof(fd) && (c = fgetc(fd)) != '\r' && c != '\n') pubkey_len++;
|
||||
if (feof(fd)) {
|
||||
/* the last character was EOF */
|
||||
pubkey_len--;
|
||||
}
|
||||
rewind(fd);
|
||||
|
||||
if (pubkey_len <= 1) {
|
||||
@@ -255,7 +280,10 @@ static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char *
|
||||
return -1;
|
||||
}
|
||||
fclose(fd);
|
||||
while (pubkey_len && (pubkey[pubkey_len-1] == '\r' || pubkey[pubkey_len-1] == '\n')) pubkey_len--;
|
||||
/*
|
||||
* Remove trailing whitespace
|
||||
*/
|
||||
while (pubkey_len && isspace(pubkey[pubkey_len-1])) pubkey_len--;
|
||||
|
||||
if (!pubkey_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_FILE, "Missing public key data", 0);
|
||||
@@ -293,15 +321,18 @@ static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char *
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_file_read_publickey
|
||||
/* {{{ libssh2_file_read_privatekey
|
||||
* Read a PEM encoded private key from an id_??? style file
|
||||
*/
|
||||
static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKEY_METHOD **hostkey_method, void **hostkey_abstract,
|
||||
char *method, int method_len,
|
||||
char *privkeyfile, char *passphrase)
|
||||
const char *method, int method_len,
|
||||
const char *privkeyfile, const char *passphrase)
|
||||
{
|
||||
LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods();
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s", privkeyfile);
|
||||
#endif
|
||||
*hostkey_method = NULL;
|
||||
*hostkey_abstract = NULL;
|
||||
while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
|
||||
@@ -326,19 +357,151 @@ static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKE
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_publickey_fromfile_ex
|
||||
/* {{{ libssh2_userauth_hostbased_fromfile_ex
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len,
|
||||
char *publickey, char *privatekey,
|
||||
char *passphrase)
|
||||
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase,
|
||||
const char *hostname, unsigned int hostname_len,
|
||||
const char *local_username, unsigned int local_username_len)
|
||||
{
|
||||
LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
void *abstract;
|
||||
unsigned char buf[5];
|
||||
struct iovec datavec[4];
|
||||
unsigned char *method, *pubkeydata, *packet, *s, *b, *sig;
|
||||
unsigned long method_len, pubkeydata_len, packet_len, sig_len;
|
||||
unsigned char *method, *pubkeydata, *packet, *s, *sig, *data, reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
||||
unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;
|
||||
|
||||
if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
packet_len = username_len + method_len + hostname_len + local_username_len + pubkeydata_len + 48;
|
||||
/* packet_type(1) + username_len(4) + servicename_len(4) + service_name(14)"ssh-connection" +
|
||||
* authmethod_len(4) + authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
|
||||
* local_username_len(4)
|
||||
*/
|
||||
/* Preallocate space for an overall length, method name again,
|
||||
* and the signature, which won't be any larger than the size of the publickeydata itself */
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len + 4 + (4 + method_len) + (4 + pubkeydata_len));
|
||||
|
||||
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
||||
libssh2_htonu32(s, username_len); s += 4;
|
||||
memcpy(s, username, username_len); s += username_len;
|
||||
|
||||
libssh2_htonu32(s, 14); s += 4;
|
||||
memcpy(s, "ssh-connection", 14); s += 14;
|
||||
|
||||
libssh2_htonu32(s, 9); s += 4;
|
||||
memcpy(s, "hostbased", 9); s += 9;
|
||||
|
||||
libssh2_htonu32(s, method_len); s += 4;
|
||||
memcpy(s, method, method_len); s += method_len;
|
||||
|
||||
libssh2_htonu32(s, pubkeydata_len); s += 4;
|
||||
memcpy(s, pubkeydata, pubkeydata_len); s += pubkeydata_len;
|
||||
|
||||
libssh2_htonu32(s, hostname_len); s += 4;
|
||||
memcpy(s, hostname, hostname_len); s += hostname_len;
|
||||
|
||||
libssh2_htonu32(s, local_username_len); s += 4;
|
||||
memcpy(s, local_username, local_username_len); s += local_username_len;
|
||||
|
||||
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, method, method_len, privatekey, passphrase)) {
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
|
||||
libssh2_htonu32(buf, session->session_id_len);
|
||||
datavec[0].iov_base = buf;
|
||||
datavec[0].iov_len = 4;
|
||||
datavec[1].iov_base = session->session_id;
|
||||
datavec[1].iov_len = session->session_id_len;
|
||||
datavec[2].iov_base = packet;
|
||||
datavec[2].iov_len = packet_len;
|
||||
|
||||
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &abstract);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &abstract);
|
||||
}
|
||||
|
||||
if (sig_len > pubkeydata_len ) {
|
||||
/* Should *NEVER* happen, but...well.. better safe than sorry */
|
||||
packet = LIBSSH2_REALLOC(session, packet, packet_len + 4 + (4 + method_len) + (4 + sig_len)); /* PK sigblob */
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating additional space for userauth-hostbased packet", 0);
|
||||
LIBSSH2_FREE(session, method);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
s = packet + packet_len;
|
||||
|
||||
libssh2_htonu32(s, 4 + method_len + 4 + sig_len); s += 4;
|
||||
|
||||
libssh2_htonu32(s, method_len); s += 4;
|
||||
memcpy(s, method, method_len); s += method_len;
|
||||
LIBSSH2_FREE(session, method);
|
||||
|
||||
libssh2_htonu32(s, sig_len); s += 4;
|
||||
memcpy(s, sig, sig_len); s += sig_len;
|
||||
LIBSSH2_FREE(session, sig);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting hostbased authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, packet, s - packet)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-hostbased request", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Hostbased authentication successful");
|
||||
#endif
|
||||
/* We are us and we've proved it. */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_publickey_fromfile_ex
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase)
|
||||
{
|
||||
LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
void *abstract;
|
||||
unsigned char buf[5];
|
||||
struct iovec datavec[4];
|
||||
unsigned char *method, *pubkeydata, *packet, *s, *b, *sig, *data;
|
||||
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PK_OK, 0 };
|
||||
unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;
|
||||
|
||||
if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
|
||||
return -1;
|
||||
@@ -371,6 +534,9 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
libssh2_htonu32(s, pubkeydata_len); s += 4;
|
||||
memcpy(s, pubkeydata, pubkeydata_len); s += pubkeydata_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@@ -379,21 +545,27 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Pubkey authentication prematurely successful");
|
||||
#endif
|
||||
/* God help any SSH server that allows an UNVERIFIED public key to validate the user */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
session->authenticated = 1;
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@@ -403,21 +575,8 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_PK_OK, &data, &data_len, 0) == 0) {
|
||||
/* Semi-Success! */
|
||||
if ((libssh2_ntohu32(data + 1) != method_len) ||
|
||||
strncmp(data + 5, method, method_len) ||
|
||||
(libssh2_ntohu32(data + 5 + method_len) != pubkeydata_len) ||
|
||||
strncmp(data + 5 + method_len + 4, pubkeydata, pubkeydata_len)) {
|
||||
/* Unlikely but possible, the server has responded to a different userauth public key request */
|
||||
LIBSSH2_FREE(session, data);
|
||||
continue;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
break;
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
}
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
|
||||
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, method, method_len, privatekey, passphrase)) {
|
||||
@@ -471,6 +630,9 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
memcpy(s, sig, sig_len); s += sig_len;
|
||||
LIBSSH2_FREE(session, sig);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication -- phase 2");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, packet, s - packet)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@@ -478,26 +640,227 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
/* PK_OK is no longer valid */
|
||||
reply_codes[2] = 0;
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Publickey authentication successful");
|
||||
#endif
|
||||
/* We are us and we've proved it. */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->authenticated = 1;
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
|
||||
return -1;
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_keyboard_interactive
|
||||
* Authenticate using a challenge-response authentication
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
|
||||
{
|
||||
unsigned char *s, *data; /* packet */
|
||||
unsigned long packet_len;
|
||||
|
||||
packet_len = 1 /* byte SSH_MSG_USERAUTH_REQUEST */
|
||||
+ 4 + username_len /* string user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
|
||||
+ 4 + 14 /* string service name (US-ASCII) */
|
||||
+ 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) */
|
||||
;
|
||||
|
||||
if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive authentication", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*s++ = SSH_MSG_USERAUTH_REQUEST;
|
||||
|
||||
/* user name */
|
||||
libssh2_htonu32(s, username_len); s += 4;
|
||||
memcpy(s, username, username_len); s += username_len;
|
||||
|
||||
/* service name */
|
||||
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
|
||||
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
|
||||
|
||||
/* "keyboard-interactive" */
|
||||
libssh2_htonu32(s, sizeof("keyboard-interactive") - 1); s += 4;
|
||||
memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1); s += sizeof("keyboard-interactive") - 1;
|
||||
|
||||
/* language tag */
|
||||
libssh2_htonu32(s, 0); s += 4;
|
||||
|
||||
/* submethods */
|
||||
libssh2_htonu32(s, 0); s += 4;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting keyboard-interactive authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, data, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send keyboard-interactive request", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
for (;;) {
|
||||
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 };
|
||||
unsigned int auth_name_len;
|
||||
char* auth_name = NULL;
|
||||
unsigned auth_instruction_len;
|
||||
char* auth_instruction = NULL;
|
||||
unsigned int language_tag_len;
|
||||
unsigned long data_len;
|
||||
unsigned int num_prompts = 0;
|
||||
unsigned int i;
|
||||
int auth_failure = 1;
|
||||
LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts = NULL;
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses = NULL;
|
||||
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive authentication successful");
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* server requested PAM-like conversation */
|
||||
|
||||
s = data + 1;
|
||||
|
||||
/* string name (ISO-10646 UTF-8) */
|
||||
auth_name_len = libssh2_ntohu32(s); s += 4;
|
||||
if (!(auth_name = LIBSSH2_ALLOC(session, auth_name_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'name' request field", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(auth_name, s, auth_name_len); s += auth_name_len;
|
||||
|
||||
/* string instruction (ISO-10646 UTF-8) */
|
||||
auth_instruction_len = libssh2_ntohu32(s); s += 4;
|
||||
if (!(auth_instruction = LIBSSH2_ALLOC(session, auth_instruction_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'instruction' request field", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(auth_instruction, s, auth_instruction_len); s += auth_instruction_len;
|
||||
|
||||
/* string language tag (as defined in [RFC-3066]) */
|
||||
language_tag_len = libssh2_ntohu32(s); s += 4;
|
||||
/* ignoring this field as deprecated */ s += language_tag_len;
|
||||
|
||||
/* int num-prompts */
|
||||
num_prompts = libssh2_ntohu32(s); s += 4;
|
||||
|
||||
prompts = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
|
||||
if (!prompts) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompts array", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memset(prompts, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
|
||||
|
||||
responses = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
|
||||
if (!responses) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive responses array", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memset(responses, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
|
||||
|
||||
for(i = 0; i != num_prompts; ++i) {
|
||||
/* string prompt[1] (ISO-10646 UTF-8) */
|
||||
prompts[i].length = libssh2_ntohu32(s); s += 4;
|
||||
if (!(prompts[i].text = LIBSSH2_ALLOC(session, prompts[i].length))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompt message", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(prompts[i].text, s, prompts[i].length); s += prompts[i].length;
|
||||
|
||||
/* boolean echo[1] */
|
||||
prompts[i].echo = *s++;
|
||||
}
|
||||
|
||||
response_callback(auth_name, auth_name_len, auth_instruction, auth_instruction_len, num_prompts, prompts, responses, &session->abstract);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive response callback function invoked");
|
||||
#endif
|
||||
|
||||
packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
|
||||
+ 4 /* int num-responses */
|
||||
;
|
||||
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
packet_len += 4 + responses[i].length; /* string response[1] (ISO-10646 UTF-8) */
|
||||
}
|
||||
|
||||
if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive response packet", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*s = SSH_MSG_USERAUTH_INFO_RESPONSE; s++;
|
||||
libssh2_htonu32(s, num_prompts); s += 4;
|
||||
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
libssh2_htonu32(s, responses[i].length); s += 4;
|
||||
memcpy(s, responses[i].text, responses[i].length); s += responses[i].length;
|
||||
}
|
||||
|
||||
if (libssh2_packet_write(session, data, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-keyboard-interactive request", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
auth_failure = 0;
|
||||
|
||||
cleanup:
|
||||
/* It's safe to clean all the data here, because unallocated pointers
|
||||
* are filled by zeroes
|
||||
*/
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
if (prompts) {
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
LIBSSH2_FREE(session, prompts[i].text);
|
||||
}
|
||||
}
|
||||
|
||||
if (responses) {
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
LIBSSH2_FREE(session, responses[i].text);
|
||||
}
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, prompts);
|
||||
LIBSSH2_FREE(session, responses);
|
||||
|
||||
if (auth_failure) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
@@ -14,12 +14,15 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
char *fingerprint;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
char *username=(char *)"username";
|
||||
char *password=(char *)"password";
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
@@ -61,15 +64,22 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(argc > 1) {
|
||||
username = argv[1];
|
||||
}
|
||||
if(argc > 2) {
|
||||
password = argv[2];
|
||||
}
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, "username", "password")) {
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, "username", "/home/username/.ssh/id_rsa.pub", "/home/username/.ssh/id_rsa", "pasphrase")) {
|
||||
if (libssh2_userauth_publickey_fromfile(session, username, "/home/username/.ssh/id_rsa.pub", "/home/username/.ssh/id_rsa", password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
@@ -84,12 +94,12 @@ int main(int argc, char *argv[]) {
|
||||
/* Some environment variables may be set,
|
||||
* It's up to the server which ones it'll allow though
|
||||
*/
|
||||
libssh2_channel_setenv(channel, "FOO", "bar");
|
||||
libssh2_channel_setenv(channel, (char *)"FOO", (char *)"bar");
|
||||
|
||||
/* Request a terminal with 'vanilla' terminal emulation
|
||||
* See /etc/termcap for more options
|
||||
*/
|
||||
if (libssh2_channel_request_pty(channel, "vanilla")) {
|
||||
if (libssh2_channel_request_pty(channel, (char *)"vanilla")) {
|
||||
fprintf(stderr, "Failed requesting pty\n");
|
||||
goto skip_shell;
|
||||
}
|
||||
|
5
tests/.cvsignore
Normal file
5
tests/.cvsignore
Normal file
@@ -0,0 +1,5 @@
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
simple
|
7
tests/Makefile.am
Normal file
7
tests/Makefile.am
Normal file
@@ -0,0 +1,7 @@
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
AM_LDFLAGS = -no-install
|
||||
LDADD = ../src/libssh2.la
|
||||
|
||||
ctests = simple$(EXEEXT)
|
||||
TESTS = $(ctests)
|
||||
check_PROGRAMS = $(ctests)
|
56
tests/simple.c
Normal file
56
tests/simple.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Copyright (C) 2007 The Written Word, Inc. All rights reserved.
|
||||
* Author: Simon Josefsson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libssh2.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
session = libssh2_session_init();
|
||||
if (!session)
|
||||
{
|
||||
fprintf (stderr, "libssh2_session_init() failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
libssh2_session_free(session);
|
||||
|
||||
return 0;
|
||||
}
|
@@ -7,3 +7,6 @@
|
||||
Debug
|
||||
Release
|
||||
*.exp
|
||||
*.ncb
|
||||
*.opt
|
||||
*.plg
|
||||
|
@@ -1,10 +1,10 @@
|
||||
|
||||
# Tweak these for your system
|
||||
OPENSSLINC=\local\php\php_build\include
|
||||
OPENSSLLIB=\local\php\php_build\lib
|
||||
OPENSSLINC=..\libssh2_build\include
|
||||
OPENSSLLIB=..\libssh2_build\lib
|
||||
|
||||
ZLIBINC=-DLIBSSH2_HAVE_ZLIB=1 /I\local\php\php_build\include
|
||||
ZLIBLIB=\local\php\php_build\lib
|
||||
ZLIBINC=-DLIBSSH2_HAVE_ZLIB=1 /I..\libssh2_build\include
|
||||
ZLIBLIB=..\libssh2_build\lib
|
||||
|
||||
!if "$(TARGET)" == ""
|
||||
TARGET=Release
|
||||
|
156
win32/libssh2.dsp
Normal file
156
win32/libssh2.dsp
Normal file
@@ -0,0 +1,156 @@
|
||||
# Microsoft Developer Studio Project File - Name="libssh2" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||
|
||||
CFG=libssh2 - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "libssh2.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "libssh2.mak" CFG="libssh2 - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "libssh2 - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "libssh2 - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "libssh2 - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "libssh2___Win32_Release"
|
||||
# PROP BASE Intermediate_Dir "libssh2___Win32_Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\include" /I "..\win32" /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "libssh2 - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\include" /I "..\win32" /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo /out:"Debug\libssh2d.lib"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "libssh2 - Win32 Release"
|
||||
# Name "libssh2 - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\channel.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\comp.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\crypt.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\hostkey.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\kex.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\mac.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\misc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\packet.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\scp.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\session.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\sftp.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\src\userauth.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\libssh2.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libssh2_config.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\libssh2_priv.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\libssh2_sftp.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
41
win32/libssh2.dsw
Normal file
41
win32/libssh2.dsw
Normal file
@@ -0,0 +1,41 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "libssh2"=.\libssh2.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "ssh2_sample"=.\ssh2_sample.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
@@ -1,4 +1,6 @@
|
||||
#ifndef WIN32
|
||||
#define WIN32
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#include <mswsock.h>
|
||||
#include <ws2tcpip.h>
|
||||
@@ -29,3 +31,8 @@ static inline int usleep(int udelay)
|
||||
|
||||
#define snprintf _snprintf
|
||||
|
||||
/* Compile in zlib support */
|
||||
#define LIBSSH2_HAVE_ZLIB 1
|
||||
|
||||
/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
|
||||
#define LIBSSH2_DH_GEX_NEW 1
|
||||
|
102
win32/ssh2_sample.dsp
Normal file
102
win32/ssh2_sample.dsp
Normal file
@@ -0,0 +1,102 @@
|
||||
# Microsoft Developer Studio Project File - Name="ssh2_sample" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=ssh2_sample - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "ssh2_sample.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "ssh2_sample.mak" CFG="ssh2_sample - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "ssh2_sample - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "ssh2_sample - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "ssh2_sample - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "ssh2_sample___Win32_Release"
|
||||
# PROP BASE Intermediate_Dir "ssh2_sample___Win32_Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\include" /I "..\win32" /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSSH2_LIBRARY" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libeay32.lib ssleay32.lib ws2_32.lib zlib.lib libssh2.lib /nologo /subsystem:console /machine:I386 /libpath:"Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ssh2_sample - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "ssh2_sample___Win32_Debug"
|
||||
# PROP BASE Intermediate_Dir "ssh2_sample___Win32_Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\include" /I "..\win32" /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSSH2_LIBRARY" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libeay32.lib ssleay32.lib ws2_32.lib zlib.lib libssh2d.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept /libpath:"Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "ssh2_sample - Win32 Release"
|
||||
# Name "ssh2_sample - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\ssh2_sample.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
Reference in New Issue
Block a user